mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-08 10:13:56 -06:00
target-arm queue:
* hw/core/clock: allow clock_propagate on child clocks * hvf: arm: Remove unused PL1_WRITE_MASK define * target/arm: Restrict translation disabled alignment check to VMSA * docs/system/arm/emulation.rst: Add missing implemented features * target/arm: Enable FEAT_CSV2_3, FEAT_ETS2, FEAT_Spec_FPACC for 'max' * tests/avocado: update sunxi kernel from armbian to 6.6.16 * target/arm: Make new CPUs default to 1GHz generic timer * hw/dmax/xlnx_dpdma: fix handling of address_extension descriptor fields * hw/char/stm32l4x5_usart: Fix memory corruption by adding correct class_size * hw/arm/npcm7xx: Store derivative OTP fuse key in little endian * hw/arm: Add DM163 display to B-L475E-IOT01A board -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmYxILcZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3pRzD/40UZrhNbS+FEANkXJ7qpUm giCKn8hVwteWY4T4LugUK9987lU0HZ7CGfsHoSaWNwa7RBdKUoDRqi/CQ1kCfeDO XET42do+6SJhak+4wmzEfYD+K7wnlauun0/dyqCjd2+JP0bln/MIY5r8JCN1GiYS YSAAKoZqAfG1bC3HmxELI9min09GPT+tzw0PAyVJipRtfE+ykZXoCytu0GWU5jB+ VBI6SGmqMPd/c/7JfJV8KP8R0Mn3etA3hbOCx7YDL6cUmbepWtNPV8dLeTwofrpa 01uqN83PpbbSYr96QdXXa7Ov105hQH7e8jmr9+7jTpd3f9U7+GwsxxqDR1KDHLgn pUGZneoTDTkJugfXM28A0VoVB3eyJYPCLE9QQ/HXpChXc62NOQV5jcECgLiUDujH hVbeGEG0KViQlhMUfI3vIfTaIjEALDcNw5bxVUCqg8vdO6UtTXqqWdaS4Xgne8HB KeCu5xXngXEZjIgidZkmIC15FD60B19JdQz2WR+6BDCw8Ajm9iPWlj+ftZztuX/S cFSUZ05BPbTkBzAHG4GBvjXTdwsxX2acGBNtdETOQAxhkoRcug0Pn+BmrZQLqkm5 mPKPW9FFxIkkgeK/ZdA4uIEwDZX/LQlnrX129XGt7DVr+yDNKekaVGfLL8x8alT1 3v0Ni/nntc6QtZDB88OIzA== =vAf/ -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20240430' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * hw/core/clock: allow clock_propagate on child clocks * hvf: arm: Remove unused PL1_WRITE_MASK define * target/arm: Restrict translation disabled alignment check to VMSA * docs/system/arm/emulation.rst: Add missing implemented features * target/arm: Enable FEAT_CSV2_3, FEAT_ETS2, FEAT_Spec_FPACC for 'max' * tests/avocado: update sunxi kernel from armbian to 6.6.16 * target/arm: Make new CPUs default to 1GHz generic timer * hw/dmax/xlnx_dpdma: fix handling of address_extension descriptor fields * hw/char/stm32l4x5_usart: Fix memory corruption by adding correct class_size * hw/arm/npcm7xx: Store derivative OTP fuse key in little endian * hw/arm: Add DM163 display to B-L475E-IOT01A board # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmYxILcZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3pRzD/40UZrhNbS+FEANkXJ7qpUm # giCKn8hVwteWY4T4LugUK9987lU0HZ7CGfsHoSaWNwa7RBdKUoDRqi/CQ1kCfeDO # XET42do+6SJhak+4wmzEfYD+K7wnlauun0/dyqCjd2+JP0bln/MIY5r8JCN1GiYS # YSAAKoZqAfG1bC3HmxELI9min09GPT+tzw0PAyVJipRtfE+ykZXoCytu0GWU5jB+ # VBI6SGmqMPd/c/7JfJV8KP8R0Mn3etA3hbOCx7YDL6cUmbepWtNPV8dLeTwofrpa # 01uqN83PpbbSYr96QdXXa7Ov105hQH7e8jmr9+7jTpd3f9U7+GwsxxqDR1KDHLgn # pUGZneoTDTkJugfXM28A0VoVB3eyJYPCLE9QQ/HXpChXc62NOQV5jcECgLiUDujH # hVbeGEG0KViQlhMUfI3vIfTaIjEALDcNw5bxVUCqg8vdO6UtTXqqWdaS4Xgne8HB # KeCu5xXngXEZjIgidZkmIC15FD60B19JdQz2WR+6BDCw8Ajm9iPWlj+ftZztuX/S # cFSUZ05BPbTkBzAHG4GBvjXTdwsxX2acGBNtdETOQAxhkoRcug0Pn+BmrZQLqkm5 # mPKPW9FFxIkkgeK/ZdA4uIEwDZX/LQlnrX129XGt7DVr+yDNKekaVGfLL8x8alT1 # 3v0Ni/nntc6QtZDB88OIzA== # =vAf/ # -----END PGP SIGNATURE----- # gpg: Signature made Tue 30 Apr 2024 09:47:51 AM PDT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] * tag 'pull-target-arm-20240430' of https://git.linaro.org/people/pmaydell/qemu-arm: (21 commits) tests/qtest : Add testcase for DM163 hw/arm : Connect DM163 to B-L475E-IOT01A hw/arm : Create Bl475eMachineState hw/arm : Pass STM32L4x5 SYSCFG gpios to STM32L4x5 SoC hw/display : Add device DM163 hw/arm/npcm7xx: Store derivative OTP fuse key in little endian hw/char/stm32l4x5_usart: Fix memory corruption by adding correct class_size hw/dmax/xlnx_dpdma: fix handling of address_extension descriptor fields target/arm: Default to 1GHz cntfrq for 'max' and new CPUs hw/watchdog/sbsa_gwdt: Make watchdog timer frequency a QOM property hw/arm/sbsa-ref: Force CPU generic timer to 62.5MHz target/arm: Refactor default generic timer frequency handling tests/avocado: update sunxi kernel from armbian to 6.6.16 target/arm: Enable FEAT_Spec_FPACC for -cpu max target/arm: Implement ID_AA64MMFR3_EL1 target/arm: Enable FEAT_ETS2 for -cpu max target/arm: Enable FEAT_CSV2_3 for -cpu max docs/system/arm/emulation.rst: Add missing implemented features target/arm: Restrict translation disabled alignment check to VMSA hvf: arm: Remove PL1_WRITE_MASK ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
9c6c079bc6
33 changed files with 986 additions and 123 deletions
|
@ -468,6 +468,7 @@ config B_L475E_IOT01A
|
|||
default y
|
||||
depends on TCG && ARM
|
||||
select STM32L4X5_SOC
|
||||
imply DM163
|
||||
|
||||
config STM32L4X5_SOC
|
||||
bool
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* B-L475E-IOT01A Discovery Kit machine
|
||||
* (B-L475E-IOT01A IoT Node)
|
||||
*
|
||||
* Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
* Copyright (c) 2023-2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023-2024 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
|
@ -27,38 +27,111 @@
|
|||
#include "hw/boards.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/arm/stm32l4x5_soc.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/core/split-irq.h"
|
||||
#include "hw/arm/stm32l4x5_soc.h"
|
||||
#include "hw/gpio/stm32l4x5_gpio.h"
|
||||
#include "hw/display/dm163.h"
|
||||
|
||||
/* B-L475E-IOT01A implementation is derived from netduinoplus2 */
|
||||
/* B-L475E-IOT01A implementation is inspired from netduinoplus2 and arduino */
|
||||
|
||||
static void b_l475e_iot01a_init(MachineState *machine)
|
||||
/*
|
||||
* There are actually 14 input pins in the DM163 device.
|
||||
* Here the DM163 input pin EN isn't connected to the STM32L4x5
|
||||
* GPIOs as the IM120417002 colors shield doesn't actually use
|
||||
* this pin to drive the RGB matrix.
|
||||
*/
|
||||
#define NUM_DM163_INPUTS 13
|
||||
|
||||
static const unsigned dm163_input[NUM_DM163_INPUTS] = {
|
||||
1 * GPIO_NUM_PINS + 2, /* ROW0 PB2 */
|
||||
0 * GPIO_NUM_PINS + 15, /* ROW1 PA15 */
|
||||
0 * GPIO_NUM_PINS + 2, /* ROW2 PA2 */
|
||||
0 * GPIO_NUM_PINS + 7, /* ROW3 PA7 */
|
||||
0 * GPIO_NUM_PINS + 6, /* ROW4 PA6 */
|
||||
0 * GPIO_NUM_PINS + 5, /* ROW5 PA5 */
|
||||
1 * GPIO_NUM_PINS + 0, /* ROW6 PB0 */
|
||||
0 * GPIO_NUM_PINS + 3, /* ROW7 PA3 */
|
||||
0 * GPIO_NUM_PINS + 4, /* SIN (SDA) PA4 */
|
||||
1 * GPIO_NUM_PINS + 1, /* DCK (SCK) PB1 */
|
||||
2 * GPIO_NUM_PINS + 3, /* RST_B (RST) PC3 */
|
||||
2 * GPIO_NUM_PINS + 4, /* LAT_B (LAT) PC4 */
|
||||
2 * GPIO_NUM_PINS + 5, /* SELBK (SB) PC5 */
|
||||
};
|
||||
|
||||
#define TYPE_B_L475E_IOT01A MACHINE_TYPE_NAME("b-l475e-iot01a")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Bl475eMachineState, B_L475E_IOT01A)
|
||||
|
||||
typedef struct Bl475eMachineState {
|
||||
MachineState parent_obj;
|
||||
|
||||
Stm32l4x5SocState soc;
|
||||
SplitIRQ gpio_splitters[NUM_DM163_INPUTS];
|
||||
DM163State dm163;
|
||||
} Bl475eMachineState;
|
||||
|
||||
static void bl475e_init(MachineState *machine)
|
||||
{
|
||||
Bl475eMachineState *s = B_L475E_IOT01A(machine);
|
||||
const Stm32l4x5SocClass *sc;
|
||||
DeviceState *dev;
|
||||
DeviceState *dev, *gpio_out_splitter;
|
||||
unsigned gpio, pin;
|
||||
|
||||
dev = qdev_new(TYPE_STM32L4X5XG_SOC);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
object_initialize_child(OBJECT(machine), "soc", &s->soc,
|
||||
TYPE_STM32L4X5XG_SOC);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
|
||||
|
||||
sc = STM32L4X5_SOC_GET_CLASS(dev);
|
||||
armv7m_load_kernel(ARM_CPU(first_cpu),
|
||||
machine->kernel_filename,
|
||||
0, sc->flash_size);
|
||||
sc = STM32L4X5_SOC_GET_CLASS(&s->soc);
|
||||
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0,
|
||||
sc->flash_size);
|
||||
|
||||
if (object_class_by_name(TYPE_DM163)) {
|
||||
object_initialize_child(OBJECT(machine), "dm163",
|
||||
&s->dm163, TYPE_DM163);
|
||||
dev = DEVICE(&s->dm163);
|
||||
qdev_realize(dev, NULL, &error_abort);
|
||||
|
||||
for (unsigned i = 0; i < NUM_DM163_INPUTS; i++) {
|
||||
object_initialize_child(OBJECT(machine), "gpio-out-splitters[*]",
|
||||
&s->gpio_splitters[i], TYPE_SPLIT_IRQ);
|
||||
gpio_out_splitter = DEVICE(&s->gpio_splitters[i]);
|
||||
qdev_prop_set_uint32(gpio_out_splitter, "num-lines", 2);
|
||||
qdev_realize(gpio_out_splitter, NULL, &error_fatal);
|
||||
|
||||
qdev_connect_gpio_out(gpio_out_splitter, 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->soc), dm163_input[i]));
|
||||
qdev_connect_gpio_out(gpio_out_splitter, 1,
|
||||
qdev_get_gpio_in(dev, i));
|
||||
gpio = dm163_input[i] / GPIO_NUM_PINS;
|
||||
pin = dm163_input[i] % GPIO_NUM_PINS;
|
||||
qdev_connect_gpio_out(DEVICE(&s->soc.gpio[gpio]), pin,
|
||||
qdev_get_gpio_in(DEVICE(gpio_out_splitter), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void b_l475e_iot01a_machine_init(MachineClass *mc)
|
||||
static void bl475e_machine_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
static const char *machine_valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
||||
NULL
|
||||
};
|
||||
mc->desc = "B-L475E-IOT01A Discovery Kit (Cortex-M4)";
|
||||
mc->init = b_l475e_iot01a_init;
|
||||
mc->init = bl475e_init;
|
||||
mc->valid_cpu_types = machine_valid_cpu_types;
|
||||
|
||||
/* SRAM pre-allocated as part of the SoC instantiation */
|
||||
mc->default_ram_size = 0;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("b-l475e-iot01a", b_l475e_iot01a_machine_init)
|
||||
static const TypeInfo bl475e_machine_type[] = {
|
||||
{
|
||||
.name = TYPE_B_L475E_IOT01A,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(Bl475eMachineState),
|
||||
.class_init = bl475e_machine_init,
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_TYPES(bl475e_machine_type)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
|
@ -386,7 +387,7 @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
|
|||
* The initial mask of disabled modules indicates the chip derivative (e.g.
|
||||
* NPCM750 or NPCM730).
|
||||
*/
|
||||
value = tswap32(nc->disabled_modules);
|
||||
value = cpu_to_le32(nc->disabled_modules);
|
||||
npcm7xx_otp_array_write(&s->fuse_array, &value, NPCM7XX_FUSE_DERIVATIVE,
|
||||
sizeof(value));
|
||||
}
|
||||
|
|
|
@ -60,6 +60,19 @@
|
|||
#define NUM_SMMU_IRQS 4
|
||||
#define NUM_SATA_PORTS 6
|
||||
|
||||
/*
|
||||
* Generic timer frequency in Hz (which drives both the CPU generic timers
|
||||
* and the SBSA watchdog-timer). Older versions of the TF-A firmware
|
||||
* typically used with sbsa-ref (including the binaries in our Avocado test
|
||||
* Aarch64SbsarefMachine.test_sbsaref_alpine_linux_max_pauth_impdef
|
||||
* assume it is this value.
|
||||
*
|
||||
* TODO: this value is not architecturally correct for an Armv8.6 or
|
||||
* better CPU, so we should move to 1GHz once the TF-A fix above has
|
||||
* made it into a release and into our Avocado test.
|
||||
*/
|
||||
#define SBSA_GTIMER_HZ 62500000
|
||||
|
||||
enum {
|
||||
SBSA_FLASH,
|
||||
SBSA_MEM,
|
||||
|
@ -530,6 +543,7 @@ static void create_wdt(const SBSAMachineState *sms)
|
|||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
int irq = sbsa_ref_irqmap[SBSA_GWDT_WS0];
|
||||
|
||||
qdev_prop_set_uint64(dev, "clock-frequency", SBSA_GTIMER_HZ);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, rbase);
|
||||
sysbus_mmio_map(s, 1, cbase);
|
||||
|
@ -767,6 +781,8 @@ static void sbsa_ref_init(MachineState *machine)
|
|||
&error_abort);
|
||||
}
|
||||
|
||||
object_property_set_int(cpuobj, "cntfrq", SBSA_GTIMER_HZ, &error_abort);
|
||||
|
||||
object_property_set_link(cpuobj, "memory", OBJECT(sysmem),
|
||||
&error_abort);
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* STM32L4x5 SoC family
|
||||
*
|
||||
* Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
* Copyright (c) 2023-2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023-2024 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
|
@ -250,6 +250,8 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
qdev_pass_gpios(DEVICE(&s->syscfg), dev_soc, NULL);
|
||||
|
||||
/* EXTI device */
|
||||
busdev = SYS_BUS_DEVICE(&s->exti);
|
||||
if (!sysbus_realize(busdev, errp)) {
|
||||
|
|
|
@ -108,7 +108,6 @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
|
|||
|
||||
void clock_propagate(Clock *clk)
|
||||
{
|
||||
assert(clk->source == NULL);
|
||||
trace_clock_propagate(CLOCK_PATH(clk));
|
||||
clock_propagate_period(clk, true);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
#include "hw/virtio/virtio-iommu.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
GlobalProperty hw_compat_9_0[] = {};
|
||||
GlobalProperty hw_compat_9_0[] = {
|
||||
{"arm-cpu", "backcompat-cntfrq", "true" },
|
||||
};
|
||||
const size_t hw_compat_9_0_len = G_N_ELEMENTS(hw_compat_9_0);
|
||||
|
||||
GlobalProperty hw_compat_8_2[] = {
|
||||
|
|
|
@ -140,3 +140,6 @@ config XLNX_DISPLAYPORT
|
|||
bool
|
||||
# defaults to "N", enabled by specific boards
|
||||
depends on PIXMAN
|
||||
|
||||
config DM163
|
||||
bool
|
||||
|
|
349
hw/display/dm163.c
Normal file
349
hw/display/dm163.c
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* QEMU DM163 8x3-channel constant current led driver
|
||||
* driving columns of associated 8x8 RGB matrix.
|
||||
*
|
||||
* Copyright (C) 2024 Samuel Tardieu <sam@rfc1149.net>
|
||||
* Copyright (C) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (C) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
/*
|
||||
* The reference used for the DM163 is the following :
|
||||
* http://www.siti.com.tw/product/spec/LED/DM163.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/display/dm163.h"
|
||||
#include "ui/console.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define LED_SQUARE_SIZE 100
|
||||
/* Number of frames a row stays visible after being turned off. */
|
||||
#define ROW_PERSISTENCE 3
|
||||
#define TURNED_OFF_ROW (COLOR_BUFFER_SIZE - 1)
|
||||
|
||||
static const VMStateDescription vmstate_dm163 = {
|
||||
.name = TYPE_DM163,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT64_ARRAY(bank0_shift_register, DM163State, 3),
|
||||
VMSTATE_UINT64_ARRAY(bank1_shift_register, DM163State, 3),
|
||||
VMSTATE_UINT16_ARRAY(latched_outputs, DM163State, DM163_NUM_LEDS),
|
||||
VMSTATE_UINT16_ARRAY(outputs, DM163State, DM163_NUM_LEDS),
|
||||
VMSTATE_UINT8(dck, DM163State),
|
||||
VMSTATE_UINT8(en_b, DM163State),
|
||||
VMSTATE_UINT8(lat_b, DM163State),
|
||||
VMSTATE_UINT8(rst_b, DM163State),
|
||||
VMSTATE_UINT8(selbk, DM163State),
|
||||
VMSTATE_UINT8(sin, DM163State),
|
||||
VMSTATE_UINT8(activated_rows, DM163State),
|
||||
VMSTATE_UINT32_2DARRAY(buffer, DM163State, COLOR_BUFFER_SIZE,
|
||||
RGB_MATRIX_NUM_COLS),
|
||||
VMSTATE_UINT8(last_buffer_idx, DM163State),
|
||||
VMSTATE_UINT8_ARRAY(buffer_idx_of_row, DM163State, RGB_MATRIX_NUM_ROWS),
|
||||
VMSTATE_UINT8_ARRAY(row_persistence_delay, DM163State,
|
||||
RGB_MATRIX_NUM_ROWS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void dm163_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
DM163State *s = DM163(obj);
|
||||
|
||||
s->sin = 0;
|
||||
s->dck = 0;
|
||||
s->rst_b = 0;
|
||||
/* Ensuring the first falling edge of lat_b isn't missed */
|
||||
s->lat_b = 1;
|
||||
s->selbk = 0;
|
||||
s->en_b = 0;
|
||||
/* Reset stops the PWM, not the shift and latched registers. */
|
||||
memset(s->outputs, 0, sizeof(s->outputs));
|
||||
|
||||
s->activated_rows = 0;
|
||||
s->redraw = 0;
|
||||
trace_dm163_redraw(s->redraw);
|
||||
for (unsigned i = 0; i < COLOR_BUFFER_SIZE; i++) {
|
||||
memset(s->buffer[i], 0, sizeof(s->buffer[0]));
|
||||
}
|
||||
s->last_buffer_idx = 0;
|
||||
memset(s->buffer_idx_of_row, TURNED_OFF_ROW, sizeof(s->buffer_idx_of_row));
|
||||
memset(s->row_persistence_delay, 0, sizeof(s->row_persistence_delay));
|
||||
}
|
||||
|
||||
static void dm163_dck_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
if (new_state && !s->dck) {
|
||||
/*
|
||||
* On raising dck, sample selbk to get the bank to use, and
|
||||
* sample sin for the bit to enter into the bank shift buffer.
|
||||
*/
|
||||
uint64_t *sb =
|
||||
s->selbk ? s->bank1_shift_register : s->bank0_shift_register;
|
||||
/* Output the outgoing bit on sout */
|
||||
const bool sout = (s->selbk ? sb[2] & MAKE_64BIT_MASK(63, 1) :
|
||||
sb[2] & MAKE_64BIT_MASK(15, 1)) != 0;
|
||||
qemu_set_irq(s->sout, sout);
|
||||
/* Enter sin into the shift buffer */
|
||||
sb[2] = (sb[2] << 1) | ((sb[1] >> 63) & 1);
|
||||
sb[1] = (sb[1] << 1) | ((sb[0] >> 63) & 1);
|
||||
sb[0] = (sb[0] << 1) | s->sin;
|
||||
}
|
||||
|
||||
s->dck = new_state;
|
||||
trace_dm163_dck(new_state);
|
||||
}
|
||||
|
||||
static void dm163_propagate_outputs(DM163State *s)
|
||||
{
|
||||
s->last_buffer_idx = (s->last_buffer_idx + 1) % RGB_MATRIX_NUM_ROWS;
|
||||
/* Values are output when reset is high and enable is low. */
|
||||
if (s->rst_b && !s->en_b) {
|
||||
memcpy(s->outputs, s->latched_outputs, sizeof(s->outputs));
|
||||
} else {
|
||||
memset(s->outputs, 0, sizeof(s->outputs));
|
||||
}
|
||||
for (unsigned x = 0; x < RGB_MATRIX_NUM_COLS; x++) {
|
||||
/* Grouping the 3 RGB channels in a pixel value */
|
||||
const uint16_t b = extract16(s->outputs[3 * x + 0], 6, 8);
|
||||
const uint16_t g = extract16(s->outputs[3 * x + 1], 6, 8);
|
||||
const uint16_t r = extract16(s->outputs[3 * x + 2], 6, 8);
|
||||
uint32_t rgba = 0;
|
||||
|
||||
trace_dm163_channels(3 * x + 2, r);
|
||||
trace_dm163_channels(3 * x + 1, g);
|
||||
trace_dm163_channels(3 * x + 0, b);
|
||||
|
||||
rgba = deposit32(rgba, 0, 8, r);
|
||||
rgba = deposit32(rgba, 8, 8, g);
|
||||
rgba = deposit32(rgba, 16, 8, b);
|
||||
|
||||
/* Led values are sent from the last one to the first one */
|
||||
s->buffer[s->last_buffer_idx][RGB_MATRIX_NUM_COLS - x - 1] = rgba;
|
||||
}
|
||||
for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
|
||||
if (s->activated_rows & (1 << row)) {
|
||||
s->buffer_idx_of_row[row] = s->last_buffer_idx;
|
||||
s->redraw |= (1 << row);
|
||||
trace_dm163_redraw(s->redraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dm163_en_b_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
s->en_b = new_state;
|
||||
dm163_propagate_outputs(s);
|
||||
trace_dm163_en_b(new_state);
|
||||
}
|
||||
|
||||
static uint8_t dm163_bank0(const DM163State *s, uint8_t led)
|
||||
{
|
||||
/*
|
||||
* Bank 0 uses 6 bits per led, so a value may be stored accross
|
||||
* two uint64_t entries.
|
||||
*/
|
||||
const uint8_t low_bit = 6 * led;
|
||||
const uint8_t low_word = low_bit / 64;
|
||||
const uint8_t high_word = (low_bit + 5) / 64;
|
||||
const uint8_t low_shift = low_bit % 64;
|
||||
|
||||
if (low_word == high_word) {
|
||||
/* Simple case: the value belongs to one entry. */
|
||||
return extract64(s->bank0_shift_register[low_word], low_shift, 6);
|
||||
}
|
||||
|
||||
const uint8_t nb_bits_in_low_word = 64 - low_shift;
|
||||
const uint8_t nb_bits_in_high_word = 6 - nb_bits_in_low_word;
|
||||
|
||||
const uint64_t bits_in_low_word = \
|
||||
extract64(s->bank0_shift_register[low_word], low_shift,
|
||||
nb_bits_in_low_word);
|
||||
const uint64_t bits_in_high_word = \
|
||||
extract64(s->bank0_shift_register[high_word], 0,
|
||||
nb_bits_in_high_word);
|
||||
uint8_t val = 0;
|
||||
|
||||
val = deposit32(val, 0, nb_bits_in_low_word, bits_in_low_word);
|
||||
val = deposit32(val, nb_bits_in_low_word, nb_bits_in_high_word,
|
||||
bits_in_high_word);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint8_t dm163_bank1(const DM163State *s, uint8_t led)
|
||||
{
|
||||
const uint64_t entry = s->bank1_shift_register[led / RGB_MATRIX_NUM_COLS];
|
||||
return extract64(entry, 8 * (led % RGB_MATRIX_NUM_COLS), 8);
|
||||
}
|
||||
|
||||
static void dm163_lat_b_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
if (s->lat_b && !new_state) {
|
||||
for (int led = 0; led < DM163_NUM_LEDS; led++) {
|
||||
s->latched_outputs[led] = dm163_bank0(s, led) * dm163_bank1(s, led);
|
||||
}
|
||||
dm163_propagate_outputs(s);
|
||||
}
|
||||
|
||||
s->lat_b = new_state;
|
||||
trace_dm163_lat_b(new_state);
|
||||
}
|
||||
|
||||
static void dm163_rst_b_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
s->rst_b = new_state;
|
||||
dm163_propagate_outputs(s);
|
||||
trace_dm163_rst_b(new_state);
|
||||
}
|
||||
|
||||
static void dm163_selbk_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
s->selbk = new_state;
|
||||
trace_dm163_selbk(new_state);
|
||||
}
|
||||
|
||||
static void dm163_sin_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
s->sin = new_state;
|
||||
trace_dm163_sin(new_state);
|
||||
}
|
||||
|
||||
static void dm163_rows_gpio_handler(void *opaque, int line, int new_state)
|
||||
{
|
||||
DM163State *s = opaque;
|
||||
|
||||
if (new_state) {
|
||||
s->activated_rows |= (1 << line);
|
||||
s->buffer_idx_of_row[line] = s->last_buffer_idx;
|
||||
s->redraw |= (1 << line);
|
||||
trace_dm163_redraw(s->redraw);
|
||||
} else {
|
||||
s->activated_rows &= ~(1 << line);
|
||||
s->row_persistence_delay[line] = ROW_PERSISTENCE;
|
||||
}
|
||||
trace_dm163_activated_rows(s->activated_rows);
|
||||
}
|
||||
|
||||
static void dm163_invalidate_display(void *opaque)
|
||||
{
|
||||
DM163State *s = (DM163State *)opaque;
|
||||
s->redraw = 0xFF;
|
||||
trace_dm163_redraw(s->redraw);
|
||||
}
|
||||
|
||||
static void update_row_persistence_delay(DM163State *s, unsigned row)
|
||||
{
|
||||
if (s->row_persistence_delay[row]) {
|
||||
s->row_persistence_delay[row]--;
|
||||
} else {
|
||||
/*
|
||||
* If the ROW_PERSISTENCE delay is up,
|
||||
* the row is turned off.
|
||||
*/
|
||||
s->buffer_idx_of_row[row] = TURNED_OFF_ROW;
|
||||
s->redraw |= (1 << row);
|
||||
trace_dm163_redraw(s->redraw);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
|
||||
unsigned row)
|
||||
{
|
||||
for (unsigned _ = 0; _ < LED_SQUARE_SIZE; _++) {
|
||||
for (int x = 0; x < RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE; x++) {
|
||||
/* UI layer guarantees that there's 32 bits per pixel (Mar 2024) */
|
||||
*dest++ = s->buffer[s->buffer_idx_of_row[row]][x / LED_SQUARE_SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
dpy_gfx_update(s->console, 0, LED_SQUARE_SIZE * row,
|
||||
RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE, LED_SQUARE_SIZE);
|
||||
s->redraw &= ~(1 << row);
|
||||
trace_dm163_redraw(s->redraw);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void dm163_update_display(void *opaque)
|
||||
{
|
||||
DM163State *s = (DM163State *)opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->console);
|
||||
uint32_t *dest;
|
||||
|
||||
dest = surface_data(surface);
|
||||
for (unsigned row = 0; row < RGB_MATRIX_NUM_ROWS; row++) {
|
||||
update_row_persistence_delay(s, row);
|
||||
if (!extract8(s->redraw, row, 1)) {
|
||||
dest += LED_SQUARE_SIZE * LED_SQUARE_SIZE * RGB_MATRIX_NUM_COLS;
|
||||
continue;
|
||||
}
|
||||
dest = update_display_of_row(s, dest, row);
|
||||
}
|
||||
}
|
||||
|
||||
static const GraphicHwOps dm163_ops = {
|
||||
.invalidate = dm163_invalidate_display,
|
||||
.gfx_update = dm163_update_display,
|
||||
};
|
||||
|
||||
static void dm163_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DM163State *s = DM163(dev);
|
||||
|
||||
qdev_init_gpio_in(dev, dm163_rows_gpio_handler, RGB_MATRIX_NUM_ROWS);
|
||||
qdev_init_gpio_in(dev, dm163_sin_gpio_handler, 1);
|
||||
qdev_init_gpio_in(dev, dm163_dck_gpio_handler, 1);
|
||||
qdev_init_gpio_in(dev, dm163_rst_b_gpio_handler, 1);
|
||||
qdev_init_gpio_in(dev, dm163_lat_b_gpio_handler, 1);
|
||||
qdev_init_gpio_in(dev, dm163_selbk_gpio_handler, 1);
|
||||
qdev_init_gpio_in(dev, dm163_en_b_gpio_handler, 1);
|
||||
qdev_init_gpio_out_named(dev, &s->sout, "sout", 1);
|
||||
|
||||
s->console = graphic_console_init(dev, 0, &dm163_ops, s);
|
||||
qemu_console_resize(s->console, RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE,
|
||||
RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE);
|
||||
}
|
||||
|
||||
static void dm163_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
dc->desc = "DM163";
|
||||
dc->vmsd = &vmstate_dm163;
|
||||
dc->realize = dm163_realize;
|
||||
rc->phases.hold = dm163_reset_hold;
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo dm163_types[] = {
|
||||
{
|
||||
.name = TYPE_DM163,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(DM163State),
|
||||
.class_init = dm163_class_init
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_TYPES(dm163_types)
|
|
@ -38,6 +38,7 @@ system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
|
|||
|
||||
system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
|
||||
system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
|
||||
system_ss.add(when: 'CONFIG_DM163', if_true: files('dm163.c'))
|
||||
|
||||
if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
|
||||
config_all_devices.has_key('CONFIG_VGA_PCI') or
|
||||
|
|
|
@ -177,3 +177,17 @@ macfb_ctrl_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"PRI
|
|||
macfb_sense_read(uint32_t value) "video sense: 0x%"PRIx32
|
||||
macfb_sense_write(uint32_t value) "video sense: 0x%"PRIx32
|
||||
macfb_update_mode(uint32_t width, uint32_t height, uint8_t depth) "setting mode to width %"PRId32 " height %"PRId32 " size %d"
|
||||
|
||||
# dm163.c
|
||||
dm163_redraw(uint8_t redraw) "0x%02x"
|
||||
dm163_dck(unsigned new_state) "dck : %u"
|
||||
dm163_en_b(unsigned new_state) "en_b : %u"
|
||||
dm163_rst_b(unsigned new_state) "rst_b : %u"
|
||||
dm163_lat_b(unsigned new_state) "lat_b : %u"
|
||||
dm163_sin(unsigned new_state) "sin : %u"
|
||||
dm163_selbk(unsigned new_state) "selbk : %u"
|
||||
dm163_activated_rows(int new_state) "Activated rows : 0x%" PRIx32 ""
|
||||
dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
|
||||
dm163_leds(int led, uint32_t value) "led %d: 0x%x"
|
||||
dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
|
||||
dm163_refresh_rate(uint32_t rr) "refresh rate %d"
|
||||
|
|
|
@ -175,24 +175,24 @@ static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc,
|
|||
|
||||
switch (frag) {
|
||||
case 0:
|
||||
addr = desc->source_address
|
||||
+ (extract32(desc->address_extension, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address
|
||||
+ (extract64(desc->address_extension, 16, 16) << 32);
|
||||
break;
|
||||
case 1:
|
||||
addr = desc->source_address2
|
||||
+ (extract32(desc->address_extension_23, 0, 12) << 8);
|
||||
addr = (uint64_t)desc->source_address2
|
||||
+ (extract64(desc->address_extension_23, 0, 16) << 32);
|
||||
break;
|
||||
case 2:
|
||||
addr = desc->source_address3
|
||||
+ (extract32(desc->address_extension_23, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address3
|
||||
+ (extract64(desc->address_extension_23, 16, 16) << 32);
|
||||
break;
|
||||
case 3:
|
||||
addr = desc->source_address4
|
||||
+ (extract32(desc->address_extension_45, 0, 12) << 8);
|
||||
addr = (uint64_t)desc->source_address4
|
||||
+ (extract64(desc->address_extension_45, 0, 16) << 32);
|
||||
break;
|
||||
case 4:
|
||||
addr = desc->source_address5
|
||||
+ (extract32(desc->address_extension_45, 16, 12) << 20);
|
||||
addr = (uint64_t)desc->source_address5
|
||||
+ (extract64(desc->address_extension_45, 16, 16) << 32);
|
||||
break;
|
||||
default:
|
||||
addr = 0;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/watchdog.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/watchdog/sbsa_gwdt.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
@ -109,7 +110,7 @@ static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
|
|||
timeout = s->woru;
|
||||
timeout <<= 32;
|
||||
timeout |= s->worl;
|
||||
timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
|
||||
timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, s->freq);
|
||||
timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
|
||||
if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
|
||||
|
@ -261,6 +262,17 @@ static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
|
|||
dev);
|
||||
}
|
||||
|
||||
static Property wdt_sbsa_gwdt_props[] = {
|
||||
/*
|
||||
* Timer frequency in Hz. This must match the frequency used by
|
||||
* the CPU's generic timer. Default 62.5Hz matches QEMU's legacy
|
||||
* CPU timer frequency default.
|
||||
*/
|
||||
DEFINE_PROP_UINT64("clock-frequency", struct SBSA_GWDTState, freq,
|
||||
62500000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
@ -271,6 +283,7 @@ static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
|
|||
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
|
||||
dc->vmsd = &vmstate_sbsa_gwdt;
|
||||
dc->desc = "SBSA-compliant generic watchdog device";
|
||||
device_class_set_props(dc, wdt_sbsa_gwdt_props);
|
||||
}
|
||||
|
||||
static const TypeInfo wdt_sbsa_gwdt_info = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue