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:
Richard Henderson 2024-04-30 09:58:54 -07:00
commit 9c6c079bc6
33 changed files with 986 additions and 123 deletions

View file

@ -468,6 +468,7 @@ config B_L475E_IOT01A
default y
depends on TCG && ARM
select STM32L4X5_SOC
imply DM163
config STM32L4X5_SOC
bool

View file

@ -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)

View file

@ -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));
}

View file

@ -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);

View file

@ -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)) {

View file

@ -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);
}

View file

@ -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[] = {

View file

@ -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
View 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)

View file

@ -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

View file

@ -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"

View file

@ -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;

View file

@ -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 = {