mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-21 04:45:25 +00:00
target-arm queue:
* versal: Support XRAMs and XRAM controller * smmu: Various minor bug fixes * SVE emulation: fix bugs handling odd vector lengths * allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value * tests/acceptance: fix orangepi-pc acceptance tests * hw/timer/sse-timer: Propagate eventual error in sse_timer_realize() * hw/arm/virt: KVM: The IPA lower bound is 32 * npcm7xx: support MFT module * pl110, pxa2xx_lcd: tidy up template headers -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmBODPcZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oxdD/9Tbgsd3yZ/zQMKECEbEczB F0wgRz5FLFOx5O+Wfz35ByjCySSms5yaikDaBxqZdvfI9CXbvhwBtt+kEj4xcmUc 0KHYxaAnv//yMqEtpN0gyaVPs0+/BBjEH6kvlOLMngDs4x1Yp7fUh+gqpVxw+V0b v1fAZlfWj4SlAeiarTY9HJ9IZ5REFY7AxA0WdZl0cVT/keKf1Np9EGzBGBQIyn40 zFFLTktJSCmAkN7uUYEmmvcNUAJ1J7YlM1Sm3v4qmAHhRhB3a76qNk9/fDXqEs+Y OimIcsnHf/EyHQd8auwl2yLZ36tyDcUILUwRafFoQ12Krz7eSFon8xNnnSBFlgoM qmsGHN+AQXpXDaT7PPqx2ckR4vIZcp5dWp4B+rD8XFLhHU9p4FsZwtVfiwWH1K+y WOoGPqIo6o7IMOhTf7+NfVMj9COKDbyr9KzteoIOnrKVzc1JQaZVMFD/MufrtH39 hq7DdAl7MX+pKHKqaNPw8WFA9b8Th6ZCbmN1kyQpIFlj7/MoivJ7EQBtBIj6kBbS oy7Z/tI0rzaw6D44OO6yqnJVi2vMKEPzMZptoKYIK8OXNZyIAWOvyvT5tFPg8YCT f4QeF2J794NAIFF9SGK9hnFEE/vajzQm248IZVKFHVfhOJ3ev+FjNSdRySInAFY/ yoZlbfk1u9zula3I1Z0z3Q== =7lkG -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210314' into staging target-arm queue: * versal: Support XRAMs and XRAM controller * smmu: Various minor bug fixes * SVE emulation: fix bugs handling odd vector lengths * allwinner-sun8i-emac: traverse transmit queue using TX_CUR_DESC register value * tests/acceptance: fix orangepi-pc acceptance tests * hw/timer/sse-timer: Propagate eventual error in sse_timer_realize() * hw/arm/virt: KVM: The IPA lower bound is 32 * npcm7xx: support MFT module * pl110, pxa2xx_lcd: tidy up template headers # gpg: Signature made Sun 14 Mar 2021 13:17:43 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] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210314: (39 commits) hw/display/pxa2xx: Inline template header hw/display/pxa2xx: Apply whitespace-only coding style fixes to template header hw/display/pxa2xx: Apply brace-related coding style fixes to template header hw/display/pxa2xx: Remove use of BITS in pxa2xx_template.h hw/display/pxa2xx_lcd: Remove dest_width state field hw/display/pxa2xx_lcd: Remove dead code for non-32-bpp surfaces hw/display/pl110: Remove use of BITS from pl110_template.h hw/display/pl110: Pull included-once parts of template header into pl110.c hw/display/pl110: Remove dead code for non-32-bpp surfaces tests/qtest: Test PWM fan RPM using MFT in PWM test hw/arm: Connect PWM fans in NPCM7XX boards hw/arm: Add MFT device to NPCM7xx Soc hw/misc: Add NPCM7XX MFT Module hw/misc: Add GPIOs for duty in NPCM7xx PWM hw/arm/virt: KVM: The IPA lower bound is 32 accel: kvm: Fix kvm_type invocation hw/timer/sse-timer: Propagate eventual error in sse_timer_realize() tests/acceptance: drop ARMBIAN_ARTIFACTS_CACHED condition for orangepi-pc, cubieboard tests tests/acceptance: update sunxi kernel from armbian to 5.10.16 tests/acceptance/boot_linux_console: change URL for test_arm_orangepi_bionic_20_08 ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6f8a81fc29
@ -2068,6 +2068,8 @@ static int kvm_init(MachineState *ms)
|
||||
"kvm-type",
|
||||
&error_abort);
|
||||
type = mc->kvm_type(ms, kvm_type);
|
||||
} else if (mc->kvm_type) {
|
||||
type = mc->kvm_type(ms, NULL);
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -45,6 +45,7 @@ Supported devices
|
||||
* Pulse Width Modulation (PWM)
|
||||
* SMBus controller (SMBF)
|
||||
* Ethernet controller (EMC)
|
||||
* Tachometer
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
@ -63,7 +64,6 @@ Missing devices
|
||||
* Peripheral SPI controller (PSPI)
|
||||
* SD/MMC host
|
||||
* PECI interface
|
||||
* Tachometer
|
||||
* PCI and PCIe root complex and bridges
|
||||
* VDM and MCTP support
|
||||
* Serial I/O expansion
|
||||
|
@ -30,6 +30,7 @@ Implemented devices:
|
||||
- 8 ADMA (Xilinx zDMA) channels
|
||||
- 2 SD Controllers
|
||||
- OCM (256KB of On Chip Memory)
|
||||
- XRAM (4MB of on chip Accelerator RAM)
|
||||
- DDR memory
|
||||
|
||||
QEMU does not yet model any other devices, including the PL and the AI Engine.
|
||||
|
@ -122,6 +122,14 @@ enum NPCM7xxInterrupt {
|
||||
NPCM7XX_SMBUS15_IRQ,
|
||||
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
|
||||
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
|
||||
NPCM7XX_MFT0_IRQ = 96, /* MFT module 0 */
|
||||
NPCM7XX_MFT1_IRQ, /* MFT module 1 */
|
||||
NPCM7XX_MFT2_IRQ, /* MFT module 2 */
|
||||
NPCM7XX_MFT3_IRQ, /* MFT module 3 */
|
||||
NPCM7XX_MFT4_IRQ, /* MFT module 4 */
|
||||
NPCM7XX_MFT5_IRQ, /* MFT module 5 */
|
||||
NPCM7XX_MFT6_IRQ, /* MFT module 6 */
|
||||
NPCM7XX_MFT7_IRQ, /* MFT module 7 */
|
||||
NPCM7XX_EMC2RX_IRQ = 114,
|
||||
NPCM7XX_EMC2TX_IRQ,
|
||||
NPCM7XX_GPIO0_IRQ = 116,
|
||||
@ -172,6 +180,18 @@ static const hwaddr npcm7xx_pwm_addr[] = {
|
||||
0xf0104000,
|
||||
};
|
||||
|
||||
/* Register base address for each MFT Module */
|
||||
static const hwaddr npcm7xx_mft_addr[] = {
|
||||
0xf0180000,
|
||||
0xf0181000,
|
||||
0xf0182000,
|
||||
0xf0183000,
|
||||
0xf0184000,
|
||||
0xf0185000,
|
||||
0xf0186000,
|
||||
0xf0187000,
|
||||
};
|
||||
|
||||
/* Direct memory-mapped access to each SMBus Module. */
|
||||
static const hwaddr npcm7xx_smbus_addr[] = {
|
||||
0xf0080000,
|
||||
@ -417,6 +437,10 @@ static void npcm7xx_init(Object *obj)
|
||||
object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
|
||||
object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
|
||||
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
|
||||
}
|
||||
@ -603,6 +627,19 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
|
||||
}
|
||||
|
||||
/* MFT Modules. Cannot fail. */
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_mft_addr) != ARRAY_SIZE(s->mft));
|
||||
for (i = 0; i < ARRAY_SIZE(s->mft); i++) {
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->mft[i]);
|
||||
|
||||
qdev_connect_clock_in(DEVICE(&s->mft[i]), "clock-in",
|
||||
qdev_get_clock_out(DEVICE(&s->clk),
|
||||
"apb4-clock"));
|
||||
sysbus_realize(sbd, &error_abort);
|
||||
sysbus_mmio_map(sbd, 0, npcm7xx_mft_addr[i]);
|
||||
sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, NPCM7XX_MFT0_IRQ + i));
|
||||
}
|
||||
|
||||
/*
|
||||
* EMC Modules. Cannot fail.
|
||||
* The mapping of the device to its netdev backend works as follows:
|
||||
@ -680,14 +717,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[3]", 0xf0183000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[4]", 0xf0184000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[5]", 0xf0185000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[6]", 0xf0186000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[7]", 0xf0187000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
@ -116,6 +117,64 @@ static void at24c_eeprom_init(NPCM7xxState *soc, int bus, uint8_t addr,
|
||||
i2c_slave_realize_and_unref(i2c_dev, i2c_bus, &error_abort);
|
||||
}
|
||||
|
||||
static void npcm7xx_init_pwm_splitter(NPCM7xxMachine *machine,
|
||||
NPCM7xxState *soc, const int *fan_counts)
|
||||
{
|
||||
SplitIRQ *splitters = machine->fan_splitter;
|
||||
|
||||
/*
|
||||
* PWM 0~3 belong to module 0 output 0~3.
|
||||
* PWM 4~7 belong to module 1 output 0~3.
|
||||
*/
|
||||
for (int i = 0; i < NPCM7XX_NR_PWM_MODULES; ++i) {
|
||||
for (int j = 0; j < NPCM7XX_PWM_PER_MODULE; ++j) {
|
||||
int splitter_no = i * NPCM7XX_PWM_PER_MODULE + j;
|
||||
DeviceState *splitter;
|
||||
|
||||
if (fan_counts[splitter_no] < 1) {
|
||||
continue;
|
||||
}
|
||||
object_initialize_child(OBJECT(machine), "fan-splitter[*]",
|
||||
&splitters[splitter_no], TYPE_SPLIT_IRQ);
|
||||
splitter = DEVICE(&splitters[splitter_no]);
|
||||
qdev_prop_set_uint16(splitter, "num-lines",
|
||||
fan_counts[splitter_no]);
|
||||
qdev_realize(splitter, NULL, &error_abort);
|
||||
qdev_connect_gpio_out_named(DEVICE(&soc->pwm[i]), "duty-gpio-out",
|
||||
j, qdev_get_gpio_in(splitter, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_connect_pwm_fan(NPCM7xxState *soc, SplitIRQ *splitter,
|
||||
int fan_no, int output_no)
|
||||
{
|
||||
DeviceState *fan;
|
||||
int fan_input;
|
||||
qemu_irq fan_duty_gpio;
|
||||
|
||||
g_assert(fan_no >= 0 && fan_no <= NPCM7XX_MFT_MAX_FAN_INPUT);
|
||||
/*
|
||||
* Fan 0~1 belong to module 0 input 0~1.
|
||||
* Fan 2~3 belong to module 1 input 0~1.
|
||||
* ...
|
||||
* Fan 14~15 belong to module 7 input 0~1.
|
||||
* Fan 16~17 belong to module 0 input 2~3.
|
||||
* Fan 18~19 belong to module 1 input 2~3.
|
||||
*/
|
||||
if (fan_no < 16) {
|
||||
fan = DEVICE(&soc->mft[fan_no / 2]);
|
||||
fan_input = fan_no % 2;
|
||||
} else {
|
||||
fan = DEVICE(&soc->mft[(fan_no - 16) / 2]);
|
||||
fan_input = fan_no % 2 + 2;
|
||||
}
|
||||
|
||||
/* Connect the Fan to PWM module */
|
||||
fan_duty_gpio = qdev_get_gpio_in_named(fan, "duty", fan_input);
|
||||
qdev_connect_gpio_out(DEVICE(splitter), output_no, fan_duty_gpio);
|
||||
}
|
||||
|
||||
static void npcm750_evb_i2c_init(NPCM7xxState *soc)
|
||||
{
|
||||
/* lm75 temperature sensor on SVB, tmp105 is compatible */
|
||||
@ -128,6 +187,30 @@ static void npcm750_evb_i2c_init(NPCM7xxState *soc)
|
||||
i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
|
||||
}
|
||||
|
||||
static void npcm750_evb_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
|
||||
{
|
||||
SplitIRQ *splitter = machine->fan_splitter;
|
||||
static const int fan_counts[] = {2, 2, 2, 2, 2, 2, 2, 2};
|
||||
|
||||
npcm7xx_init_pwm_splitter(machine, soc, fan_counts);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[3], 0x06, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[3], 0x07, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[4], 0x08, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[4], 0x09, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[5], 0x0a, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[5], 0x0b, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[6], 0x0c, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[6], 0x0d, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[7], 0x0e, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[7], 0x0f, 1);
|
||||
}
|
||||
|
||||
static void quanta_gsj_i2c_init(NPCM7xxState *soc)
|
||||
{
|
||||
/* GSJ machine have 4 max31725 temperature sensors, tmp105 is compatible. */
|
||||
@ -142,6 +225,20 @@ static void quanta_gsj_i2c_init(NPCM7xxState *soc)
|
||||
/* TODO: Add additional i2c devices. */
|
||||
}
|
||||
|
||||
static void quanta_gsj_fan_init(NPCM7xxMachine *machine, NPCM7xxState *soc)
|
||||
{
|
||||
SplitIRQ *splitter = machine->fan_splitter;
|
||||
static const int fan_counts[] = {2, 2, 2, 0, 0, 0, 0, 0};
|
||||
|
||||
npcm7xx_init_pwm_splitter(machine, soc, fan_counts);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
|
||||
npcm7xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
|
||||
}
|
||||
|
||||
static void npcm750_evb_init(MachineState *machine)
|
||||
{
|
||||
NPCM7xxState *soc;
|
||||
@ -153,6 +250,7 @@ static void npcm750_evb_init(MachineState *machine)
|
||||
npcm7xx_load_bootrom(machine, soc);
|
||||
npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
|
||||
npcm750_evb_i2c_init(soc);
|
||||
npcm750_evb_fan_init(NPCM7XX_MACHINE(machine), soc);
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
@ -168,6 +266,7 @@ static void quanta_gsj_init(MachineState *machine)
|
||||
npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e",
|
||||
drive_get(IF_MTD, 0, 0));
|
||||
quanta_gsj_i2c_init(soc);
|
||||
quanta_gsj_fan_init(NPCM7XX_MACHINE(machine), soc);
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
|
@ -151,22 +151,28 @@ inline void
|
||||
smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
|
||||
uint8_t tg, uint64_t num_pages, uint8_t ttl)
|
||||
{
|
||||
if (ttl && (num_pages == 1)) {
|
||||
/* if tg is not set we use 4KB range invalidation */
|
||||
uint8_t granule = tg ? tg * 2 + 10 : 12;
|
||||
|
||||
if (ttl && (num_pages == 1) && (asid >= 0)) {
|
||||
SMMUIOTLBKey key = smmu_get_iotlb_key(asid, iova, tg, ttl);
|
||||
|
||||
g_hash_table_remove(s->iotlb, &key);
|
||||
} else {
|
||||
/* if tg is not set we use 4KB range invalidation */
|
||||
uint8_t granule = tg ? tg * 2 + 10 : 12;
|
||||
|
||||
SMMUIOTLBPageInvInfo info = {
|
||||
.asid = asid, .iova = iova,
|
||||
.mask = (num_pages * 1 << granule) - 1};
|
||||
|
||||
g_hash_table_foreach_remove(s->iotlb,
|
||||
smmu_hash_remove_by_asid_iova,
|
||||
&info);
|
||||
if (g_hash_table_remove(s->iotlb, &key)) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* if the entry is not found, let's see if it does not
|
||||
* belong to a larger IOTLB entry
|
||||
*/
|
||||
}
|
||||
|
||||
SMMUIOTLBPageInvInfo info = {
|
||||
.asid = asid, .iova = iova,
|
||||
.mask = (num_pages * 1 << granule) - 1};
|
||||
|
||||
g_hash_table_foreach_remove(s->iotlb,
|
||||
smmu_hash_remove_by_asid_iova,
|
||||
&info);
|
||||
}
|
||||
|
||||
inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
|
||||
|
@ -104,4 +104,9 @@ typedef struct SMMUIOTLBPageInvInfo {
|
||||
uint64_t mask;
|
||||
} SMMUIOTLBPageInvInfo;
|
||||
|
||||
typedef struct SMMUSIDRange {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
} SMMUSIDRange;
|
||||
|
||||
#endif
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "hw/arm/smmuv3.h"
|
||||
#include "smmuv3-internal.h"
|
||||
#include "smmu-internal.h"
|
||||
|
||||
/**
|
||||
* smmuv3_trigger_irq - pulse @irq if enabled and update
|
||||
@ -861,7 +862,8 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
|
||||
uint16_t vmid = CMD_VMID(cmd);
|
||||
bool leaf = CMD_LEAF(cmd);
|
||||
uint8_t tg = CMD_TG(cmd);
|
||||
hwaddr num_pages = 1;
|
||||
uint64_t first_page = 0, last_page;
|
||||
uint64_t num_pages = 1;
|
||||
int asid = -1;
|
||||
|
||||
if (tg) {
|
||||
@ -874,9 +876,38 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
|
||||
if (type == SMMU_CMD_TLBI_NH_VA) {
|
||||
asid = CMD_ASID(cmd);
|
||||
}
|
||||
trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf);
|
||||
smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages);
|
||||
smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl);
|
||||
|
||||
/* Split invalidations into ^2 range invalidations */
|
||||
last_page = num_pages - 1;
|
||||
while (num_pages) {
|
||||
uint8_t granule = tg * 2 + 10;
|
||||
uint64_t mask, count;
|
||||
|
||||
mask = dma_aligned_pow2_mask(first_page, last_page, 64 - granule);
|
||||
count = mask + 1;
|
||||
|
||||
trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, count, ttl, leaf);
|
||||
smmuv3_inv_notifiers_iova(s, asid, addr, tg, count);
|
||||
smmu_iotlb_inv_iova(s, asid, addr, tg, count, ttl);
|
||||
|
||||
num_pages -= count;
|
||||
first_page += count;
|
||||
addr += count * BIT_ULL(granule);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
SMMUDevice *sdev = (SMMUDevice *)key;
|
||||
uint32_t sid = smmu_get_sid(sdev);
|
||||
SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
|
||||
|
||||
if (sid < sid_range->start || sid > sid_range->end) {
|
||||
return false;
|
||||
}
|
||||
trace_smmuv3_config_cache_inv(sid);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int smmuv3_cmdq_consume(SMMUv3State *s)
|
||||
@ -949,27 +980,18 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
|
||||
}
|
||||
case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */
|
||||
{
|
||||
uint32_t start = CMD_SID(&cmd), end, i;
|
||||
uint32_t start = CMD_SID(&cmd);
|
||||
uint8_t range = CMD_STE_RANGE(&cmd);
|
||||
uint64_t end = start + (1ULL << (range + 1)) - 1;
|
||||
SMMUSIDRange sid_range = {start, end};
|
||||
|
||||
if (CMD_SSEC(&cmd)) {
|
||||
cmd_error = SMMU_CERROR_ILL;
|
||||
break;
|
||||
}
|
||||
|
||||
end = start + (1 << (range + 1)) - 1;
|
||||
trace_smmuv3_cmdq_cfgi_ste_range(start, end);
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, i);
|
||||
SMMUDevice *sdev;
|
||||
|
||||
if (!mr) {
|
||||
continue;
|
||||
}
|
||||
sdev = container_of(mr, SMMUDevice, iommu);
|
||||
smmuv3_flush_config(sdev);
|
||||
}
|
||||
g_hash_table_foreach_remove(bs->configs, smmuv3_invalidate_ste,
|
||||
&sid_range);
|
||||
break;
|
||||
}
|
||||
case SMMU_CMD_CFGI_CD:
|
||||
|
@ -29,26 +29,26 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
|
||||
smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
|
||||
smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
|
||||
smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
|
||||
smmuv3_record_event(const char *type, uint32_t sid) "%s sid=%d"
|
||||
smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "SID:0x%x features:0x%x, sid_split:0x%x"
|
||||
smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
|
||||
smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
|
||||
smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
|
||||
smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
|
||||
smmuv3_translate_disable(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=%d bypass (smmu disabled) iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_bypass(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=%d STE bypass iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_abort(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=%d abort on iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t translated, int perm) "%s sid=%d iova=0x%"PRIx64" translated=0x%"PRIx64" perm=0x%x"
|
||||
smmuv3_translate_disable(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x bypass (smmu disabled) iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_bypass(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x STE bypass iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_abort(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x abort on iova:0x%"PRIx64" is_write=%d"
|
||||
smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t translated, int perm) "%s sid=0x%x iova=0x%"PRIx64" translated=0x%"PRIx64" perm=0x%x"
|
||||
smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
|
||||
smmuv3_decode_cd(uint32_t oas) "oas=%d"
|
||||
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
|
||||
smmuv3_cmdq_cfgi_ste(int streamid) "streamid =%d"
|
||||
smmuv3_cmdq_cfgi_ste(int streamid) "streamid= 0x%x"
|
||||
smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
|
||||
smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
|
||||
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
|
||||
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
|
||||
smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf) "vmid =%d asid =%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
|
||||
smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
|
||||
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
|
||||
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
|
||||
smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
|
||||
smmuv3_cmdq_tlbi_nh(void) ""
|
||||
smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d"
|
||||
smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid %d"
|
||||
smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
|
||||
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
|
||||
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
|
||||
smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
|
||||
|
@ -2548,27 +2548,36 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
|
||||
static int virt_kvm_type(MachineState *ms, const char *type_str)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(ms);
|
||||
int max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms);
|
||||
int requested_pa_size;
|
||||
int max_vm_pa_size, requested_pa_size;
|
||||
bool fixed_ipa;
|
||||
|
||||
max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa);
|
||||
|
||||
/* we freeze the memory map to compute the highest gpa */
|
||||
virt_set_memmap(vms);
|
||||
|
||||
requested_pa_size = 64 - clz64(vms->highest_gpa);
|
||||
|
||||
/*
|
||||
* KVM requires the IPA size to be at least 32 bits.
|
||||
*/
|
||||
if (requested_pa_size < 32) {
|
||||
requested_pa_size = 32;
|
||||
}
|
||||
|
||||
if (requested_pa_size > max_vm_pa_size) {
|
||||
error_report("-m and ,maxmem option values "
|
||||
"require an IPA range (%d bits) larger than "
|
||||
"the one supported by the host (%d bits)",
|
||||
requested_pa_size, max_vm_pa_size);
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* By default we return 0 which corresponds to an implicit legacy
|
||||
* 40b IPA setting. Otherwise we return the actual requested PA
|
||||
* logsize
|
||||
* We return the requested PA log size, unless KVM only supports
|
||||
* the implicit legacy 40b IPA setting, in which case the kvm_type
|
||||
* must be 0.
|
||||
*/
|
||||
return requested_pa_size > 40 ? requested_pa_size : 0;
|
||||
return fixed_ipa ? 0 : requested_pa_size;
|
||||
}
|
||||
|
||||
static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
@ -278,6 +279,40 @@ static void versal_create_rtc(Versal *s, qemu_irq *pic)
|
||||
sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]);
|
||||
}
|
||||
|
||||
static void versal_create_xrams(Versal *s, qemu_irq *pic)
|
||||
{
|
||||
int nr_xrams = ARRAY_SIZE(s->lpd.xram.ctrl);
|
||||
DeviceState *orgate;
|
||||
int i;
|
||||
|
||||
/* XRAM IRQs get ORed into a single line. */
|
||||
object_initialize_child(OBJECT(s), "xram-irq-orgate",
|
||||
&s->lpd.xram.irq_orgate, TYPE_OR_IRQ);
|
||||
orgate = DEVICE(&s->lpd.xram.irq_orgate);
|
||||
object_property_set_int(OBJECT(orgate),
|
||||
"num-lines", nr_xrams, &error_fatal);
|
||||
qdev_realize(orgate, NULL, &error_fatal);
|
||||
qdev_connect_gpio_out(orgate, 0, pic[VERSAL_XRAM_IRQ_0]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->lpd.xram.ctrl); i++) {
|
||||
SysBusDevice *sbd;
|
||||
MemoryRegion *mr;
|
||||
|
||||
object_initialize_child(OBJECT(s), "xram[*]", &s->lpd.xram.ctrl[i],
|
||||
TYPE_XLNX_XRAM_CTRL);
|
||||
sbd = SYS_BUS_DEVICE(&s->lpd.xram.ctrl[i]);
|
||||
sysbus_realize(sbd, &error_fatal);
|
||||
|
||||
mr = sysbus_mmio_get_region(sbd, 0);
|
||||
memory_region_add_subregion(&s->mr_ps,
|
||||
MM_XRAMC + i * MM_XRAMC_SIZE, mr);
|
||||
mr = sysbus_mmio_get_region(sbd, 1);
|
||||
memory_region_add_subregion(&s->mr_ps, MM_XRAM + i * MiB, mr);
|
||||
|
||||
sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(orgate, i));
|
||||
}
|
||||
}
|
||||
|
||||
/* This takes the board allocated linear DDR memory and creates aliases
|
||||
* for each split DDR range/aperture on the Versal address map.
|
||||
*/
|
||||
@ -363,6 +398,7 @@ static void versal_realize(DeviceState *dev, Error **errp)
|
||||
versal_create_admas(s, pic);
|
||||
versal_create_sds(s, pic);
|
||||
versal_create_rtc(s, pic);
|
||||
versal_create_xrams(s, pic);
|
||||
versal_map_ddr(s);
|
||||
versal_unimp(s);
|
||||
|
||||
|
@ -123,16 +123,84 @@ static const unsigned char *idregs[] = {
|
||||
pl111_id
|
||||
};
|
||||
|
||||
#define BITS 8
|
||||
#define COPY_PIXEL(to, from) do { *(uint32_t *)to = from; to += 4; } while (0)
|
||||
|
||||
#undef RGB
|
||||
#define BORDER bgr
|
||||
#define ORDER 0
|
||||
#include "pl110_template.h"
|
||||
#define BITS 15
|
||||
#define ORDER 1
|
||||
#include "pl110_template.h"
|
||||
#define BITS 16
|
||||
#define ORDER 2
|
||||
#include "pl110_template.h"
|
||||
#define BITS 24
|
||||
#undef BORDER
|
||||
#define RGB
|
||||
#define BORDER rgb
|
||||
#define ORDER 0
|
||||
#include "pl110_template.h"
|
||||
#define BITS 32
|
||||
#define ORDER 1
|
||||
#include "pl110_template.h"
|
||||
#define ORDER 2
|
||||
#include "pl110_template.h"
|
||||
#undef BORDER
|
||||
|
||||
#undef COPY_PIXEL
|
||||
|
||||
static drawfn pl110_draw_fn_32[48] = {
|
||||
pl110_draw_line1_lblp_bgr,
|
||||
pl110_draw_line2_lblp_bgr,
|
||||
pl110_draw_line4_lblp_bgr,
|
||||
pl110_draw_line8_lblp_bgr,
|
||||
pl110_draw_line16_555_lblp_bgr,
|
||||
pl110_draw_line32_lblp_bgr,
|
||||
pl110_draw_line16_lblp_bgr,
|
||||
pl110_draw_line12_lblp_bgr,
|
||||
|
||||
pl110_draw_line1_bbbp_bgr,
|
||||
pl110_draw_line2_bbbp_bgr,
|
||||
pl110_draw_line4_bbbp_bgr,
|
||||
pl110_draw_line8_bbbp_bgr,
|
||||
pl110_draw_line16_555_bbbp_bgr,
|
||||
pl110_draw_line32_bbbp_bgr,
|
||||
pl110_draw_line16_bbbp_bgr,
|
||||
pl110_draw_line12_bbbp_bgr,
|
||||
|
||||
pl110_draw_line1_lbbp_bgr,
|
||||
pl110_draw_line2_lbbp_bgr,
|
||||
pl110_draw_line4_lbbp_bgr,
|
||||
pl110_draw_line8_lbbp_bgr,
|
||||
pl110_draw_line16_555_lbbp_bgr,
|
||||
pl110_draw_line32_lbbp_bgr,
|
||||
pl110_draw_line16_lbbp_bgr,
|
||||
pl110_draw_line12_lbbp_bgr,
|
||||
|
||||
pl110_draw_line1_lblp_rgb,
|
||||
pl110_draw_line2_lblp_rgb,
|
||||
pl110_draw_line4_lblp_rgb,
|
||||
pl110_draw_line8_lblp_rgb,
|
||||
pl110_draw_line16_555_lblp_rgb,
|
||||
pl110_draw_line32_lblp_rgb,
|
||||
pl110_draw_line16_lblp_rgb,
|
||||
pl110_draw_line12_lblp_rgb,
|
||||
|
||||
pl110_draw_line1_bbbp_rgb,
|
||||
pl110_draw_line2_bbbp_rgb,
|
||||
pl110_draw_line4_bbbp_rgb,
|
||||
pl110_draw_line8_bbbp_rgb,
|
||||
pl110_draw_line16_555_bbbp_rgb,
|
||||
pl110_draw_line32_bbbp_rgb,
|
||||
pl110_draw_line16_bbbp_rgb,
|
||||
pl110_draw_line12_bbbp_rgb,
|
||||
|
||||
pl110_draw_line1_lbbp_rgb,
|
||||
pl110_draw_line2_lbbp_rgb,
|
||||
pl110_draw_line4_lbbp_rgb,
|
||||
pl110_draw_line8_lbbp_rgb,
|
||||
pl110_draw_line16_555_lbbp_rgb,
|
||||
pl110_draw_line32_lbbp_rgb,
|
||||
pl110_draw_line16_lbbp_rgb,
|
||||
pl110_draw_line12_lbbp_rgb,
|
||||
};
|
||||
|
||||
static int pl110_enabled(PL110State *s)
|
||||
{
|
||||
@ -144,9 +212,7 @@ static void pl110_update_display(void *opaque)
|
||||
PL110State *s = (PL110State *)opaque;
|
||||
SysBusDevice *sbd;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
drawfn* fntable;
|
||||
drawfn fn;
|
||||
int dest_width;
|
||||
int src_width;
|
||||
int bpp_offset;
|
||||
int first;
|
||||
@ -158,33 +224,6 @@ static void pl110_update_display(void *opaque)
|
||||
|
||||
sbd = SYS_BUS_DEVICE(s);
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
case 0:
|
||||
return;
|
||||
case 8:
|
||||
fntable = pl110_draw_fn_8;
|
||||
dest_width = 1;
|
||||
break;
|
||||
case 15:
|
||||
fntable = pl110_draw_fn_15;
|
||||
dest_width = 2;
|
||||
break;
|
||||
case 16:
|
||||
fntable = pl110_draw_fn_16;
|
||||
dest_width = 2;
|
||||
break;
|
||||
case 24:
|
||||
fntable = pl110_draw_fn_24;
|
||||
dest_width = 3;
|
||||
break;
|
||||
case 32:
|
||||
fntable = pl110_draw_fn_32;
|
||||
dest_width = 4;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "pl110: Bad color depth\n");
|
||||
exit(1);
|
||||
}
|
||||
if (s->cr & PL110_CR_BGR)
|
||||
bpp_offset = 0;
|
||||
else
|
||||
@ -218,12 +257,13 @@ static void pl110_update_display(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
if (s->cr & PL110_CR_BEBO)
|
||||
fn = fntable[s->bpp + 8 + bpp_offset];
|
||||
else if (s->cr & PL110_CR_BEPO)
|
||||
fn = fntable[s->bpp + 16 + bpp_offset];
|
||||
else
|
||||
fn = fntable[s->bpp + bpp_offset];
|
||||
if (s->cr & PL110_CR_BEBO) {
|
||||
fn = pl110_draw_fn_32[s->bpp + 8 + bpp_offset];
|
||||
} else if (s->cr & PL110_CR_BEPO) {
|
||||
fn = pl110_draw_fn_32[s->bpp + 16 + bpp_offset];
|
||||
} else {
|
||||
fn = pl110_draw_fn_32[s->bpp + bpp_offset];
|
||||
}
|
||||
|
||||
src_width = s->cols;
|
||||
switch (s->bpp) {
|
||||
@ -247,7 +287,6 @@ static void pl110_update_display(void *opaque)
|
||||
src_width <<= 2;
|
||||
break;
|
||||
}
|
||||
dest_width *= s->cols;
|
||||
first = 0;
|
||||
if (s->invalidate) {
|
||||
framebuffer_update_memory_section(&s->fbsection,
|
||||
@ -258,7 +297,7 @@ static void pl110_update_display(void *opaque)
|
||||
|
||||
framebuffer_update_display(surface, &s->fbsection,
|
||||
s->cols, s->rows,
|
||||
src_width, dest_width, 0,
|
||||
src_width, s->cols * 4, 0,
|
||||
s->invalidate,
|
||||
fn, s->palette,
|
||||
&first, &last);
|
||||
|
@ -10,118 +10,22 @@
|
||||
*/
|
||||
|
||||
#ifndef ORDER
|
||||
|
||||
#if BITS == 8
|
||||
#define COPY_PIXEL(to, from) *(to++) = from
|
||||
#elif BITS == 15 || BITS == 16
|
||||
#define COPY_PIXEL(to, from) do { *(uint16_t *)to = from; to += 2; } while (0)
|
||||
#elif BITS == 24
|
||||
#define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
*(to++) = from; \
|
||||
*(to++) = (from) >> 8; \
|
||||
*(to++) = (from) >> 16; \
|
||||
} while (0)
|
||||
#elif BITS == 32
|
||||
#define COPY_PIXEL(to, from) do { *(uint32_t *)to = from; to += 4; } while (0)
|
||||
#else
|
||||
#error unknown bit depth
|
||||
#error "pl110_template.h is only for inclusion by pl110.c"
|
||||
#endif
|
||||
|
||||
#undef RGB
|
||||
#define BORDER bgr
|
||||
#define ORDER 0
|
||||
#include "pl110_template.h"
|
||||
#define ORDER 1
|
||||
#include "pl110_template.h"
|
||||
#define ORDER 2
|
||||
#include "pl110_template.h"
|
||||
#undef BORDER
|
||||
#define RGB
|
||||
#define BORDER rgb
|
||||
#define ORDER 0
|
||||
#include "pl110_template.h"
|
||||
#define ORDER 1
|
||||
#include "pl110_template.h"
|
||||
#define ORDER 2
|
||||
#include "pl110_template.h"
|
||||
#undef BORDER
|
||||
|
||||
static drawfn glue(pl110_draw_fn_,BITS)[48] =
|
||||
{
|
||||
glue(pl110_draw_line1_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line2_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line4_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line8_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line16_555_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line32_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line16_lblp_bgr,BITS),
|
||||
glue(pl110_draw_line12_lblp_bgr,BITS),
|
||||
|
||||
glue(pl110_draw_line1_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line2_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line4_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line8_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line16_555_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line32_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line16_bbbp_bgr,BITS),
|
||||
glue(pl110_draw_line12_bbbp_bgr,BITS),
|
||||
|
||||
glue(pl110_draw_line1_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line2_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line4_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line8_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line16_555_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line32_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line16_lbbp_bgr,BITS),
|
||||
glue(pl110_draw_line12_lbbp_bgr,BITS),
|
||||
|
||||
glue(pl110_draw_line1_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line2_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line4_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line8_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line16_555_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line32_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line16_lblp_rgb,BITS),
|
||||
glue(pl110_draw_line12_lblp_rgb,BITS),
|
||||
|
||||
glue(pl110_draw_line1_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line2_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line4_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line8_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line16_555_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line32_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line16_bbbp_rgb,BITS),
|
||||
glue(pl110_draw_line12_bbbp_rgb,BITS),
|
||||
|
||||
glue(pl110_draw_line1_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line2_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line4_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line8_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line16_555_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line32_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line16_lbbp_rgb,BITS),
|
||||
glue(pl110_draw_line12_lbbp_rgb,BITS),
|
||||
};
|
||||
|
||||
#undef BITS
|
||||
#undef COPY_PIXEL
|
||||
|
||||
#else
|
||||
|
||||
#if ORDER == 0
|
||||
#define NAME glue(glue(lblp_, BORDER), BITS)
|
||||
#define NAME glue(lblp_, BORDER)
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define SWAP_WORDS 1
|
||||
#endif
|
||||
#elif ORDER == 1
|
||||
#define NAME glue(glue(bbbp_, BORDER), BITS)
|
||||
#define NAME glue(bbbp_, BORDER)
|
||||
#ifndef HOST_WORDS_BIGENDIAN
|
||||
#define SWAP_WORDS 1
|
||||
#endif
|
||||
#else
|
||||
#define SWAP_PIXELS 1
|
||||
#define NAME glue(glue(lbbp_, BORDER), BITS)
|
||||
#define NAME glue(lbbp_, BORDER)
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define SWAP_WORDS 1
|
||||
#endif
|
||||
@ -270,14 +174,14 @@ static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_
|
||||
MSB = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
#endif
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
LSB = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
MSB = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
#undef MSB
|
||||
#undef LSB
|
||||
width -= 2;
|
||||
@ -307,7 +211,7 @@ static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_
|
||||
g = (data >> 16) & 0xff;
|
||||
MSB = (data >> 8) & 0xff;
|
||||
#endif
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
#undef MSB
|
||||
#undef LSB
|
||||
width--;
|
||||
@ -338,14 +242,14 @@ static void glue(pl110_draw_line16_555_,NAME)(void *opaque, uint8_t *d, const ui
|
||||
data >>= 5;
|
||||
MSB = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
LSB = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
MSB = (data & 0x1f) << 3;
|
||||
data >>= 6;
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
#undef MSB
|
||||
#undef LSB
|
||||
width -= 2;
|
||||
@ -376,14 +280,14 @@ static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_
|
||||
data >>= 4;
|
||||
MSB = (data & 0xf) << 4;
|
||||
data >>= 8;
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
LSB = (data & 0xf) << 4;
|
||||
data >>= 4;
|
||||
g = (data & 0xf) << 4;
|
||||
data >>= 4;
|
||||
MSB = (data & 0xf) << 4;
|
||||
data >>= 8;
|
||||
COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
|
||||
COPY_PIXEL(d, rgb_to_pixel32(r, g, b));
|
||||
#undef MSB
|
||||
#undef LSB
|
||||
width -= 2;
|
||||
@ -395,5 +299,3 @@ static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_
|
||||
#undef NAME
|
||||
#undef SWAP_WORDS
|
||||
#undef ORDER
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,6 @@ struct PXA2xxLCDState {
|
||||
|
||||
int invalidated;
|
||||
QemuConsole *con;
|
||||
drawfn *line_fn[2];
|
||||
int dest_width;
|
||||
int xres, yres;
|
||||
int pal_for;
|
||||
@ -188,6 +187,435 @@ typedef struct QEMU_PACKED {
|
||||
#define LDCMD_SOFINT (1 << 22)
|
||||
#define LDCMD_PAL (1 << 26)
|
||||
|
||||
/* Size of a pixel in the QEMU UI output surface, in bytes */
|
||||
#define DEST_PIXEL_WIDTH 4
|
||||
|
||||
/* Line drawing code to handle the various possible guest pixel formats */
|
||||
|
||||
# define SKIP_PIXEL(to) do { to += deststep; } while (0)
|
||||
# define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
*(uint32_t *) to = from; \
|
||||
SKIP_PIXEL(to); \
|
||||
} while (0)
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
# define SWAP_WORDS 1
|
||||
#endif
|
||||
|
||||
#define FN_2(x) FN(x + 1) FN(x)
|
||||
#define FN_4(x) FN_2(x + 2) FN_2(x)
|
||||
|
||||
static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN_4(12)
|
||||
FN_4(8)
|
||||
FN_4(4)
|
||||
FN_4(0)
|
||||
#else
|
||||
FN_4(0)
|
||||
FN_4(4)
|
||||
FN_4(8)
|
||||
FN_4(12)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 16;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN_2(6)
|
||||
FN_2(4)
|
||||
FN_2(2)
|
||||
FN_2(0)
|
||||
#else
|
||||
FN_2(0)
|
||||
FN_2(2)
|
||||
FN_2(4)
|
||||
FN_2(6)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 8;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN(24)
|
||||
FN(16)
|
||||
FN(8)
|
||||
FN(0)
|
||||
#else
|
||||
FN(0)
|
||||
FN(8)
|
||||
FN(16)
|
||||
FN(24)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
width -= 2;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
if (data & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
data >>= 1;
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
if (data & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
width -= 2;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x3f) << 2;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* The wicked packed format */
|
||||
static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data[3];
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data[0] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[1] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[2] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
#ifdef SWAP_WORDS
|
||||
data[0] = bswap32(data[0]);
|
||||
data[1] = bswap32(data[1]);
|
||||
data[2] = bswap32(data[2]);
|
||||
#endif
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
r = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 12;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = ((data[1] & 0xf) << 4) | (data[0] << 2);
|
||||
data[1] >>= 4;
|
||||
r = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 12;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
b = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
g = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
r = ((data[2] & 0x3) << 6) | (data[1] << 2);
|
||||
data[2] >>= 8;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
b = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
g = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
r = data[2] << 2;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
width -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
if (data & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* The wicked packed format */
|
||||
static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data[3];
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data[0] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[1] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[2] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
# ifdef SWAP_WORDS
|
||||
data[0] = bswap32(data[0]);
|
||||
data[1] = bswap32(data[1]);
|
||||
data[2] = bswap32(data[2]);
|
||||
# endif
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
r = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
if (data[0] & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
data[0] >>= 6;
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = ((data[1] & 0xf) << 4) | (data[0] << 2);
|
||||
data[1] >>= 4;
|
||||
r = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
if (data[1] & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
data[1] >>= 6;
|
||||
b = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
g = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
r = ((data[2] & 0x3) << 6) | (data[1] << 2);
|
||||
data[2] >>= 2;
|
||||
if (data[2] & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
data[2] >>= 6;
|
||||
b = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
g = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
r = data[2] << 2;
|
||||
data[2] >>= 6;
|
||||
if (data[2] & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
width -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = data & 0xff;
|
||||
data >>= 8;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x7f) << 1;
|
||||
data >>= 7;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
data >>= 8;
|
||||
if (data & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = data & 0xff;
|
||||
data >>= 8;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
data >>= 8;
|
||||
if (data & 1) {
|
||||
SKIP_PIXEL(dest);
|
||||
} else {
|
||||
COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
|
||||
}
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overlay planes disabled, no transparency */
|
||||
static drawfn pxa2xx_draw_fn_32[16] = {
|
||||
[0 ... 0xf] = NULL,
|
||||
[pxa_lcdc_2bpp] = pxa2xx_draw_line2,
|
||||
[pxa_lcdc_4bpp] = pxa2xx_draw_line4,
|
||||
[pxa_lcdc_8bpp] = pxa2xx_draw_line8,
|
||||
[pxa_lcdc_16bpp] = pxa2xx_draw_line16,
|
||||
[pxa_lcdc_18bpp] = pxa2xx_draw_line18,
|
||||
[pxa_lcdc_18pbpp] = pxa2xx_draw_line18p,
|
||||
[pxa_lcdc_24bpp] = pxa2xx_draw_line24,
|
||||
};
|
||||
|
||||
/* Overlay planes enabled, transparency used */
|
||||
static drawfn pxa2xx_draw_fn_32t[16] = {
|
||||
[0 ... 0xf] = NULL,
|
||||
[pxa_lcdc_4bpp] = pxa2xx_draw_line4,
|
||||
[pxa_lcdc_8bpp] = pxa2xx_draw_line8,
|
||||
[pxa_lcdc_16bpp] = pxa2xx_draw_line16t,
|
||||
[pxa_lcdc_19bpp] = pxa2xx_draw_line19,
|
||||
[pxa_lcdc_19pbpp] = pxa2xx_draw_line19p,
|
||||
[pxa_lcdc_24bpp] = pxa2xx_draw_line24t,
|
||||
[pxa_lcdc_25bpp] = pxa2xx_draw_line25,
|
||||
};
|
||||
|
||||
#undef COPY_PIXEL
|
||||
#undef SKIP_PIXEL
|
||||
|
||||
#ifdef SWAP_WORDS
|
||||
# undef SWAP_WORDS
|
||||
#endif
|
||||
|
||||
/* Route internal interrupt lines to the global IC */
|
||||
static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
|
||||
{
|
||||
@ -674,14 +1102,21 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s)
|
||||
{
|
||||
if (s->transp) {
|
||||
return pxa2xx_draw_fn_32t[s->bpp];
|
||||
} else {
|
||||
return pxa2xx_draw_fn_32[s->bpp];
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
|
||||
hwaddr addr, int *miny, int *maxy)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width)
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
drawfn fn = pxa2xx_drawfn(s);
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
@ -693,14 +1128,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
|
||||
else if (s->bpp > pxa_lcdc_8bpp)
|
||||
src_width *= 2;
|
||||
|
||||
dest_width = s->xres * s->dest_width;
|
||||
dest_width = s->xres * DEST_PIXEL_WIDTH;
|
||||
*miny = 0;
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, dest_width, s->dest_width,
|
||||
src_width, dest_width, DEST_PIXEL_WIDTH,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
}
|
||||
@ -710,9 +1145,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width)
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
drawfn fn = pxa2xx_drawfn(s);
|
||||
if (!fn)
|
||||
return;
|
||||
|
||||
@ -724,14 +1157,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
|
||||
else if (s->bpp > pxa_lcdc_8bpp)
|
||||
src_width *= 2;
|
||||
|
||||
dest_width = s->yres * s->dest_width;
|
||||
dest_width = s->yres * DEST_PIXEL_WIDTH;
|
||||
*miny = 0;
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, s->dest_width, -dest_width,
|
||||
src_width, DEST_PIXEL_WIDTH, -dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette,
|
||||
miny, maxy);
|
||||
@ -742,10 +1175,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width) {
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
}
|
||||
drawfn fn = pxa2xx_drawfn(s);
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
@ -759,14 +1189,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
|
||||
src_width *= 2;
|
||||
}
|
||||
|
||||
dest_width = s->xres * s->dest_width;
|
||||
dest_width = s->xres * DEST_PIXEL_WIDTH;
|
||||
*miny = 0;
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, -dest_width, -s->dest_width,
|
||||
src_width, -dest_width, -DEST_PIXEL_WIDTH,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
}
|
||||
@ -776,10 +1206,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width) {
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
}
|
||||
drawfn fn = pxa2xx_drawfn(s);
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
@ -793,14 +1220,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
|
||||
src_width *= 2;
|
||||
}
|
||||
|
||||
dest_width = s->yres * s->dest_width;
|
||||
dest_width = s->yres * DEST_PIXEL_WIDTH;
|
||||
*miny = 0;
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, -s->dest_width, dest_width,
|
||||
src_width, -DEST_PIXEL_WIDTH, dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette,
|
||||
miny, maxy);
|
||||
@ -990,17 +1417,6 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = {
|
||||
}
|
||||
};
|
||||
|
||||
#define BITS 8
|
||||
#include "pxa2xx_template.h"
|
||||
#define BITS 15
|
||||
#include "pxa2xx_template.h"
|
||||
#define BITS 16
|
||||
#include "pxa2xx_template.h"
|
||||
#define BITS 24
|
||||
#include "pxa2xx_template.h"
|
||||
#define BITS 32
|
||||
#include "pxa2xx_template.h"
|
||||
|
||||
static const GraphicHwOps pxa2xx_ops = {
|
||||
.invalidate = pxa2xx_invalidate_display,
|
||||
.gfx_update = pxa2xx_update_display,
|
||||
@ -1010,7 +1426,6 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
|
||||
hwaddr base, qemu_irq irq)
|
||||
{
|
||||
PXA2xxLCDState *s;
|
||||
DisplaySurface *surface;
|
||||
|
||||
s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
|
||||
s->invalidated = 1;
|
||||
@ -1024,41 +1439,6 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
|
||||
s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
case 0:
|
||||
s->dest_width = 0;
|
||||
break;
|
||||
case 8:
|
||||
s->line_fn[0] = pxa2xx_draw_fn_8;
|
||||
s->line_fn[1] = pxa2xx_draw_fn_8t;
|
||||
s->dest_width = 1;
|
||||
break;
|
||||
case 15:
|
||||
s->line_fn[0] = pxa2xx_draw_fn_15;
|
||||
s->line_fn[1] = pxa2xx_draw_fn_15t;
|
||||
s->dest_width = 2;
|
||||
break;
|
||||
case 16:
|
||||
s->line_fn[0] = pxa2xx_draw_fn_16;
|
||||
s->line_fn[1] = pxa2xx_draw_fn_16t;
|
||||
s->dest_width = 2;
|
||||
break;
|
||||
case 24:
|
||||
s->line_fn[0] = pxa2xx_draw_fn_24;
|
||||
s->line_fn[1] = pxa2xx_draw_fn_24t;
|
||||
s->dest_width = 3;
|
||||
break;
|
||||
case 32:
|
||||
s->line_fn[0] = pxa2xx_draw_fn_32;
|
||||
s->line_fn[1] = pxa2xx_draw_fn_32t;
|
||||
s->dest_width = 4;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: Bad color depth\n", __func__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
|
||||
|
||||
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
* Intel XScale PXA255/270 LCDC emulation.
|
||||
*
|
||||
* Copyright (c) 2006 Openedhand Ltd.
|
||||
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
||||
*
|
||||
* This code is licensed under the GPLv2.
|
||||
*
|
||||
* Framebuffer format conversion routines.
|
||||
*/
|
||||
|
||||
# define SKIP_PIXEL(to) to += deststep
|
||||
#if BITS == 8
|
||||
# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
|
||||
#elif BITS == 15 || BITS == 16
|
||||
# define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
*(uint16_t *) to = from; \
|
||||
SKIP_PIXEL(to); \
|
||||
} while (0)
|
||||
#elif BITS == 24
|
||||
# define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
*(uint16_t *) to = from; \
|
||||
*(to + 2) = (from) >> 16; \
|
||||
SKIP_PIXEL(to); \
|
||||
} while (0)
|
||||
#elif BITS == 32
|
||||
# define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
*(uint32_t *) to = from; \
|
||||
SKIP_PIXEL(to); \
|
||||
} while (0)
|
||||
#else
|
||||
# error unknown bit depth
|
||||
#endif
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
# define SWAP_WORDS 1
|
||||
#endif
|
||||
|
||||
#define FN_2(x) FN(x + 1) FN(x)
|
||||
#define FN_4(x) FN_2(x + 2) FN_2(x)
|
||||
|
||||
static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN_4(12)
|
||||
FN_4(8)
|
||||
FN_4(4)
|
||||
FN_4(0)
|
||||
#else
|
||||
FN_4(0)
|
||||
FN_4(4)
|
||||
FN_4(8)
|
||||
FN_4(12)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 16;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN_2(6)
|
||||
FN_2(4)
|
||||
FN_2(2)
|
||||
FN_2(0)
|
||||
#else
|
||||
FN_2(0)
|
||||
FN_2(2)
|
||||
FN_2(4)
|
||||
FN_2(6)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 8;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t *palette = opaque;
|
||||
uint32_t data;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
|
||||
#ifdef SWAP_WORDS
|
||||
FN(24)
|
||||
FN(16)
|
||||
FN(8)
|
||||
FN(0)
|
||||
#else
|
||||
FN(0)
|
||||
FN(8)
|
||||
FN(16)
|
||||
FN(24)
|
||||
#endif
|
||||
#undef FN
|
||||
width -= 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 2;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
if (data & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
data >>= 1;
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
if (data & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 2;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x3f) << 2;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* The wicked packed format */
|
||||
static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data[3];
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data[0] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[1] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[2] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
#ifdef SWAP_WORDS
|
||||
data[0] = bswap32(data[0]);
|
||||
data[1] = bswap32(data[1]);
|
||||
data[2] = bswap32(data[2]);
|
||||
#endif
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
r = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 12;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = ((data[1] & 0xf) << 4) | (data[0] << 2);
|
||||
data[1] >>= 4;
|
||||
r = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 12;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
b = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
g = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
r = ((data[2] & 0x3) << 6) | (data[1] << 2);
|
||||
data[2] >>= 8;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
b = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
g = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
r = data[2] << 2;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
if (data & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* The wicked packed format */
|
||||
static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data[3];
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data[0] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[1] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
data[2] = *(uint32_t *) src;
|
||||
src += 4;
|
||||
# ifdef SWAP_WORDS
|
||||
data[0] = bswap32(data[0]);
|
||||
data[1] = bswap32(data[1]);
|
||||
data[2] = bswap32(data[2]);
|
||||
# endif
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
r = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
if (data[0] & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
data[0] >>= 6;
|
||||
b = (data[0] & 0x3f) << 2;
|
||||
data[0] >>= 6;
|
||||
g = ((data[1] & 0xf) << 4) | (data[0] << 2);
|
||||
data[1] >>= 4;
|
||||
r = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
if (data[1] & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
data[1] >>= 6;
|
||||
b = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
g = (data[1] & 0x3f) << 2;
|
||||
data[1] >>= 6;
|
||||
r = ((data[2] & 0x3) << 6) | (data[1] << 2);
|
||||
data[2] >>= 2;
|
||||
if (data[2] & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
data[2] >>= 6;
|
||||
b = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
g = (data[2] & 0x3f) << 2;
|
||||
data[2] >>= 6;
|
||||
r = data[2] << 2;
|
||||
data[2] >>= 6;
|
||||
if (data[2] & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = data & 0xff;
|
||||
data >>= 8;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = (data & 0x7f) << 1;
|
||||
data >>= 7;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
data >>= 8;
|
||||
if (data & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
|
||||
uint8_t *dest, const uint8_t *src, int width, int deststep)
|
||||
{
|
||||
uint32_t data;
|
||||
unsigned int r, g, b;
|
||||
while (width > 0) {
|
||||
data = *(uint32_t *) src;
|
||||
#ifdef SWAP_WORDS
|
||||
data = bswap32(data);
|
||||
#endif
|
||||
b = data & 0xff;
|
||||
data >>= 8;
|
||||
g = data & 0xff;
|
||||
data >>= 8;
|
||||
r = data & 0xff;
|
||||
data >>= 8;
|
||||
if (data & 1)
|
||||
SKIP_PIXEL(dest);
|
||||
else
|
||||
COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
|
||||
width -= 1;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overlay planes disabled, no transparency */
|
||||
static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
|
||||
{
|
||||
[0 ... 0xf] = NULL,
|
||||
[pxa_lcdc_2bpp] = glue(pxa2xx_draw_line2_, BITS),
|
||||
[pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
|
||||
[pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
|
||||
[pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16_, BITS),
|
||||
[pxa_lcdc_18bpp] = glue(pxa2xx_draw_line18_, BITS),
|
||||
[pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
|
||||
[pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24_, BITS),
|
||||
};
|
||||
|
||||
/* Overlay planes enabled, transparency used */
|
||||
static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
|
||||
{
|
||||
[0 ... 0xf] = NULL,
|
||||
[pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS),
|
||||
[pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS),
|
||||
[pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16t_, BITS),
|
||||
[pxa_lcdc_19bpp] = glue(pxa2xx_draw_line19_, BITS),
|
||||
[pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
|
||||
[pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24t_, BITS),
|
||||
[pxa_lcdc_25bpp] = glue(pxa2xx_draw_line25_, BITS),
|
||||
};
|
||||
|
||||
#undef BITS
|
||||
#undef COPY_PIXEL
|
||||
#undef SKIP_PIXEL
|
||||
|
||||
#ifdef SWAP_WORDS
|
||||
# undef SWAP_WORDS
|
||||
#endif
|
@ -35,6 +35,7 @@
|
||||
#include "hw/i386/x86-iommu.h"
|
||||
#include "hw/pci-host/q35.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/i386/apic_internal.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
@ -1884,6 +1885,8 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s,
|
||||
case 3:
|
||||
mask = 7; /* Mask bit 2:0 in the SID field */
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
mask = ~mask;
|
||||
|
||||
@ -3453,24 +3456,6 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
|
||||
return vtd_dev_as;
|
||||
}
|
||||
|
||||
static uint64_t get_naturally_aligned_size(uint64_t start,
|
||||
uint64_t size, int gaw)
|
||||
{
|
||||
uint64_t max_mask = 1ULL << gaw;
|
||||
uint64_t alignment = start ? start & -start : max_mask;
|
||||
|
||||
alignment = MIN(alignment, max_mask);
|
||||
size = MIN(size, max_mask);
|
||||
|
||||
if (alignment <= size) {
|
||||
/* Increase the alignment of start */
|
||||
return alignment;
|
||||
} else {
|
||||
/* Find the largest page mask from size */
|
||||
return 1ULL << (63 - clz64(size));
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap the whole range in the notifier's scope. */
|
||||
static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
{
|
||||
@ -3499,13 +3484,14 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
|
||||
while (remain >= VTD_PAGE_SIZE) {
|
||||
IOMMUTLBEvent event;
|
||||
uint64_t mask = get_naturally_aligned_size(start, remain, s->aw_bits);
|
||||
uint64_t mask = dma_aligned_pow2_mask(start, end, s->aw_bits);
|
||||
uint64_t size = mask + 1;
|
||||
|
||||
assert(mask);
|
||||
assert(size);
|
||||
|
||||
event.type = IOMMU_NOTIFIER_UNMAP;
|
||||
event.entry.iova = start;
|
||||
event.entry.addr_mask = mask - 1;
|
||||
event.entry.addr_mask = mask;
|
||||
event.entry.target_as = &address_space_memory;
|
||||
event.entry.perm = IOMMU_NONE;
|
||||
/* This field is meaningless for unmap */
|
||||
@ -3513,8 +3499,8 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
|
||||
|
||||
memory_region_notify_iommu_one(n, &event);
|
||||
|
||||
start += mask;
|
||||
remain -= mask;
|
||||
start += size;
|
||||
remain -= size;
|
||||
}
|
||||
|
||||
assert(!remain);
|
||||
|
@ -65,6 +65,7 @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm7xx_clk.c',
|
||||
'npcm7xx_gcr.c',
|
||||
'npcm7xx_mft.c',
|
||||
'npcm7xx_pwm.c',
|
||||
'npcm7xx_rng.c',
|
||||
))
|
||||
@ -85,6 +86,7 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
|
||||
|
540
hw/misc/npcm7xx_mft.c
Normal file
540
hw/misc/npcm7xx_mft.c
Normal file
@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx MFT Module
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/misc/npcm7xx_mft.h"
|
||||
#include "hw/misc/npcm7xx_pwm.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/units.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
* Some of the registers can only accessed via 16-bit ops and some can only
|
||||
* be accessed via 8-bit ops. However we mark all of them using REG16 to
|
||||
* simplify implementation. npcm7xx_mft_check_mem_op checks the access length
|
||||
* of memory operations.
|
||||
*/
|
||||
REG16(NPCM7XX_MFT_CNT1, 0x00);
|
||||
REG16(NPCM7XX_MFT_CRA, 0x02);
|
||||
REG16(NPCM7XX_MFT_CRB, 0x04);
|
||||
REG16(NPCM7XX_MFT_CNT2, 0x06);
|
||||
REG16(NPCM7XX_MFT_PRSC, 0x08);
|
||||
REG16(NPCM7XX_MFT_CKC, 0x0a);
|
||||
REG16(NPCM7XX_MFT_MCTRL, 0x0c);
|
||||
REG16(NPCM7XX_MFT_ICTRL, 0x0e);
|
||||
REG16(NPCM7XX_MFT_ICLR, 0x10);
|
||||
REG16(NPCM7XX_MFT_IEN, 0x12);
|
||||
REG16(NPCM7XX_MFT_CPA, 0x14);
|
||||
REG16(NPCM7XX_MFT_CPB, 0x16);
|
||||
REG16(NPCM7XX_MFT_CPCFG, 0x18);
|
||||
REG16(NPCM7XX_MFT_INASEL, 0x1a);
|
||||
REG16(NPCM7XX_MFT_INBSEL, 0x1c);
|
||||
|
||||
/* Register Fields */
|
||||
#define NPCM7XX_MFT_CKC_C2CSEL BIT(3)
|
||||
#define NPCM7XX_MFT_CKC_C1CSEL BIT(0)
|
||||
|
||||
#define NPCM7XX_MFT_MCTRL_TBEN BIT(6)
|
||||
#define NPCM7XX_MFT_MCTRL_TAEN BIT(5)
|
||||
#define NPCM7XX_MFT_MCTRL_TBEDG BIT(4)
|
||||
#define NPCM7XX_MFT_MCTRL_TAEDG BIT(3)
|
||||
#define NPCM7XX_MFT_MCTRL_MODE5 BIT(2)
|
||||
|
||||
#define NPCM7XX_MFT_ICTRL_TFPND BIT(5)
|
||||
#define NPCM7XX_MFT_ICTRL_TEPND BIT(4)
|
||||
#define NPCM7XX_MFT_ICTRL_TDPND BIT(3)
|
||||
#define NPCM7XX_MFT_ICTRL_TCPND BIT(2)
|
||||
#define NPCM7XX_MFT_ICTRL_TBPND BIT(1)
|
||||
#define NPCM7XX_MFT_ICTRL_TAPND BIT(0)
|
||||
|
||||
#define NPCM7XX_MFT_ICLR_TFCLR BIT(5)
|
||||
#define NPCM7XX_MFT_ICLR_TECLR BIT(4)
|
||||
#define NPCM7XX_MFT_ICLR_TDCLR BIT(3)
|
||||
#define NPCM7XX_MFT_ICLR_TCCLR BIT(2)
|
||||
#define NPCM7XX_MFT_ICLR_TBCLR BIT(1)
|
||||
#define NPCM7XX_MFT_ICLR_TACLR BIT(0)
|
||||
|
||||
#define NPCM7XX_MFT_IEN_TFIEN BIT(5)
|
||||
#define NPCM7XX_MFT_IEN_TEIEN BIT(4)
|
||||
#define NPCM7XX_MFT_IEN_TDIEN BIT(3)
|
||||
#define NPCM7XX_MFT_IEN_TCIEN BIT(2)
|
||||
#define NPCM7XX_MFT_IEN_TBIEN BIT(1)
|
||||
#define NPCM7XX_MFT_IEN_TAIEN BIT(0)
|
||||
|
||||
#define NPCM7XX_MFT_CPCFG_GET_B(rv) extract8((rv), 4, 4)
|
||||
#define NPCM7XX_MFT_CPCFG_GET_A(rv) extract8((rv), 0, 4)
|
||||
#define NPCM7XX_MFT_CPCFG_HIEN BIT(3)
|
||||
#define NPCM7XX_MFT_CPCFG_EQEN BIT(2)
|
||||
#define NPCM7XX_MFT_CPCFG_LOEN BIT(1)
|
||||
#define NPCM7XX_MFT_CPCFG_CPSEL BIT(0)
|
||||
|
||||
#define NPCM7XX_MFT_INASEL_SELA BIT(0)
|
||||
#define NPCM7XX_MFT_INBSEL_SELB BIT(0)
|
||||
|
||||
/* Max CNT values of the module. The CNT value is a countdown from it. */
|
||||
#define NPCM7XX_MFT_MAX_CNT 0xFFFF
|
||||
|
||||
/* Each fan revolution should generated 2 pulses */
|
||||
#define NPCM7XX_MFT_PULSE_PER_REVOLUTION 2
|
||||
|
||||
typedef enum NPCM7xxMFTCaptureState {
|
||||
/* capture succeeded with a valid CNT value. */
|
||||
NPCM7XX_CAPTURE_SUCCEED,
|
||||
/* capture stopped prematurely due to reaching CPCFG condition. */
|
||||
NPCM7XX_CAPTURE_COMPARE_HIT,
|
||||
/* capture fails since it reaches underflow condition for CNT. */
|
||||
NPCM7XX_CAPTURE_UNDERFLOW,
|
||||
} NPCM7xxMFTCaptureState;
|
||||
|
||||
static void npcm7xx_mft_reset(NPCM7xxMFTState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Only registers PRSC ~ INBSEL need to be reset. */
|
||||
for (i = R_NPCM7XX_MFT_PRSC; i <= R_NPCM7XX_MFT_INBSEL; ++i) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_clear_interrupt(NPCM7xxMFTState *s, uint8_t iclr)
|
||||
{
|
||||
/*
|
||||
* Clear bits in ICTRL where corresponding bits in iclr is 1.
|
||||
* Both iclr and ictrl are 8-bit regs. (See npcm7xx_mft_check_mem_op)
|
||||
*/
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] &= ~iclr;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the CPCFG's condition should be triggered during count down from
|
||||
* NPCM7XX_MFT_MAX_CNT to src if compared to tgt, return the count when
|
||||
* the condition is triggered.
|
||||
* Otherwise return -1.
|
||||
* Since tgt is uint16_t it must always <= NPCM7XX_MFT_MAX_CNT.
|
||||
*/
|
||||
static int npcm7xx_mft_compare(int32_t src, uint16_t tgt, uint8_t cpcfg)
|
||||
{
|
||||
if (cpcfg & NPCM7XX_MFT_CPCFG_HIEN) {
|
||||
return NPCM7XX_MFT_MAX_CNT;
|
||||
}
|
||||
if ((cpcfg & NPCM7XX_MFT_CPCFG_EQEN) && (src <= tgt)) {
|
||||
return tgt;
|
||||
}
|
||||
if ((cpcfg & NPCM7XX_MFT_CPCFG_LOEN) && (tgt > 0) && (src < tgt)) {
|
||||
return tgt - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Compute CNT according to corresponding fan's RPM. */
|
||||
static NPCM7xxMFTCaptureState npcm7xx_mft_compute_cnt(
|
||||
Clock *clock, uint32_t max_rpm, uint32_t duty, uint16_t tgt,
|
||||
uint8_t cpcfg, uint16_t *cnt)
|
||||
{
|
||||
uint32_t rpm = (uint64_t)max_rpm * (uint64_t)duty / NPCM7XX_PWM_MAX_DUTY;
|
||||
int32_t count;
|
||||
int stopped;
|
||||
NPCM7xxMFTCaptureState state;
|
||||
|
||||
if (rpm == 0) {
|
||||
/*
|
||||
* If RPM = 0, capture won't happen. CNT will continue count down.
|
||||
* So it's effective equivalent to have a cnt > NPCM7XX_MFT_MAX_CNT
|
||||
*/
|
||||
count = NPCM7XX_MFT_MAX_CNT + 1;
|
||||
} else {
|
||||
/*
|
||||
* RPM = revolution/min. The time for one revlution (in ns) is
|
||||
* MINUTE_TO_NANOSECOND / RPM.
|
||||
*/
|
||||
count = clock_ns_to_ticks(clock, (60 * NANOSECONDS_PER_SECOND) /
|
||||
(rpm * NPCM7XX_MFT_PULSE_PER_REVOLUTION));
|
||||
}
|
||||
|
||||
if (count > NPCM7XX_MFT_MAX_CNT) {
|
||||
count = -1;
|
||||
} else {
|
||||
/* The CNT is a countdown value from NPCM7XX_MFT_MAX_CNT. */
|
||||
count = NPCM7XX_MFT_MAX_CNT - count;
|
||||
}
|
||||
stopped = npcm7xx_mft_compare(count, tgt, cpcfg);
|
||||
if (stopped == -1) {
|
||||
if (count == -1) {
|
||||
/* Underflow */
|
||||
state = NPCM7XX_CAPTURE_UNDERFLOW;
|
||||
} else {
|
||||
state = NPCM7XX_CAPTURE_SUCCEED;
|
||||
}
|
||||
} else {
|
||||
count = stopped;
|
||||
state = NPCM7XX_CAPTURE_COMPARE_HIT;
|
||||
}
|
||||
|
||||
if (count != -1) {
|
||||
*cnt = count;
|
||||
}
|
||||
trace_npcm7xx_mft_rpm(clock->canonical_path, clock_get_hz(clock),
|
||||
state, count, rpm, duty);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Capture Fan RPM and update CNT and CR registers accordingly.
|
||||
* Raise IRQ if certain contidions are met in IEN.
|
||||
*/
|
||||
static void npcm7xx_mft_capture(NPCM7xxMFTState *s)
|
||||
{
|
||||
int irq_level = 0;
|
||||
NPCM7xxMFTCaptureState state;
|
||||
int sel;
|
||||
uint8_t cpcfg;
|
||||
|
||||
/*
|
||||
* If not mode 5, the behavior is undefined. We just do nothing in this
|
||||
* case.
|
||||
*/
|
||||
if (!(s->regs[R_NPCM7XX_MFT_MCTRL] & NPCM7XX_MFT_MCTRL_MODE5)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Capture input A. */
|
||||
if (s->regs[R_NPCM7XX_MFT_MCTRL] & NPCM7XX_MFT_MCTRL_TAEN &&
|
||||
s->regs[R_NPCM7XX_MFT_CKC] & NPCM7XX_MFT_CKC_C1CSEL) {
|
||||
sel = s->regs[R_NPCM7XX_MFT_INASEL] & NPCM7XX_MFT_INASEL_SELA;
|
||||
cpcfg = NPCM7XX_MFT_CPCFG_GET_A(s->regs[R_NPCM7XX_MFT_CPCFG]);
|
||||
state = npcm7xx_mft_compute_cnt(s->clock_1,
|
||||
sel ? s->max_rpm[2] : s->max_rpm[0],
|
||||
sel ? s->duty[2] : s->duty[0],
|
||||
s->regs[R_NPCM7XX_MFT_CPA],
|
||||
cpcfg,
|
||||
&s->regs[R_NPCM7XX_MFT_CNT1]);
|
||||
switch (state) {
|
||||
case NPCM7XX_CAPTURE_SUCCEED:
|
||||
/* Interrupt on input capture on TAn transition - TAPND */
|
||||
s->regs[R_NPCM7XX_MFT_CRA] = s->regs[R_NPCM7XX_MFT_CNT1];
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TAPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TAIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case NPCM7XX_CAPTURE_COMPARE_HIT:
|
||||
/* Compare Hit - TEPND */
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TEPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TEIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case NPCM7XX_CAPTURE_UNDERFLOW:
|
||||
/* Underflow - TCPND */
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TCPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TCIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture input B. */
|
||||
if (s->regs[R_NPCM7XX_MFT_MCTRL] & NPCM7XX_MFT_MCTRL_TBEN &&
|
||||
s->regs[R_NPCM7XX_MFT_CKC] & NPCM7XX_MFT_CKC_C2CSEL) {
|
||||
sel = s->regs[R_NPCM7XX_MFT_INBSEL] & NPCM7XX_MFT_INBSEL_SELB;
|
||||
cpcfg = NPCM7XX_MFT_CPCFG_GET_B(s->regs[R_NPCM7XX_MFT_CPCFG]);
|
||||
state = npcm7xx_mft_compute_cnt(s->clock_2,
|
||||
sel ? s->max_rpm[3] : s->max_rpm[1],
|
||||
sel ? s->duty[3] : s->duty[1],
|
||||
s->regs[R_NPCM7XX_MFT_CPB],
|
||||
cpcfg,
|
||||
&s->regs[R_NPCM7XX_MFT_CNT2]);
|
||||
switch (state) {
|
||||
case NPCM7XX_CAPTURE_SUCCEED:
|
||||
/* Interrupt on input capture on TBn transition - TBPND */
|
||||
s->regs[R_NPCM7XX_MFT_CRB] = s->regs[R_NPCM7XX_MFT_CNT2];
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TBPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TBIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case NPCM7XX_CAPTURE_COMPARE_HIT:
|
||||
/* Compare Hit - TFPND */
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TFPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TFIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case NPCM7XX_CAPTURE_UNDERFLOW:
|
||||
/* Underflow - TDPND */
|
||||
s->regs[R_NPCM7XX_MFT_ICTRL] |= NPCM7XX_MFT_ICTRL_TDPND;
|
||||
if (s->regs[R_NPCM7XX_MFT_IEN] & NPCM7XX_MFT_IEN_TDIEN) {
|
||||
irq_level = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
trace_npcm7xx_mft_capture(DEVICE(s)->canonical_path, irq_level);
|
||||
qemu_set_irq(s->irq, irq_level);
|
||||
}
|
||||
|
||||
/* Update clock for counters. */
|
||||
static void npcm7xx_mft_update_clock(void *opaque, ClockEvent event)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(opaque);
|
||||
uint64_t prescaled_clock_period;
|
||||
|
||||
prescaled_clock_period = clock_get(s->clock_in) *
|
||||
(s->regs[R_NPCM7XX_MFT_PRSC] + 1ULL);
|
||||
trace_npcm7xx_mft_update_clock(s->clock_in->canonical_path,
|
||||
s->regs[R_NPCM7XX_MFT_CKC],
|
||||
clock_get(s->clock_in),
|
||||
prescaled_clock_period);
|
||||
/* Update clock 1 */
|
||||
if (s->regs[R_NPCM7XX_MFT_CKC] & NPCM7XX_MFT_CKC_C1CSEL) {
|
||||
/* Clock is prescaled. */
|
||||
clock_update(s->clock_1, prescaled_clock_period);
|
||||
} else {
|
||||
/* Clock stopped. */
|
||||
clock_update(s->clock_1, 0);
|
||||
}
|
||||
/* Update clock 2 */
|
||||
if (s->regs[R_NPCM7XX_MFT_CKC] & NPCM7XX_MFT_CKC_C2CSEL) {
|
||||
/* Clock is prescaled. */
|
||||
clock_update(s->clock_2, prescaled_clock_period);
|
||||
} else {
|
||||
/* Clock stopped. */
|
||||
clock_update(s->clock_2, 0);
|
||||
}
|
||||
|
||||
npcm7xx_mft_capture(s);
|
||||
}
|
||||
|
||||
static uint64_t npcm7xx_mft_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(opaque);
|
||||
uint16_t value = 0;
|
||||
|
||||
switch (offset) {
|
||||
case A_NPCM7XX_MFT_ICLR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: register @ 0x%04" HWADDR_PRIx " is write-only\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
value = s->regs[offset / 2];
|
||||
}
|
||||
|
||||
trace_npcm7xx_mft_read(DEVICE(s)->canonical_path, offset, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_write(void *opaque, hwaddr offset,
|
||||
uint64_t v, unsigned size)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(opaque);
|
||||
|
||||
trace_npcm7xx_mft_write(DEVICE(s)->canonical_path, offset, v);
|
||||
switch (offset) {
|
||||
case A_NPCM7XX_MFT_ICLR:
|
||||
npcm7xx_mft_clear_interrupt(s, v);
|
||||
break;
|
||||
|
||||
case A_NPCM7XX_MFT_CKC:
|
||||
case A_NPCM7XX_MFT_PRSC:
|
||||
s->regs[offset / 2] = v;
|
||||
npcm7xx_mft_update_clock(s, ClockUpdate);
|
||||
break;
|
||||
|
||||
default:
|
||||
s->regs[offset / 2] = v;
|
||||
npcm7xx_mft_capture(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool npcm7xx_mft_check_mem_op(void *opaque, hwaddr offset,
|
||||
unsigned size, bool is_write,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
switch (offset) {
|
||||
/* 16-bit registers. Must be accessed with 16-bit read/write.*/
|
||||
case A_NPCM7XX_MFT_CNT1:
|
||||
case A_NPCM7XX_MFT_CRA:
|
||||
case A_NPCM7XX_MFT_CRB:
|
||||
case A_NPCM7XX_MFT_CNT2:
|
||||
case A_NPCM7XX_MFT_CPA:
|
||||
case A_NPCM7XX_MFT_CPB:
|
||||
return size == 2;
|
||||
|
||||
/* 8-bit registers. Must be accessed with 8-bit read/write.*/
|
||||
case A_NPCM7XX_MFT_PRSC:
|
||||
case A_NPCM7XX_MFT_CKC:
|
||||
case A_NPCM7XX_MFT_MCTRL:
|
||||
case A_NPCM7XX_MFT_ICTRL:
|
||||
case A_NPCM7XX_MFT_ICLR:
|
||||
case A_NPCM7XX_MFT_IEN:
|
||||
case A_NPCM7XX_MFT_CPCFG:
|
||||
case A_NPCM7XX_MFT_INASEL:
|
||||
case A_NPCM7XX_MFT_INBSEL:
|
||||
return size == 1;
|
||||
|
||||
default:
|
||||
/* Invalid registers. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_get_max_rpm(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_set_max_rpm(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
|
||||
uint32_t *max_rpm = opaque;
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*max_rpm = value;
|
||||
npcm7xx_mft_capture(s);
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_duty_handler(void *opaque, int n, int value)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(opaque);
|
||||
|
||||
trace_npcm7xx_mft_set_duty(DEVICE(s)->canonical_path, n, value);
|
||||
s->duty[n] = value;
|
||||
npcm7xx_mft_capture(s);
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps npcm7xx_mft_ops = {
|
||||
.read = npcm7xx_mft_read,
|
||||
.write = npcm7xx_mft_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 2,
|
||||
.unaligned = false,
|
||||
.accepts = npcm7xx_mft_check_mem_op,
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_mft_enter_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
|
||||
|
||||
npcm7xx_mft_reset(s);
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_hold_reset(Object *obj)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
|
||||
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_init(Object *obj)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_mft_ops, s,
|
||||
TYPE_NPCM7XX_MFT, 4 * KiB);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
s->clock_in = qdev_init_clock_in(dev, "clock-in", npcm7xx_mft_update_clock,
|
||||
s, ClockUpdate);
|
||||
s->clock_1 = qdev_init_clock_out(dev, "clock1");
|
||||
s->clock_2 = qdev_init_clock_out(dev, "clock2");
|
||||
|
||||
for (int i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
|
||||
object_property_add(obj, "max_rpm[*]", "uint32",
|
||||
npcm7xx_mft_get_max_rpm,
|
||||
npcm7xx_mft_set_max_rpm,
|
||||
NULL, &s->max_rpm[i]);
|
||||
}
|
||||
qdev_init_gpio_in_named(dev, npcm7xx_mft_duty_handler, "duty",
|
||||
NPCM7XX_MFT_FANIN_COUNT);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_mft = {
|
||||
.name = "npcm7xx-mft-module",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CLOCK(clock_in, NPCM7xxMFTState),
|
||||
VMSTATE_CLOCK(clock_1, NPCM7xxMFTState),
|
||||
VMSTATE_CLOCK(clock_2, NPCM7xxMFTState),
|
||||
VMSTATE_UINT16_ARRAY(regs, NPCM7xxMFTState, NPCM7XX_MFT_NR_REGS),
|
||||
VMSTATE_UINT32_ARRAY(max_rpm, NPCM7xxMFTState, NPCM7XX_MFT_FANIN_COUNT),
|
||||
VMSTATE_UINT32_ARRAY(duty, NPCM7xxMFTState, NPCM7XX_MFT_FANIN_COUNT),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_mft_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "NPCM7xx MFT Controller";
|
||||
dc->vmsd = &vmstate_npcm7xx_mft;
|
||||
rc->phases.enter = npcm7xx_mft_enter_reset;
|
||||
rc->phases.hold = npcm7xx_mft_hold_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo npcm7xx_mft_info = {
|
||||
.name = TYPE_NPCM7XX_MFT,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NPCM7xxMFTState),
|
||||
.class_init = npcm7xx_mft_class_init,
|
||||
.instance_init = npcm7xx_mft_init,
|
||||
};
|
||||
|
||||
static void npcm7xx_mft_register_type(void)
|
||||
{
|
||||
type_register_static(&npcm7xx_mft_info);
|
||||
}
|
||||
type_init(npcm7xx_mft_register_type);
|
@ -139,6 +139,7 @@ static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
|
||||
trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
|
||||
p->index, p->duty, duty);
|
||||
p->duty = duty;
|
||||
qemu_set_irq(p->module->duty_gpio_out[p->index], p->duty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,6 +484,7 @@ static void npcm7xx_pwm_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int i;
|
||||
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->pwm) != NPCM7XX_PWM_PER_MODULE);
|
||||
for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
|
||||
NPCM7xxPWM *p = &s->pwm[i];
|
||||
p->module = s;
|
||||
@ -501,6 +503,8 @@ static void npcm7xx_pwm_init(Object *obj)
|
||||
object_property_add_uint32_ptr(obj, "duty[*]",
|
||||
&s->pwm[i].duty, OBJ_PROP_FLAG_READ);
|
||||
}
|
||||
qdev_init_gpio_out_named(DEVICE(s), s->duty_gpio_out,
|
||||
"duty-gpio-out", NPCM7XX_PWM_PER_MODULE);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_pwm = {
|
||||
|
@ -116,6 +116,14 @@ npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
|
||||
npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
|
||||
npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
|
||||
|
||||
# npcm7xx_mft.c
|
||||
npcm7xx_mft_read(const char *name, uint64_t offset, uint16_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
|
||||
npcm7xx_mft_write(const char *name, uint64_t offset, uint16_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
|
||||
npcm7xx_mft_rpm(const char *clock, uint32_t clock_hz, int state, int32_t cnt, uint32_t rpm, uint32_t duty) " fan clk: %s clock_hz: %" PRIu32 ", state: %d, cnt: %" PRIi32 ", rpm: %" PRIu32 ", duty: %" PRIu32
|
||||
npcm7xx_mft_capture(const char *name, int irq_level) "%s: level: %d"
|
||||
npcm7xx_mft_update_clock(const char *name, uint16_t sel, uint64_t clock_period, uint64_t prescaled_clock_period) "%s: sel: 0x%02" PRIx16 ", period: %" PRIu64 ", prescaled: %" PRIu64
|
||||
npcm7xx_mft_set_duty(const char *name, int n, int value) "%s[%d]: %d"
|
||||
|
||||
# npcm7xx_rng.c
|
||||
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
|
253
hw/misc/xlnx-versal-xramc.c
Normal file
253
hw/misc/xlnx-versal-xramc.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* QEMU model of the Xilinx XRAM Controller.
|
||||
*
|
||||
* Copyright (c) 2021 Xilinx Inc.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/register.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/misc/xlnx-versal-xramc.h"
|
||||
|
||||
#ifndef XLNX_XRAM_CTRL_ERR_DEBUG
|
||||
#define XLNX_XRAM_CTRL_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
static void xram_update_irq(XlnxXramCtrl *s)
|
||||
{
|
||||
bool pending = s->regs[R_XRAM_ISR] & ~s->regs[R_XRAM_IMR];
|
||||
qemu_set_irq(s->irq, pending);
|
||||
}
|
||||
|
||||
static void xram_isr_postw(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque);
|
||||
xram_update_irq(s);
|
||||
}
|
||||
|
||||
static uint64_t xram_ien_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque);
|
||||
uint32_t val = val64;
|
||||
|
||||
s->regs[R_XRAM_IMR] &= ~val;
|
||||
xram_update_irq(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t xram_ids_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(reg->opaque);
|
||||
uint32_t val = val64;
|
||||
|
||||
s->regs[R_XRAM_IMR] |= val;
|
||||
xram_update_irq(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const RegisterAccessInfo xram_ctrl_regs_info[] = {
|
||||
{ .name = "XRAM_ERR_CTRL", .addr = A_XRAM_ERR_CTRL,
|
||||
.reset = 0xf,
|
||||
.rsvd = 0xfffffff0,
|
||||
},{ .name = "XRAM_ISR", .addr = A_XRAM_ISR,
|
||||
.rsvd = 0xfffff800,
|
||||
.w1c = 0x7ff,
|
||||
.post_write = xram_isr_postw,
|
||||
},{ .name = "XRAM_IMR", .addr = A_XRAM_IMR,
|
||||
.reset = 0x7ff,
|
||||
.rsvd = 0xfffff800,
|
||||
.ro = 0x7ff,
|
||||
},{ .name = "XRAM_IEN", .addr = A_XRAM_IEN,
|
||||
.rsvd = 0xfffff800,
|
||||
.pre_write = xram_ien_prew,
|
||||
},{ .name = "XRAM_IDS", .addr = A_XRAM_IDS,
|
||||
.rsvd = 0xfffff800,
|
||||
.pre_write = xram_ids_prew,
|
||||
},{ .name = "XRAM_ECC_CNTL", .addr = A_XRAM_ECC_CNTL,
|
||||
.rsvd = 0xfffffff8,
|
||||
},{ .name = "XRAM_CLR_EXE", .addr = A_XRAM_CLR_EXE,
|
||||
.rsvd = 0xffffff00,
|
||||
},{ .name = "XRAM_CE_FFA", .addr = A_XRAM_CE_FFA,
|
||||
.rsvd = 0xfff00000,
|
||||
.ro = 0xfffff,
|
||||
},{ .name = "XRAM_CE_FFD0", .addr = A_XRAM_CE_FFD0,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_CE_FFD1", .addr = A_XRAM_CE_FFD1,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_CE_FFD2", .addr = A_XRAM_CE_FFD2,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_CE_FFD3", .addr = A_XRAM_CE_FFD3,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_CE_FFE", .addr = A_XRAM_CE_FFE,
|
||||
.rsvd = 0xffff0000,
|
||||
.ro = 0xffff,
|
||||
},{ .name = "XRAM_UE_FFA", .addr = A_XRAM_UE_FFA,
|
||||
.rsvd = 0xfff00000,
|
||||
.ro = 0xfffff,
|
||||
},{ .name = "XRAM_UE_FFD0", .addr = A_XRAM_UE_FFD0,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_UE_FFD1", .addr = A_XRAM_UE_FFD1,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_UE_FFD2", .addr = A_XRAM_UE_FFD2,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_UE_FFD3", .addr = A_XRAM_UE_FFD3,
|
||||
.ro = 0xffffffff,
|
||||
},{ .name = "XRAM_UE_FFE", .addr = A_XRAM_UE_FFE,
|
||||
.rsvd = 0xffff0000,
|
||||
.ro = 0xffff,
|
||||
},{ .name = "XRAM_FI_D0", .addr = A_XRAM_FI_D0,
|
||||
},{ .name = "XRAM_FI_D1", .addr = A_XRAM_FI_D1,
|
||||
},{ .name = "XRAM_FI_D2", .addr = A_XRAM_FI_D2,
|
||||
},{ .name = "XRAM_FI_D3", .addr = A_XRAM_FI_D3,
|
||||
},{ .name = "XRAM_FI_SY", .addr = A_XRAM_FI_SY,
|
||||
.rsvd = 0xffff0000,
|
||||
},{ .name = "XRAM_RMW_UE_FFA", .addr = A_XRAM_RMW_UE_FFA,
|
||||
.rsvd = 0xfff00000,
|
||||
.ro = 0xfffff,
|
||||
},{ .name = "XRAM_FI_CNTR", .addr = A_XRAM_FI_CNTR,
|
||||
.rsvd = 0xff000000,
|
||||
},{ .name = "XRAM_IMP", .addr = A_XRAM_IMP,
|
||||
.reset = 0x4,
|
||||
.rsvd = 0xfffffff0,
|
||||
.ro = 0xf,
|
||||
},{ .name = "XRAM_PRDY_DBG", .addr = A_XRAM_PRDY_DBG,
|
||||
.reset = 0xffff,
|
||||
.rsvd = 0xffff0000,
|
||||
.ro = 0xffff,
|
||||
},{ .name = "XRAM_SAFETY_CHK", .addr = A_XRAM_SAFETY_CHK,
|
||||
}
|
||||
};
|
||||
|
||||
static void xram_ctrl_reset_enter(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
|
||||
register_reset(&s->regs_info[i]);
|
||||
}
|
||||
|
||||
ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size);
|
||||
}
|
||||
|
||||
static void xram_ctrl_reset_hold(Object *obj)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
|
||||
|
||||
xram_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps xram_ctrl_ops = {
|
||||
.read = register_read_memory,
|
||||
.write = register_write_memory,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void xram_ctrl_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(dev);
|
||||
|
||||
switch (s->cfg.size) {
|
||||
case 64 * KiB:
|
||||
s->cfg.encoded_size = 0;
|
||||
break;
|
||||
case 128 * KiB:
|
||||
s->cfg.encoded_size = 1;
|
||||
break;
|
||||
case 256 * KiB:
|
||||
s->cfg.encoded_size = 2;
|
||||
break;
|
||||
case 512 * KiB:
|
||||
s->cfg.encoded_size = 3;
|
||||
break;
|
||||
case 1 * MiB:
|
||||
s->cfg.encoded_size = 4;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported XRAM size %" PRId64, s->cfg.size);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_ram(&s->ram, OBJECT(s),
|
||||
object_get_canonical_path_component(OBJECT(s)),
|
||||
s->cfg.size, &error_fatal);
|
||||
sysbus_init_mmio(sbd, &s->ram);
|
||||
}
|
||||
|
||||
static void xram_ctrl_init(Object *obj)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->reg_array =
|
||||
register_init_block32(DEVICE(obj), xram_ctrl_regs_info,
|
||||
ARRAY_SIZE(xram_ctrl_regs_info),
|
||||
s->regs_info, s->regs,
|
||||
&xram_ctrl_ops,
|
||||
XLNX_XRAM_CTRL_ERR_DEBUG,
|
||||
XRAM_CTRL_R_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->reg_array->mem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
static void xram_ctrl_finalize(Object *obj)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
|
||||
register_finalize_block(s->reg_array);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_xram_ctrl = {
|
||||
.name = TYPE_XLNX_XRAM_CTRL,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, XlnxXramCtrl, XRAM_CTRL_R_MAX),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static Property xram_ctrl_properties[] = {
|
||||
DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void xram_ctrl_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = xram_ctrl_realize;
|
||||
dc->vmsd = &vmstate_xram_ctrl;
|
||||
device_class_set_props(dc, xram_ctrl_properties);
|
||||
|
||||
rc->phases.enter = xram_ctrl_reset_enter;
|
||||
rc->phases.hold = xram_ctrl_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo xram_ctrl_info = {
|
||||
.name = TYPE_XLNX_XRAM_CTRL,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(XlnxXramCtrl),
|
||||
.class_init = xram_ctrl_class_init,
|
||||
.instance_init = xram_ctrl_init,
|
||||
.instance_finalize = xram_ctrl_finalize,
|
||||
};
|
||||
|
||||
static void xram_ctrl_register_types(void)
|
||||
{
|
||||
type_register_static(&xram_ctrl_info);
|
||||
}
|
||||
|
||||
type_init(xram_ctrl_register_types)
|
@ -339,35 +339,40 @@ static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState *s)
|
||||
qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0);
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
size_t min_size)
|
||||
static bool allwinner_sun8i_emac_desc_owned(FrameDescriptor *desc,
|
||||
size_t min_buf_size)
|
||||
{
|
||||
uint32_t paddr = desc->next;
|
||||
|
||||
dma_memory_read(&s->dma_as, paddr, desc, sizeof(*desc));
|
||||
|
||||
if ((desc->status & DESC_STATUS_CTL) &&
|
||||
(desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
|
||||
return paddr;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return (desc->status & DESC_STATUS_CTL) && (min_buf_size == 0 ||
|
||||
(desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_buf_size);
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
uint32_t start_addr,
|
||||
size_t min_size)
|
||||
static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
uint32_t phys_addr)
|
||||
{
|
||||
dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc));
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc)
|
||||
{
|
||||
const uint32_t nxt = desc->next;
|
||||
allwinner_sun8i_emac_get_desc(s, desc, nxt);
|
||||
return nxt;
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
uint32_t start_addr,
|
||||
size_t min_size)
|
||||
{
|
||||
uint32_t desc_addr = start_addr;
|
||||
|
||||
/* Note that the list is a cycle. Last entry points back to the head. */
|
||||
while (desc_addr != 0) {
|
||||
dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc));
|
||||
allwinner_sun8i_emac_get_desc(s, desc, desc_addr);
|
||||
|
||||
if ((desc->status & DESC_STATUS_CTL) &&
|
||||
(desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_size) {
|
||||
if (allwinner_sun8i_emac_desc_owned(desc, min_size)) {
|
||||
return desc_addr;
|
||||
} else if (desc->next == start_addr) {
|
||||
break;
|
||||
@ -383,14 +388,14 @@ static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
size_t min_size)
|
||||
{
|
||||
return allwinner_sun8i_emac_get_desc(s, desc, s->rx_desc_curr, min_size);
|
||||
return allwinner_sun8i_emac_find_desc(s, desc, s->rx_desc_curr, min_size);
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
size_t min_size)
|
||||
FrameDescriptor *desc)
|
||||
{
|
||||
return allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_head, min_size);
|
||||
allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_curr);
|
||||
return s->tx_desc_curr;
|
||||
}
|
||||
|
||||
static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
|
||||
@ -470,7 +475,8 @@ static ssize_t allwinner_sun8i_emac_receive(NetClientState *nc,
|
||||
bytes_left -= desc_bytes;
|
||||
|
||||
/* Move to the next descriptor */
|
||||
s->rx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc, 64);
|
||||
s->rx_desc_curr = allwinner_sun8i_emac_find_desc(s, &desc, desc.next,
|
||||
AW_SUN8I_EMAC_MIN_PKT_SZ);
|
||||
if (!s->rx_desc_curr) {
|
||||
/* Not enough buffer space available */
|
||||
s->int_sta |= INT_STA_RX_BUF_UA;
|
||||
@ -495,10 +501,10 @@ static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s)
|
||||
size_t transmitted = 0;
|
||||
static uint8_t packet_buf[2048];
|
||||
|
||||
s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc, 0);
|
||||
s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc);
|
||||
|
||||
/* Read all transmit descriptors */
|
||||
while (s->tx_desc_curr != 0) {
|
||||
while (allwinner_sun8i_emac_desc_owned(&desc, 0)) {
|
||||
|
||||
/* Read from physical memory into packet buffer */
|
||||
bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
|
||||
@ -524,7 +530,7 @@ static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s)
|
||||
packet_bytes = 0;
|
||||
transmitted++;
|
||||
}
|
||||
s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc, 0);
|
||||
s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc);
|
||||
}
|
||||
|
||||
/* Raise transmit completed interrupt */
|
||||
|
@ -415,6 +415,7 @@ static void sse_timer_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
if (!s->counter) {
|
||||
error_setg(errp, "counter property was not set");
|
||||
return;
|
||||
}
|
||||
|
||||
s->counter_notifier.notify = sse_timer_counter_callback;
|
||||
|
@ -155,6 +155,7 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start,
|
||||
hwaddr virt_end)
|
||||
{
|
||||
IOMMUTLBEvent event;
|
||||
uint64_t delta = virt_end - virt_start;
|
||||
|
||||
if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) {
|
||||
return;
|
||||
@ -164,12 +165,24 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start,
|
||||
|
||||
event.type = IOMMU_NOTIFIER_UNMAP;
|
||||
event.entry.target_as = &address_space_memory;
|
||||
event.entry.addr_mask = virt_end - virt_start;
|
||||
event.entry.iova = virt_start;
|
||||
event.entry.perm = IOMMU_NONE;
|
||||
event.entry.translated_addr = 0;
|
||||
event.entry.addr_mask = delta;
|
||||
event.entry.iova = virt_start;
|
||||
|
||||
memory_region_notify_iommu(mr, 0, event);
|
||||
if (delta == UINT64_MAX) {
|
||||
memory_region_notify_iommu(mr, 0, event);
|
||||
}
|
||||
|
||||
|
||||
while (virt_start != virt_end + 1) {
|
||||
uint64_t mask = dma_aligned_pow2_mask(virt_start, virt_end, 64);
|
||||
|
||||
event.entry.addr_mask = mask;
|
||||
event.entry.iova = virt_start;
|
||||
memory_region_notify_iommu(mr, 0, event);
|
||||
virt_start += mask + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean virtio_iommu_notify_unmap_cb(gpointer key, gpointer value,
|
||||
|
@ -18,12 +18,14 @@
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/adc/npcm7xx_adc.h"
|
||||
#include "hw/core/split-irq.h"
|
||||
#include "hw/cpu/a9mpcore.h"
|
||||
#include "hw/gpio/npcm7xx_gpio.h"
|
||||
#include "hw/i2c/npcm7xx_smbus.h"
|
||||
#include "hw/mem/npcm7xx_mc.h"
|
||||
#include "hw/misc/npcm7xx_clk.h"
|
||||
#include "hw/misc/npcm7xx_gcr.h"
|
||||
#include "hw/misc/npcm7xx_mft.h"
|
||||
#include "hw/misc/npcm7xx_pwm.h"
|
||||
#include "hw/misc/npcm7xx_rng.h"
|
||||
#include "hw/net/npcm7xx_emc.h"
|
||||
@ -47,8 +49,16 @@
|
||||
#define NPCM7XX_GIC_CPU_IF_ADDR (0xf03fe100) /* GIC within A9 */
|
||||
#define NPCM7XX_BOARD_SETUP_ADDR (0xffff1000) /* Boot ROM */
|
||||
|
||||
#define NPCM7XX_NR_PWM_MODULES 2
|
||||
|
||||
typedef struct NPCM7xxMachine {
|
||||
MachineState parent;
|
||||
/*
|
||||
* PWM fan splitter. each splitter connects to one PWM output and
|
||||
* multiple MFT inputs.
|
||||
*/
|
||||
SplitIRQ fan_splitter[NPCM7XX_NR_PWM_MODULES *
|
||||
NPCM7XX_PWM_PER_MODULE];
|
||||
} NPCM7xxMachine;
|
||||
|
||||
#define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx")
|
||||
@ -81,7 +91,8 @@ typedef struct NPCM7xxState {
|
||||
NPCM7xxCLKState clk;
|
||||
NPCM7xxTimerCtrlState tim[3];
|
||||
NPCM7xxADCState adc;
|
||||
NPCM7xxPWMState pwm[2];
|
||||
NPCM7xxPWMState pwm[NPCM7XX_NR_PWM_MODULES];
|
||||
NPCM7xxMFTState mft[8];
|
||||
NPCM7xxOTPState key_storage;
|
||||
NPCM7xxOTPState fuse_array;
|
||||
NPCM7xxMCState mc;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/or-irq.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
#include "hw/intc/arm_gicv3.h"
|
||||
#include "hw/char/pl011.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "hw/rtc/xlnx-zynqmp-rtc.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/usb/xlnx-usb-subsystem.h"
|
||||
#include "hw/misc/xlnx-versal-xramc.h"
|
||||
|
||||
#define TYPE_XLNX_VERSAL "xlnx-versal"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
|
||||
@ -31,6 +33,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
|
||||
#define XLNX_VERSAL_NR_GEMS 2
|
||||
#define XLNX_VERSAL_NR_ADMAS 8
|
||||
#define XLNX_VERSAL_NR_SDS 2
|
||||
#define XLNX_VERSAL_NR_XRAM 4
|
||||
#define XLNX_VERSAL_NR_IRQS 192
|
||||
|
||||
struct Versal {
|
||||
@ -62,6 +65,11 @@ struct Versal {
|
||||
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
|
||||
VersalUsb2 usb;
|
||||
} iou;
|
||||
|
||||
struct {
|
||||
qemu_or_irq irq_orgate;
|
||||
XlnxXramCtrl ctrl[XLNX_VERSAL_NR_XRAM];
|
||||
} xram;
|
||||
} lpd;
|
||||
|
||||
/* The Platform Management Controller subsystem. */
|
||||
@ -96,6 +104,7 @@ struct Versal {
|
||||
#define VERSAL_GEM1_IRQ_0 58
|
||||
#define VERSAL_GEM1_WAKE_IRQ_0 59
|
||||
#define VERSAL_ADMA_IRQ_0 60
|
||||
#define VERSAL_XRAM_IRQ_0 79
|
||||
#define VERSAL_RTC_APB_ERR_IRQ 121
|
||||
#define VERSAL_SD0_IRQ_0 126
|
||||
#define VERSAL_RTC_ALARM_IRQ 142
|
||||
@ -128,6 +137,10 @@ struct Versal {
|
||||
#define MM_OCM 0xfffc0000U
|
||||
#define MM_OCM_SIZE 0x40000
|
||||
|
||||
#define MM_XRAM 0xfe800000
|
||||
#define MM_XRAMC 0xff8e0000
|
||||
#define MM_XRAMC_SIZE 0x10000
|
||||
|
||||
#define MM_USB2_CTRL_REGS 0xFF9D0000
|
||||
#define MM_USB2_CTRL_REGS_SIZE 0x10000
|
||||
|
||||
|
@ -128,6 +128,7 @@ typedef struct {
|
||||
* @kvm_type:
|
||||
* Return the type of KVM corresponding to the kvm-type string option or
|
||||
* computed based on other criteria such as the host kernel capabilities.
|
||||
* kvm-type may be NULL if it is not needed.
|
||||
* @numa_mem_supported:
|
||||
* true if '--numa node.mem' option is supported and false otherwise
|
||||
* @smp_parse:
|
||||
|
70
include/hw/misc/npcm7xx_mft.h
Normal file
70
include/hw/misc/npcm7xx_mft.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx MFT Module
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
#ifndef NPCM7XX_MFT_H
|
||||
#define NPCM7XX_MFT_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/clock.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Max Fan input number. */
|
||||
#define NPCM7XX_MFT_MAX_FAN_INPUT 19
|
||||
|
||||
/*
|
||||
* Number of registers in one MFT module. Don't change this without increasing
|
||||
* the version_id in vmstate.
|
||||
*/
|
||||
#define NPCM7XX_MFT_NR_REGS (0x20 / sizeof(uint16_t))
|
||||
|
||||
/*
|
||||
* The MFT can take up to 4 inputs: A0, B0, A1, B1. It can measure one A and one
|
||||
* B simultaneously. NPCM7XX_MFT_INASEL and NPCM7XX_MFT_INBSEL are used to
|
||||
* select which A or B input are used.
|
||||
*/
|
||||
#define NPCM7XX_MFT_FANIN_COUNT 4
|
||||
|
||||
/**
|
||||
* struct NPCM7xxMFTState - Multi Functional Tachometer device state.
|
||||
* @parent: System bus device.
|
||||
* @iomem: Memory region through which registers are accessed.
|
||||
* @clock_in: The input clock for MFT from CLK module.
|
||||
* @clock_{1,2}: The counter clocks for NPCM7XX_MFT_CNT{1,2}
|
||||
* @irq: The IRQ for this MFT state.
|
||||
* @regs: The MMIO registers.
|
||||
* @max_rpm: The maximum rpm for fans. Order: A0, B0, A1, B1.
|
||||
* @duty: The duty cycles for fans, relative to NPCM7XX_PWM_MAX_DUTY.
|
||||
*/
|
||||
typedef struct NPCM7xxMFTState {
|
||||
SysBusDevice parent;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
Clock *clock_in;
|
||||
Clock *clock_1, *clock_2;
|
||||
qemu_irq irq;
|
||||
uint16_t regs[NPCM7XX_MFT_NR_REGS];
|
||||
|
||||
uint32_t max_rpm[NPCM7XX_MFT_FANIN_COUNT];
|
||||
uint32_t duty[NPCM7XX_MFT_FANIN_COUNT];
|
||||
} NPCM7xxMFTState;
|
||||
|
||||
#define TYPE_NPCM7XX_MFT "npcm7xx-mft"
|
||||
#define NPCM7XX_MFT(obj) \
|
||||
OBJECT_CHECK(NPCM7xxMFTState, (obj), TYPE_NPCM7XX_MFT)
|
||||
|
||||
#endif /* NPCM7XX_MFT_H */
|
@ -77,6 +77,7 @@ typedef struct NPCM7xxPWM {
|
||||
* @iomem: Memory region through which registers are accessed.
|
||||
* @clock: The PWM clock.
|
||||
* @pwm: The PWM channels owned by this module.
|
||||
* @duty_gpio_out: The duty cycle of each PWM channels as a output GPIO.
|
||||
* @ppr: The prescaler register.
|
||||
* @csr: The clock selector register.
|
||||
* @pcr: The control register.
|
||||
@ -89,7 +90,8 @@ struct NPCM7xxPWMState {
|
||||
MemoryRegion iomem;
|
||||
|
||||
Clock *clock;
|
||||
NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
|
||||
NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
|
||||
qemu_irq duty_gpio_out[NPCM7XX_PWM_PER_MODULE];
|
||||
|
||||
uint32_t ppr;
|
||||
uint32_t csr;
|
||||
|
97
include/hw/misc/xlnx-versal-xramc.h
Normal file
97
include/hw/misc/xlnx-versal-xramc.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* QEMU model of the Xilinx XRAM Controller.
|
||||
*
|
||||
* Copyright (c) 2021 Xilinx Inc.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
|
||||
*/
|
||||
|
||||
#ifndef XLNX_VERSAL_XRAMC_H
|
||||
#define XLNX_VERSAL_XRAMC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/register.h"
|
||||
|
||||
#define TYPE_XLNX_XRAM_CTRL "xlnx.versal-xramc"
|
||||
|
||||
#define XLNX_XRAM_CTRL(obj) \
|
||||
OBJECT_CHECK(XlnxXramCtrl, (obj), TYPE_XLNX_XRAM_CTRL)
|
||||
|
||||
REG32(XRAM_ERR_CTRL, 0x0)
|
||||
FIELD(XRAM_ERR_CTRL, UE_RES, 3, 1)
|
||||
FIELD(XRAM_ERR_CTRL, PWR_ERR_RES, 2, 1)
|
||||
FIELD(XRAM_ERR_CTRL, PZ_ERR_RES, 1, 1)
|
||||
FIELD(XRAM_ERR_CTRL, APB_ERR_RES, 0, 1)
|
||||
REG32(XRAM_ISR, 0x4)
|
||||
FIELD(XRAM_ISR, INV_APB, 0, 1)
|
||||
REG32(XRAM_IMR, 0x8)
|
||||
FIELD(XRAM_IMR, INV_APB, 0, 1)
|
||||
REG32(XRAM_IEN, 0xc)
|
||||
FIELD(XRAM_IEN, INV_APB, 0, 1)
|
||||
REG32(XRAM_IDS, 0x10)
|
||||
FIELD(XRAM_IDS, INV_APB, 0, 1)
|
||||
REG32(XRAM_ECC_CNTL, 0x14)
|
||||
FIELD(XRAM_ECC_CNTL, FI_MODE, 2, 1)
|
||||
FIELD(XRAM_ECC_CNTL, DET_ONLY, 1, 1)
|
||||
FIELD(XRAM_ECC_CNTL, ECC_ON_OFF, 0, 1)
|
||||
REG32(XRAM_CLR_EXE, 0x18)
|
||||
FIELD(XRAM_CLR_EXE, MON_7, 7, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_6, 6, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_5, 5, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_4, 4, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_3, 3, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_2, 2, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_1, 1, 1)
|
||||
FIELD(XRAM_CLR_EXE, MON_0, 0, 1)
|
||||
REG32(XRAM_CE_FFA, 0x1c)
|
||||
FIELD(XRAM_CE_FFA, ADDR, 0, 20)
|
||||
REG32(XRAM_CE_FFD0, 0x20)
|
||||
REG32(XRAM_CE_FFD1, 0x24)
|
||||
REG32(XRAM_CE_FFD2, 0x28)
|
||||
REG32(XRAM_CE_FFD3, 0x2c)
|
||||
REG32(XRAM_CE_FFE, 0x30)
|
||||
FIELD(XRAM_CE_FFE, SYNDROME, 0, 16)
|
||||
REG32(XRAM_UE_FFA, 0x34)
|
||||
FIELD(XRAM_UE_FFA, ADDR, 0, 20)
|
||||
REG32(XRAM_UE_FFD0, 0x38)
|
||||
REG32(XRAM_UE_FFD1, 0x3c)
|
||||
REG32(XRAM_UE_FFD2, 0x40)
|
||||
REG32(XRAM_UE_FFD3, 0x44)
|
||||
REG32(XRAM_UE_FFE, 0x48)
|
||||
FIELD(XRAM_UE_FFE, SYNDROME, 0, 16)
|
||||
REG32(XRAM_FI_D0, 0x4c)
|
||||
REG32(XRAM_FI_D1, 0x50)
|
||||
REG32(XRAM_FI_D2, 0x54)
|
||||
REG32(XRAM_FI_D3, 0x58)
|
||||
REG32(XRAM_FI_SY, 0x5c)
|
||||
FIELD(XRAM_FI_SY, DATA, 0, 16)
|
||||
REG32(XRAM_RMW_UE_FFA, 0x70)
|
||||
FIELD(XRAM_RMW_UE_FFA, ADDR, 0, 20)
|
||||
REG32(XRAM_FI_CNTR, 0x74)
|
||||
FIELD(XRAM_FI_CNTR, COUNT, 0, 24)
|
||||
REG32(XRAM_IMP, 0x80)
|
||||
FIELD(XRAM_IMP, SIZE, 0, 4)
|
||||
REG32(XRAM_PRDY_DBG, 0x84)
|
||||
FIELD(XRAM_PRDY_DBG, ISLAND3, 12, 4)
|
||||
FIELD(XRAM_PRDY_DBG, ISLAND2, 8, 4)
|
||||
FIELD(XRAM_PRDY_DBG, ISLAND1, 4, 4)
|
||||
FIELD(XRAM_PRDY_DBG, ISLAND0, 0, 4)
|
||||
REG32(XRAM_SAFETY_CHK, 0xff8)
|
||||
|
||||
#define XRAM_CTRL_R_MAX (R_XRAM_SAFETY_CHK + 1)
|
||||
|
||||
typedef struct XlnxXramCtrl {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion ram;
|
||||
qemu_irq irq;
|
||||
|
||||
struct {
|
||||
uint64_t size;
|
||||
unsigned int encoded_size;
|
||||
} cfg;
|
||||
|
||||
RegisterInfoArray *reg_array;
|
||||
uint32_t regs[XRAM_CTRL_R_MAX];
|
||||
RegisterInfo regs_info[XRAM_CTRL_R_MAX];
|
||||
} XlnxXramCtrl;
|
||||
#endif
|
@ -296,4 +296,16 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg);
|
||||
void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie,
|
||||
QEMUSGList *sg, enum BlockAcctType type);
|
||||
|
||||
/**
|
||||
* dma_aligned_pow2_mask: Return the address bit mask of the largest
|
||||
* power of 2 size less or equal than @end - @start + 1, aligned with @start,
|
||||
* and bounded by 1 << @max_addr_bits bits.
|
||||
*
|
||||
* @start: range start address
|
||||
* @end: range end address (greater than @start)
|
||||
* @max_addr_bits: max address bits (<= 64)
|
||||
*/
|
||||
uint64_t dma_aligned_pow2_mask(uint64_t start, uint64_t end,
|
||||
int max_addr_bits);
|
||||
|
||||
#endif
|
||||
|
@ -330,3 +330,29 @@ void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie,
|
||||
{
|
||||
block_acct_start(blk_get_stats(blk), cookie, sg->size, type);
|
||||
}
|
||||
|
||||
uint64_t dma_aligned_pow2_mask(uint64_t start, uint64_t end, int max_addr_bits)
|
||||
{
|
||||
uint64_t max_mask = UINT64_MAX, addr_mask = end - start;
|
||||
uint64_t alignment_mask, size_mask;
|
||||
|
||||
if (max_addr_bits != 64) {
|
||||
max_mask = (1ULL << max_addr_bits) - 1;
|
||||
}
|
||||
|
||||
alignment_mask = start ? (start & -start) - 1 : max_mask;
|
||||
alignment_mask = MIN(alignment_mask, max_mask);
|
||||
size_mask = MIN(addr_mask, max_mask);
|
||||
|
||||
if (alignment_mask <= size_mask) {
|
||||
/* Increase the alignment of start */
|
||||
return alignment_mask;
|
||||
} else {
|
||||
/* Find the largest page mask from size */
|
||||
if (addr_mask == UINT64_MAX) {
|
||||
return UINT64_MAX;
|
||||
}
|
||||
return (1ULL << (63 - clz64(addr_mask + 1))) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,12 +230,14 @@ bool kvm_arm_pmu_supported(void)
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3);
|
||||
}
|
||||
|
||||
int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
|
||||
int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
|
||||
{
|
||||
KVMState *s = KVM_STATE(ms->accelerator);
|
||||
int ret;
|
||||
|
||||
ret = kvm_check_extension(s, KVM_CAP_ARM_VM_IPA_SIZE);
|
||||
*fixed_ipa = ret <= 0;
|
||||
|
||||
return ret > 0 ? ret : 40;
|
||||
}
|
||||
|
||||
|
@ -311,10 +311,12 @@ bool kvm_arm_sve_supported(void);
|
||||
/**
|
||||
* kvm_arm_get_max_vm_ipa_size:
|
||||
* @ms: Machine state handle
|
||||
* @fixed_ipa: True when the IPA limit is fixed at 40. This is the case
|
||||
* for legacy KVM.
|
||||
*
|
||||
* Returns the number of bits in the IPA address space supported by KVM
|
||||
*/
|
||||
int kvm_arm_get_max_vm_ipa_size(MachineState *ms);
|
||||
int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa);
|
||||
|
||||
/**
|
||||
* kvm_arm_sync_mpstate_to_kvm:
|
||||
@ -409,7 +411,7 @@ static inline void kvm_arm_add_vcpu_properties(Object *obj)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
|
||||
static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -1871,6 +1871,7 @@ void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
|
||||
intptr_t high = FIELD_EX32(pred_desc, PREDDESC, DATA);
|
||||
int esize = 1 << esz;
|
||||
uint64_t *d = vd;
|
||||
intptr_t i;
|
||||
|
||||
@ -1883,33 +1884,35 @@ void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
mm = extract64(mm, high * half, half);
|
||||
nn = expand_bits(nn, esz);
|
||||
mm = expand_bits(mm, esz);
|
||||
d[0] = nn + (mm << (1 << esz));
|
||||
d[0] = nn | (mm << esize);
|
||||
} else {
|
||||
ARMPredicateReg tmp_n, tmp_m;
|
||||
ARMPredicateReg tmp;
|
||||
|
||||
/* We produce output faster than we consume input.
|
||||
Therefore we must be mindful of possible overlap. */
|
||||
if ((vn - vd) < (uintptr_t)oprsz) {
|
||||
vn = memcpy(&tmp_n, vn, oprsz);
|
||||
}
|
||||
if ((vm - vd) < (uintptr_t)oprsz) {
|
||||
vm = memcpy(&tmp_m, vm, oprsz);
|
||||
if (vd == vn) {
|
||||
vn = memcpy(&tmp, vn, oprsz);
|
||||
if (vd == vm) {
|
||||
vm = vn;
|
||||
}
|
||||
} else if (vd == vm) {
|
||||
vm = memcpy(&tmp, vm, oprsz);
|
||||
}
|
||||
if (high) {
|
||||
high = oprsz >> 1;
|
||||
}
|
||||
|
||||
if ((high & 3) == 0) {
|
||||
if ((oprsz & 7) == 0) {
|
||||
uint32_t *n = vn, *m = vm;
|
||||
high >>= 2;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(oprsz, 8); i++) {
|
||||
for (i = 0; i < oprsz / 8; i++) {
|
||||
uint64_t nn = n[H4(high + i)];
|
||||
uint64_t mm = m[H4(high + i)];
|
||||
|
||||
nn = expand_bits(nn, esz);
|
||||
mm = expand_bits(mm, esz);
|
||||
d[i] = nn + (mm << (1 << esz));
|
||||
d[i] = nn | (mm << esize);
|
||||
}
|
||||
} else {
|
||||
uint8_t *n = vn, *m = vm;
|
||||
@ -1921,7 +1924,7 @@ void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
|
||||
nn = expand_bits(nn, esz);
|
||||
mm = expand_bits(mm, esz);
|
||||
d16[H2(i)] = nn + (mm << (1 << esz));
|
||||
d16[H2(i)] = nn | (mm << esize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1939,7 +1942,7 @@ void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
if (oprsz <= 8) {
|
||||
l = compress_bits(n[0] >> odd, esz);
|
||||
h = compress_bits(m[0] >> odd, esz);
|
||||
d[0] = extract64(l + (h << (4 * oprsz)), 0, 8 * oprsz);
|
||||
d[0] = l | (h << (4 * oprsz));
|
||||
} else {
|
||||
ARMPredicateReg tmp_m;
|
||||
intptr_t oprsz_16 = oprsz / 16;
|
||||
@ -1953,23 +1956,35 @@ void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
h = n[2 * i + 1];
|
||||
l = compress_bits(l >> odd, esz);
|
||||
h = compress_bits(h >> odd, esz);
|
||||
d[i] = l + (h << 32);
|
||||
d[i] = l | (h << 32);
|
||||
}
|
||||
|
||||
/* For VL which is not a power of 2, the results from M do not
|
||||
align nicely with the uint64_t for D. Put the aligned results
|
||||
from M into TMP_M and then copy it into place afterward. */
|
||||
/*
|
||||
* For VL which is not a multiple of 512, the results from M do not
|
||||
* align nicely with the uint64_t for D. Put the aligned results
|
||||
* from M into TMP_M and then copy it into place afterward.
|
||||
*/
|
||||
if (oprsz & 15) {
|
||||
d[i] = compress_bits(n[2 * i] >> odd, esz);
|
||||
int final_shift = (oprsz & 15) * 2;
|
||||
|
||||
l = n[2 * i + 0];
|
||||
h = n[2 * i + 1];
|
||||
l = compress_bits(l >> odd, esz);
|
||||
h = compress_bits(h >> odd, esz);
|
||||
d[i] = l | (h << final_shift);
|
||||
|
||||
for (i = 0; i < oprsz_16; i++) {
|
||||
l = m[2 * i + 0];
|
||||
h = m[2 * i + 1];
|
||||
l = compress_bits(l >> odd, esz);
|
||||
h = compress_bits(h >> odd, esz);
|
||||
tmp_m.p[i] = l + (h << 32);
|
||||
tmp_m.p[i] = l | (h << 32);
|
||||
}
|
||||
tmp_m.p[i] = compress_bits(m[2 * i] >> odd, esz);
|
||||
l = m[2 * i + 0];
|
||||
h = m[2 * i + 1];
|
||||
l = compress_bits(l >> odd, esz);
|
||||
h = compress_bits(h >> odd, esz);
|
||||
tmp_m.p[i] = l | (h << final_shift);
|
||||
|
||||
swap_memmove(vd + oprsz / 2, &tmp_m, oprsz / 2);
|
||||
} else {
|
||||
@ -1978,7 +1993,7 @@ void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
|
||||
h = m[2 * i + 1];
|
||||
l = compress_bits(l >> odd, esz);
|
||||
h = compress_bits(h >> odd, esz);
|
||||
d[oprsz_16 + i] = l + (h << 32);
|
||||
d[oprsz_16 + i] = l | (h << 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2090,11 +2105,11 @@ void HELPER(sve_punpk_p)(void *vd, void *vn, uint32_t pred_desc)
|
||||
high = oprsz >> 1;
|
||||
}
|
||||
|
||||
if ((high & 3) == 0) {
|
||||
if ((oprsz & 7) == 0) {
|
||||
uint32_t *n = vn;
|
||||
high >>= 2;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(oprsz, 8); i++) {
|
||||
for (i = 0; i < oprsz / 8; i++) {
|
||||
uint64_t nn = n[H4(high + i)];
|
||||
d[i] = expand_bits(nn, 0);
|
||||
}
|
||||
@ -2222,10 +2237,10 @@ void HELPER(sve_compact_d)(void *vd, void *vn, void *vg, uint32_t desc)
|
||||
*/
|
||||
int32_t HELPER(sve_last_active_element)(void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
|
||||
intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
|
||||
intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
|
||||
|
||||
return last_active_element(vg, DIV_ROUND_UP(oprsz, 8), esz);
|
||||
return last_active_element(vg, words, esz);
|
||||
}
|
||||
|
||||
void HELPER(sve_splice)(void *vd, void *vn, void *vm, void *vg, uint32_t desc)
|
||||
@ -2695,7 +2710,7 @@ static uint32_t do_zero(ARMPredicateReg *d, intptr_t oprsz)
|
||||
void HELPER(sve_brkpa)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (last_active_pred(vn, vg, oprsz)) {
|
||||
compute_brk_z(vd, vm, vg, oprsz, true);
|
||||
} else {
|
||||
@ -2706,7 +2721,7 @@ void HELPER(sve_brkpa)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t HELPER(sve_brkpas)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (last_active_pred(vn, vg, oprsz)) {
|
||||
return compute_brks_z(vd, vm, vg, oprsz, true);
|
||||
} else {
|
||||
@ -2717,7 +2732,7 @@ uint32_t HELPER(sve_brkpas)(void *vd, void *vn, void *vm, void *vg,
|
||||
void HELPER(sve_brkpb)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (last_active_pred(vn, vg, oprsz)) {
|
||||
compute_brk_z(vd, vm, vg, oprsz, false);
|
||||
} else {
|
||||
@ -2728,7 +2743,7 @@ void HELPER(sve_brkpb)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t HELPER(sve_brkpbs)(void *vd, void *vn, void *vm, void *vg,
|
||||
uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (last_active_pred(vn, vg, oprsz)) {
|
||||
return compute_brks_z(vd, vm, vg, oprsz, false);
|
||||
} else {
|
||||
@ -2738,56 +2753,55 @@ uint32_t HELPER(sve_brkpbs)(void *vd, void *vn, void *vm, void *vg,
|
||||
|
||||
void HELPER(sve_brka_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
compute_brk_z(vd, vn, vg, oprsz, true);
|
||||
}
|
||||
|
||||
uint32_t HELPER(sve_brkas_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
return compute_brks_z(vd, vn, vg, oprsz, true);
|
||||
}
|
||||
|
||||
void HELPER(sve_brkb_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
compute_brk_z(vd, vn, vg, oprsz, false);
|
||||
}
|
||||
|
||||
uint32_t HELPER(sve_brkbs_z)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
return compute_brks_z(vd, vn, vg, oprsz, false);
|
||||
}
|
||||
|
||||
void HELPER(sve_brka_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
compute_brk_m(vd, vn, vg, oprsz, true);
|
||||
}
|
||||
|
||||
uint32_t HELPER(sve_brkas_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
return compute_brks_m(vd, vn, vg, oprsz, true);
|
||||
}
|
||||
|
||||
void HELPER(sve_brkb_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
compute_brk_m(vd, vn, vg, oprsz, false);
|
||||
}
|
||||
|
||||
uint32_t HELPER(sve_brkbs_m)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
return compute_brks_m(vd, vn, vg, oprsz, false);
|
||||
}
|
||||
|
||||
void HELPER(sve_brkn)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (!last_active_pred(vn, vg, oprsz)) {
|
||||
do_zero(vd, oprsz);
|
||||
}
|
||||
@ -2812,8 +2826,7 @@ static uint32_t predtest_ones(ARMPredicateReg *d, intptr_t oprsz,
|
||||
|
||||
uint32_t HELPER(sve_brkns)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
if (last_active_pred(vn, vg, oprsz)) {
|
||||
return predtest_ones(vd, oprsz, -1);
|
||||
} else {
|
||||
@ -2823,12 +2836,12 @@ uint32_t HELPER(sve_brkns)(void *vd, void *vn, void *vg, uint32_t pred_desc)
|
||||
|
||||
uint64_t HELPER(sve_cntp)(void *vn, void *vg, uint32_t pred_desc)
|
||||
{
|
||||
intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
|
||||
intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
|
||||
intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
|
||||
uint64_t *n = vn, *g = vg, sum = 0, mask = pred_esz_masks[esz];
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(oprsz, 8); ++i) {
|
||||
for (i = 0; i < words; ++i) {
|
||||
uint64_t t = n[i] & g[i] & mask;
|
||||
sum += ctpop64(t);
|
||||
}
|
||||
@ -2837,8 +2850,8 @@ uint64_t HELPER(sve_cntp)(void *vn, void *vg, uint32_t pred_desc)
|
||||
|
||||
uint32_t HELPER(sve_while)(void *vd, uint32_t count, uint32_t pred_desc)
|
||||
{
|
||||
uintptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
|
||||
intptr_t esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
|
||||
intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
|
||||
intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
|
||||
uint64_t esz_mask = pred_esz_masks[esz];
|
||||
ARMPredicateReg *d = vd;
|
||||
uint32_t flags;
|
||||
@ -2883,7 +2896,7 @@ static TYPE NAME##_reduce(TYPE *data, float_status *status, uintptr_t n) \
|
||||
} \
|
||||
uint64_t HELPER(NAME)(void *vn, void *vg, void *vs, uint32_t desc) \
|
||||
{ \
|
||||
uintptr_t i, oprsz = simd_oprsz(desc), maxsz = simd_maxsz(desc); \
|
||||
uintptr_t i, oprsz = simd_oprsz(desc), maxsz = simd_data(desc); \
|
||||
TYPE data[sizeof(ARMVectorReg) / sizeof(TYPE)]; \
|
||||
for (i = 0; i < oprsz; ) { \
|
||||
uint16_t pg = *(uint16_t *)(vg + H1_2(i >> 3)); \
|
||||
|
@ -2302,11 +2302,10 @@ static void find_last_active(DisasContext *s, TCGv_i32 ret, int esz, int pg)
|
||||
*/
|
||||
TCGv_ptr t_p = tcg_temp_new_ptr();
|
||||
TCGv_i32 t_desc;
|
||||
unsigned vsz = pred_full_reg_size(s);
|
||||
unsigned desc;
|
||||
unsigned desc = 0;
|
||||
|
||||
desc = vsz - 2;
|
||||
desc = deposit32(desc, SIMD_DATA_SHIFT, 2, esz);
|
||||
desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s));
|
||||
desc = FIELD_DP32(desc, PREDDESC, ESZ, esz);
|
||||
|
||||
tcg_gen_addi_ptr(t_p, cpu_env, pred_full_reg_offset(s, pg));
|
||||
t_desc = tcg_const_i32(desc);
|
||||
@ -2851,7 +2850,7 @@ static bool do_brk3(DisasContext *s, arg_rprr_s *a,
|
||||
TCGv_ptr n = tcg_temp_new_ptr();
|
||||
TCGv_ptr m = tcg_temp_new_ptr();
|
||||
TCGv_ptr g = tcg_temp_new_ptr();
|
||||
TCGv_i32 t = tcg_const_i32(vsz - 2);
|
||||
TCGv_i32 t = tcg_const_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz));
|
||||
|
||||
tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd));
|
||||
tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn));
|
||||
@ -2885,7 +2884,7 @@ static bool do_brk2(DisasContext *s, arg_rpr_s *a,
|
||||
TCGv_ptr d = tcg_temp_new_ptr();
|
||||
TCGv_ptr n = tcg_temp_new_ptr();
|
||||
TCGv_ptr g = tcg_temp_new_ptr();
|
||||
TCGv_i32 t = tcg_const_i32(vsz - 2);
|
||||
TCGv_i32 t = tcg_const_i32(FIELD_DP32(0, PREDDESC, OPRSZ, vsz));
|
||||
|
||||
tcg_gen_addi_ptr(d, cpu_env, pred_full_reg_offset(s, a->rd));
|
||||
tcg_gen_addi_ptr(n, cpu_env, pred_full_reg_offset(s, a->rn));
|
||||
@ -2968,11 +2967,11 @@ static void do_cntp(DisasContext *s, TCGv_i64 val, int esz, int pn, int pg)
|
||||
} else {
|
||||
TCGv_ptr t_pn = tcg_temp_new_ptr();
|
||||
TCGv_ptr t_pg = tcg_temp_new_ptr();
|
||||
unsigned desc;
|
||||
unsigned desc = 0;
|
||||
TCGv_i32 t_desc;
|
||||
|
||||
desc = psz - 2;
|
||||
desc = deposit32(desc, SIMD_DATA_SHIFT, 2, esz);
|
||||
desc = FIELD_DP32(desc, PREDDESC, OPRSZ, psz);
|
||||
desc = FIELD_DP32(desc, PREDDESC, ESZ, esz);
|
||||
|
||||
tcg_gen_addi_ptr(t_pn, cpu_env, pred_full_reg_offset(s, pn));
|
||||
tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, pg));
|
||||
@ -3098,7 +3097,8 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a)
|
||||
TCGv_i64 op0, op1, t0, t1, tmax;
|
||||
TCGv_i32 t2, t3;
|
||||
TCGv_ptr ptr;
|
||||
unsigned desc, vsz = vec_full_reg_size(s);
|
||||
unsigned vsz = vec_full_reg_size(s);
|
||||
unsigned desc = 0;
|
||||
TCGCond cond;
|
||||
|
||||
if (!sve_access_check(s)) {
|
||||
@ -3162,8 +3162,8 @@ static bool trans_WHILE(DisasContext *s, arg_WHILE *a)
|
||||
/* Scale elements to bits. */
|
||||
tcg_gen_shli_i32(t2, t2, a->esz);
|
||||
|
||||
desc = (vsz / 8) - 2;
|
||||
desc = deposit32(desc, SIMD_DATA_SHIFT, 2, a->esz);
|
||||
desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz / 8);
|
||||
desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz);
|
||||
t3 = tcg_const_i32(desc);
|
||||
|
||||
ptr = tcg_temp_new_ptr();
|
||||
@ -3440,7 +3440,7 @@ static void do_reduce(DisasContext *s, arg_rpr_esz *a,
|
||||
{
|
||||
unsigned vsz = vec_full_reg_size(s);
|
||||
unsigned p2vsz = pow2ceil(vsz);
|
||||
TCGv_i32 t_desc = tcg_const_i32(simd_desc(vsz, p2vsz, 0));
|
||||
TCGv_i32 t_desc = tcg_const_i32(simd_desc(vsz, vsz, p2vsz));
|
||||
TCGv_ptr t_zn, t_pg, status;
|
||||
TCGv_i64 temp;
|
||||
|
||||
|
@ -507,20 +507,18 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
self.wait_for_console_pattern('Boot successful.')
|
||||
# TODO user command, for now the uart is stuck
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_cubieboard_initrd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:cubieboard
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
|
||||
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
|
||||
@ -549,20 +547,18 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
'system-control@1c00000')
|
||||
# cubieboard's reboot is not functioning; omit reboot test.
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_cubieboard_sata(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:cubieboard
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
rootfs_url = ('https://github.com/groeck/linux-build-test/raw/'
|
||||
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
|
||||
@ -678,20 +674,18 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
self.wait_for_console_pattern(
|
||||
'Give root password for system maintenance')
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_orangepi(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:orangepi-pc
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
|
||||
self.vm.set_console()
|
||||
@ -705,20 +699,18 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
console_pattern = 'Kernel command line: %s' % kernel_command_line
|
||||
self.wait_for_console_pattern(console_pattern)
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_orangepi_initrd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:orangepi-pc
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
|
||||
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
|
||||
@ -749,8 +741,6 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
# Wait for VM to shut down gracefully
|
||||
self.vm.wait()
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_orangepi_sd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
@ -758,12 +748,12 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
:avocado: tags=device:sd
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun8i-h3-orangepi-pc.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/'
|
||||
'kci-2019.02/armel/base/rootfs.ext2.xz')
|
||||
@ -802,7 +792,27 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
# Wait for VM to shut down gracefully
|
||||
self.vm.wait()
|
||||
|
||||
def do_test_arm_orangepi_uboot_armbian(self, image_path):
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
|
||||
def test_arm_orangepi_bionic_20_08(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:orangepi-pc
|
||||
:avocado: tags=device:sd
|
||||
"""
|
||||
|
||||
# This test download a 275 MiB compressed image and expand it
|
||||
# to 1036 MiB, but the underlying filesystem is 1552 MiB...
|
||||
# As we expand it to 2 GiB we are safe.
|
||||
|
||||
image_url = ('https://archive.armbian.com/orangepipc/archive/'
|
||||
'Armbian_20.08.1_Orangepipc_bionic_current_5.8.5.img.xz')
|
||||
image_hash = ('b4d6775f5673486329e45a0586bf06b6'
|
||||
'dbe792199fd182ac6b9c7bb6c7d3e6dd')
|
||||
image_path_xz = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
image_path = archive.extract(image_path_xz, self.workdir)
|
||||
image_pow2ceil_expand(image_path)
|
||||
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
|
||||
'-nic', 'user',
|
||||
@ -828,54 +838,6 @@ class BootLinuxConsole(LinuxKernelTest):
|
||||
'to <orangepipc>')
|
||||
self.wait_for_console_pattern('Starting Load Kernel Modules...')
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
|
||||
@skipUnless(P7ZIP_AVAILABLE, '7z not installed')
|
||||
def test_arm_orangepi_bionic_19_11(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:orangepi-pc
|
||||
:avocado: tags=device:sd
|
||||
"""
|
||||
|
||||
# This test download a 196MB compressed image and expand it to 1GB
|
||||
image_url = ('https://dl.armbian.com/orangepipc/archive/'
|
||||
'Armbian_19.11.3_Orangepipc_bionic_current_5.3.9.7z')
|
||||
image_hash = '196a8ffb72b0123d92cea4a070894813d305c71e'
|
||||
image_path_7z = self.fetch_asset(image_url, asset_hash=image_hash)
|
||||
image_name = 'Armbian_19.11.3_Orangepipc_bionic_current_5.3.9.img'
|
||||
image_path = os.path.join(self.workdir, image_name)
|
||||
process.run("7z e -o%s %s" % (self.workdir, image_path_7z))
|
||||
image_pow2ceil_expand(image_path)
|
||||
|
||||
self.do_test_arm_orangepi_uboot_armbian(image_path)
|
||||
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
|
||||
def test_arm_orangepi_bionic_20_08(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:orangepi-pc
|
||||
:avocado: tags=device:sd
|
||||
"""
|
||||
|
||||
# This test download a 275 MiB compressed image and expand it
|
||||
# to 1036 MiB, but the underlying filesystem is 1552 MiB...
|
||||
# As we expand it to 2 GiB we are safe.
|
||||
|
||||
image_url = ('https://dl.armbian.com/orangepipc/archive/'
|
||||
'Armbian_20.08.1_Orangepipc_bionic_current_5.8.5.img.xz')
|
||||
image_hash = ('b4d6775f5673486329e45a0586bf06b6'
|
||||
'dbe792199fd182ac6b9c7bb6c7d3e6dd')
|
||||
image_path_xz = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
image_path = archive.extract(image_path_xz, self.workdir)
|
||||
image_pow2ceil_expand(image_path)
|
||||
|
||||
self.do_test_arm_orangepi_uboot_armbian(image_path)
|
||||
|
||||
@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
|
||||
def test_arm_orangepi_uboot_netbsd9(self):
|
||||
"""
|
||||
|
@ -177,20 +177,18 @@ class ReplayKernelNormal(ReplayKernelBase):
|
||||
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=1)
|
||||
|
||||
@skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
|
||||
@skipUnless(os.getenv('ARMBIAN_ARTIFACTS_CACHED'),
|
||||
'Test artifacts fetched from unreliable apt.armbian.com')
|
||||
def test_arm_cubieboard_initrd(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:cubieboard
|
||||
"""
|
||||
deb_url = ('https://apt.armbian.com/pool/main/l/'
|
||||
'linux-4.20.7-sunxi/linux-image-dev-sunxi_5.75_armhf.deb')
|
||||
deb_hash = '1334c29c44d984ffa05ed10de8c3361f33d78315'
|
||||
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
|
||||
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
|
||||
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
|
||||
kernel_path = self.extract_from_deb(deb_path,
|
||||
'/boot/vmlinuz-4.20.7-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-dev-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
'/boot/vmlinuz-5.10.16-sunxi')
|
||||
dtb_path = '/usr/lib/linux-image-current-sunxi/sun4i-a10-cubieboard.dtb'
|
||||
dtb_path = self.extract_from_deb(deb_path, dtb_path)
|
||||
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
|
||||
'2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
|
||||
|
@ -45,6 +45,7 @@
|
||||
#define PLL_FBDV(rv) extract32((rv), 16, 12)
|
||||
#define PLL_OTDV1(rv) extract32((rv), 8, 3)
|
||||
#define PLL_OTDV2(rv) extract32((rv), 13, 3)
|
||||
#define APB4CKDIV(rv) extract32((rv), 30, 2)
|
||||
#define APB3CKDIV(rv) extract32((rv), 28, 2)
|
||||
#define CLK2CKDIV(rv) extract32((rv), 0, 1)
|
||||
#define CLK4CKDIV(rv) extract32((rv), 26, 2)
|
||||
@ -52,6 +53,49 @@
|
||||
|
||||
#define MAX_DUTY 1000000
|
||||
|
||||
/* MFT (PWM fan) related */
|
||||
#define MFT_BA(n) (0xf0180000 + ((n) * 0x1000))
|
||||
#define MFT_IRQ(n) (96 + (n))
|
||||
#define MFT_CNT1 0x00
|
||||
#define MFT_CRA 0x02
|
||||
#define MFT_CRB 0x04
|
||||
#define MFT_CNT2 0x06
|
||||
#define MFT_PRSC 0x08
|
||||
#define MFT_CKC 0x0a
|
||||
#define MFT_MCTRL 0x0c
|
||||
#define MFT_ICTRL 0x0e
|
||||
#define MFT_ICLR 0x10
|
||||
#define MFT_IEN 0x12
|
||||
#define MFT_CPA 0x14
|
||||
#define MFT_CPB 0x16
|
||||
#define MFT_CPCFG 0x18
|
||||
#define MFT_INASEL 0x1a
|
||||
#define MFT_INBSEL 0x1c
|
||||
|
||||
#define MFT_MCTRL_ALL 0x64
|
||||
#define MFT_ICLR_ALL 0x3f
|
||||
#define MFT_IEN_ALL 0x3f
|
||||
#define MFT_CPCFG_EQ_MODE 0x44
|
||||
|
||||
#define MFT_CKC_C2CSEL BIT(3)
|
||||
#define MFT_CKC_C1CSEL BIT(0)
|
||||
|
||||
#define MFT_ICTRL_TFPND BIT(5)
|
||||
#define MFT_ICTRL_TEPND BIT(4)
|
||||
#define MFT_ICTRL_TDPND BIT(3)
|
||||
#define MFT_ICTRL_TCPND BIT(2)
|
||||
#define MFT_ICTRL_TBPND BIT(1)
|
||||
#define MFT_ICTRL_TAPND BIT(0)
|
||||
|
||||
#define MFT_MAX_CNT 0xffff
|
||||
#define MFT_TIMEOUT 0x5000
|
||||
|
||||
#define DEFAULT_RPM 19800
|
||||
#define DEFAULT_PRSC 255
|
||||
#define MFT_PULSE_PER_REVOLUTION 2
|
||||
|
||||
#define MAX_ERROR 1
|
||||
|
||||
typedef struct PWMModule {
|
||||
int irq;
|
||||
uint64_t base_addr;
|
||||
@ -210,19 +254,36 @@ static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
|
||||
return pwm_qom_get(qts, path, name);
|
||||
}
|
||||
|
||||
static void mft_qom_set(QTestState *qts, int index, const char *name,
|
||||
uint32_t value)
|
||||
{
|
||||
QDict *response;
|
||||
char *path = g_strdup_printf("/machine/soc/mft[%d]", index);
|
||||
|
||||
g_test_message("Setting properties %s of mft[%d] with value %u",
|
||||
name, index, value);
|
||||
response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
|
||||
" 'arguments': { 'path': %s, "
|
||||
" 'property': %s, 'value': %u}}",
|
||||
path, name, value);
|
||||
/* The qom set message returns successfully. */
|
||||
g_assert_true(qdict_haskey(response, "return"));
|
||||
}
|
||||
|
||||
static uint32_t get_pll(uint32_t con)
|
||||
{
|
||||
return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
|
||||
* PLL_OTDV2(con));
|
||||
}
|
||||
|
||||
static uint64_t read_pclk(QTestState *qts)
|
||||
static uint64_t read_pclk(QTestState *qts, bool mft)
|
||||
{
|
||||
uint64_t freq = REF_HZ;
|
||||
uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
|
||||
uint32_t pllcon;
|
||||
uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
|
||||
uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
|
||||
uint32_t apbdiv = mft ? APB4CKDIV(clkdiv2) : APB3CKDIV(clkdiv2);
|
||||
|
||||
switch (CPUCKSEL(clksel)) {
|
||||
case 0:
|
||||
@ -241,7 +302,7 @@ static uint64_t read_pclk(QTestState *qts)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
|
||||
freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + apbdiv);
|
||||
|
||||
return freq;
|
||||
}
|
||||
@ -267,7 +328,7 @@ static uint32_t pwm_selector(uint32_t csr)
|
||||
static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
|
||||
uint32_t cnr)
|
||||
{
|
||||
return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
|
||||
return read_pclk(qts, false) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
|
||||
}
|
||||
|
||||
static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
|
||||
@ -301,6 +362,28 @@ static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
|
||||
qtest_writel(qts, td->module->base_addr + offset, value);
|
||||
}
|
||||
|
||||
static uint8_t mft_readb(QTestState *qts, int index, unsigned offset)
|
||||
{
|
||||
return qtest_readb(qts, MFT_BA(index) + offset);
|
||||
}
|
||||
|
||||
static uint16_t mft_readw(QTestState *qts, int index, unsigned offset)
|
||||
{
|
||||
return qtest_readw(qts, MFT_BA(index) + offset);
|
||||
}
|
||||
|
||||
static void mft_writeb(QTestState *qts, int index, unsigned offset,
|
||||
uint8_t value)
|
||||
{
|
||||
qtest_writeb(qts, MFT_BA(index) + offset, value);
|
||||
}
|
||||
|
||||
static void mft_writew(QTestState *qts, int index, unsigned offset,
|
||||
uint16_t value)
|
||||
{
|
||||
return qtest_writew(qts, MFT_BA(index) + offset, value);
|
||||
}
|
||||
|
||||
static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
|
||||
{
|
||||
return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
|
||||
@ -351,11 +434,116 @@ static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
|
||||
pwm_write(qts, td, td->pwm->cmr_offset, value);
|
||||
}
|
||||
|
||||
static int mft_compute_index(const TestData *td)
|
||||
{
|
||||
int index = pwm_module_index(td->module) * ARRAY_SIZE(pwm_list) +
|
||||
pwm_index(td->pwm);
|
||||
|
||||
g_assert_cmpint(index, <,
|
||||
ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static void mft_reset_counters(QTestState *qts, int index)
|
||||
{
|
||||
mft_writew(qts, index, MFT_CNT1, MFT_MAX_CNT);
|
||||
mft_writew(qts, index, MFT_CNT2, MFT_MAX_CNT);
|
||||
mft_writew(qts, index, MFT_CRA, MFT_MAX_CNT);
|
||||
mft_writew(qts, index, MFT_CRB, MFT_MAX_CNT);
|
||||
mft_writew(qts, index, MFT_CPA, MFT_MAX_CNT - MFT_TIMEOUT);
|
||||
mft_writew(qts, index, MFT_CPB, MFT_MAX_CNT - MFT_TIMEOUT);
|
||||
}
|
||||
|
||||
static void mft_init(QTestState *qts, const TestData *td)
|
||||
{
|
||||
int index = mft_compute_index(td);
|
||||
|
||||
/* Enable everything */
|
||||
mft_writeb(qts, index, MFT_CKC, 0);
|
||||
mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
|
||||
mft_writeb(qts, index, MFT_MCTRL, MFT_MCTRL_ALL);
|
||||
mft_writeb(qts, index, MFT_IEN, MFT_IEN_ALL);
|
||||
mft_writeb(qts, index, MFT_INASEL, 0);
|
||||
mft_writeb(qts, index, MFT_INBSEL, 0);
|
||||
|
||||
/* Set cpcfg to use EQ mode, same as kernel driver */
|
||||
mft_writeb(qts, index, MFT_CPCFG, MFT_CPCFG_EQ_MODE);
|
||||
|
||||
/* Write default counters, timeout and prescaler */
|
||||
mft_reset_counters(qts, index);
|
||||
mft_writeb(qts, index, MFT_PRSC, DEFAULT_PRSC);
|
||||
|
||||
/* Write default max rpm via QMP */
|
||||
mft_qom_set(qts, index, "max_rpm[0]", DEFAULT_RPM);
|
||||
mft_qom_set(qts, index, "max_rpm[1]", DEFAULT_RPM);
|
||||
}
|
||||
|
||||
static int32_t mft_compute_cnt(uint32_t rpm, uint64_t clk)
|
||||
{
|
||||
uint64_t cnt;
|
||||
|
||||
if (rpm == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cnt = clk * 60 / ((DEFAULT_PRSC + 1) * rpm * MFT_PULSE_PER_REVOLUTION);
|
||||
if (cnt >= MFT_TIMEOUT) {
|
||||
return -1;
|
||||
}
|
||||
return MFT_MAX_CNT - cnt;
|
||||
}
|
||||
|
||||
static void mft_verify_rpm(QTestState *qts, const TestData *td, uint64_t duty)
|
||||
{
|
||||
int index = mft_compute_index(td);
|
||||
uint16_t cnt, cr;
|
||||
uint32_t rpm = DEFAULT_RPM * duty / MAX_DUTY;
|
||||
uint64_t clk = read_pclk(qts, true);
|
||||
int32_t expected_cnt = mft_compute_cnt(rpm, clk);
|
||||
|
||||
qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
|
||||
g_test_message(
|
||||
"verifying rpm for mft[%d]: clk: %" PRIu64 ", duty: %" PRIu64 ", rpm: %u, cnt: %d",
|
||||
index, clk, duty, rpm, expected_cnt);
|
||||
|
||||
/* Verify rpm for fan A */
|
||||
/* Stop capture */
|
||||
mft_writeb(qts, index, MFT_CKC, 0);
|
||||
mft_writeb(qts, index, MFT_ICLR, MFT_ICLR_ALL);
|
||||
mft_reset_counters(qts, index);
|
||||
g_assert_cmphex(mft_readw(qts, index, MFT_CNT1), ==, MFT_MAX_CNT);
|
||||
g_assert_cmphex(mft_readw(qts, index, MFT_CRA), ==, MFT_MAX_CNT);
|
||||
g_assert_cmphex(mft_readw(qts, index, MFT_CPA), ==,
|
||||
MFT_MAX_CNT - MFT_TIMEOUT);
|
||||
/* Start capture */
|
||||
mft_writeb(qts, index, MFT_CKC, MFT_CKC_C1CSEL);
|
||||
g_assert_true(qtest_get_irq(qts, MFT_IRQ(index)));
|
||||
if (expected_cnt == -1) {
|
||||
g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TEPND);
|
||||
} else {
|
||||
g_assert_cmphex(mft_readb(qts, index, MFT_ICTRL), ==, MFT_ICTRL_TAPND);
|
||||
cnt = mft_readw(qts, index, MFT_CNT1);
|
||||
/*
|
||||
* Due to error in clock measurement and rounding, we might have a small
|
||||
* error in measuring RPM.
|
||||
*/
|
||||
g_assert_cmphex(cnt + MAX_ERROR, >=, expected_cnt);
|
||||
g_assert_cmphex(cnt, <=, expected_cnt + MAX_ERROR);
|
||||
cr = mft_readw(qts, index, MFT_CRA);
|
||||
g_assert_cmphex(cnt, ==, cr);
|
||||
}
|
||||
|
||||
/* Verify rpm for fan B */
|
||||
|
||||
qtest_irq_intercept_out(qts, "/machine/soc/a9mpcore/gic");
|
||||
}
|
||||
|
||||
/* Check pwm registers can be reset to default value */
|
||||
static void test_init(gconstpointer test_data)
|
||||
{
|
||||
const TestData *td = test_data;
|
||||
QTestState *qts = qtest_init("-machine quanta-gsj");
|
||||
QTestState *qts = qtest_init("-machine npcm750-evb");
|
||||
int module = pwm_module_index(td->module);
|
||||
int pwm = pwm_index(td->pwm);
|
||||
|
||||
@ -369,7 +557,7 @@ static void test_init(gconstpointer test_data)
|
||||
static void test_oneshot(gconstpointer test_data)
|
||||
{
|
||||
const TestData *td = test_data;
|
||||
QTestState *qts = qtest_init("-machine quanta-gsj");
|
||||
QTestState *qts = qtest_init("-machine npcm750-evb");
|
||||
int module = pwm_module_index(td->module);
|
||||
int pwm = pwm_index(td->pwm);
|
||||
uint32_t ppr, csr, pcr;
|
||||
@ -400,13 +588,15 @@ static void test_oneshot(gconstpointer test_data)
|
||||
static void test_toggle(gconstpointer test_data)
|
||||
{
|
||||
const TestData *td = test_data;
|
||||
QTestState *qts = qtest_init("-machine quanta-gsj");
|
||||
QTestState *qts = qtest_init("-machine npcm750-evb");
|
||||
int module = pwm_module_index(td->module);
|
||||
int pwm = pwm_index(td->pwm);
|
||||
uint32_t ppr, csr, pcr, cnr, cmr;
|
||||
int i, j, k, l;
|
||||
uint64_t expected_freq, expected_duty;
|
||||
|
||||
mft_init(qts, td);
|
||||
|
||||
pcr = CH_EN | CH_MOD;
|
||||
for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
|
||||
ppr = ppr_list[i];
|
||||
@ -440,6 +630,9 @@ static void test_toggle(gconstpointer test_data)
|
||||
==, expected_freq);
|
||||
}
|
||||
|
||||
/* Test MFT's RPM is correct. */
|
||||
mft_verify_rpm(qts, td, expected_duty);
|
||||
|
||||
/* Test inverted mode */
|
||||
expected_duty = pwm_compute_duty(cnr, cmr, true);
|
||||
pwm_write_pcr(qts, td, pcr | CH_INV);
|
||||
|
Loading…
x
Reference in New Issue
Block a user