aspeed queue:
* New ISL69259 device model * New fby35 multi-SoC machine (AST1030 BIC + AST2600 BMC) * Aspeed GPIO fixes * Extension of m25p80 with write protect bits * More avocado tests using the Aspeed SDK -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmLQJ/kACgkQUaNDx8/7 7KFO5BAAkqiSSQ9G3ihI51ET3+inihrw9wmN7FX5eMOxj8csLz1UbKOJ/YtjXvgt whfY5/iugVveUW+/X1xZmHbydec24f/umSpqqCtkPkIwCgvN4gjQAriXTK4qqx7g pCZoWxYeHsR19r985y//I+wFPB//Dd3Ac/1BgA4m0tdy/bK3MPLV2ocDe8d09Yfe wDYAFby4q8raKzMkJMibP7/phIg4hyguNAYtkSUsJChnXjK8/2ymsjlx7Xz+N1Gp Fynv9vaFiYOEvmDTPqbs7XMs3Qc+Sjz2RsxgaEdSI4pLk8H8hhgVueYE1ctWlpkI 7q/g5KjXZsq6eKxNYDqU+ysY+vjdLZmO1tEmolgR+k4C+ladUYSBaI1XiGJjCmpb 6vkM2ls1sgmb6C24e8vP64Jp/AgT6Qg7OW1Db3VcpBbQirf9SqtkXezgseOrsnXm Ni1uQF9NwUiRUWTA/bK4y/pSYNItoQ4KkeoAWPsiEm0d4Pezk2X+EMjJcCTQw9Zx BFtDxi/3rWB3imvhizynT93+rtNH7Z74kiI7iZGbZr6L2XhpEUlwoo+EOaeb4XAS ZEuR+kBNUMR9k4YhyF0DlvN61SuD703SdXCROsUq3EzCgza24JM4bl2IMSyv9Wdj DCL6yYEyf8FsJ9+KtK8A1uXc2yDcV4iGfEqOReTB5+k99ICzgEg= =faie -----END PGP SIGNATURE----- Merge tag 'pull-aspeed-20220714' of https://github.com/legoater/qemu into staging aspeed queue: * New ISL69259 device model * New fby35 multi-SoC machine (AST1030 BIC + AST2600 BMC) * Aspeed GPIO fixes * Extension of m25p80 with write protect bits * More avocado tests using the Aspeed SDK # gpg: Signature made Thu 14 Jul 2022 15:28:09 BST # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-aspeed-20220714' of https://github.com/legoater/qemu: aspeed: Add fby35-bmc slot GPIO's hw/gpio/aspeed: Don't let guests modify input pins qtest/aspeed_gpio: Add input pin modification test hw: m25p80: add tests for BP and TB bit write protect hw: m25p80: Add Block Protect and Top Bottom bits for write protect test/avocado/machine_aspeed.py: Add SDK tests docs: aspeed: Minor updates docs: aspeed: Add fby35 multi-SoC machine section aspeed: Add AST1030 (BIC) to fby35 aspeed: fby35: Add a bootrom for the BMC aspeed: Add AST2600 (BMC) to fby35 aspeed: Add fby35 skeleton aspeed: Make aspeed_board_init_flashes public aspeed: Refactor UART init for multi-SoC machines aspeed: Create SRAM name from first CPU index hw/sensor: Add Renesas ISL69259 device model hw/sensor: Add IC_DEVICE_ID to ISL voltage regulators hw/i2c/pmbus: Add idle state to return 0xff's aspeed: sbc: Allow per-machine settings Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
44bfcf628b
@ -1065,6 +1065,7 @@ F: hw/net/ftgmac100.c
|
||||
F: include/hw/net/ftgmac100.h
|
||||
F: docs/system/arm/aspeed.rst
|
||||
F: tests/qtest/*aspeed*
|
||||
F: hw/arm/fby35.c
|
||||
|
||||
NRF51
|
||||
M: Joel Stanley <joel@jms.id.au>
|
||||
|
@ -31,7 +31,10 @@ AST2600 SoC based machines :
|
||||
- ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC
|
||||
- ``rainier-bmc`` IBM Rainier POWER10 BMC
|
||||
- ``fuji-bmc`` Facebook Fuji BMC
|
||||
- ``bletchley-bmc`` Facebook Bletchley BMC
|
||||
- ``fby35-bmc`` Facebook fby35 BMC
|
||||
- ``qcom-dc-scm-v1-bmc`` Qualcomm DC-SCM V1 BMC
|
||||
- ``qcom-firework-bmc`` Qualcomm Firework BMC
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
@ -40,7 +43,7 @@ Supported devices
|
||||
* Interrupt Controller (VIC)
|
||||
* Timer Controller
|
||||
* RTC Controller
|
||||
* I2C Controller
|
||||
* I2C Controller, including the new register interface of the AST2600
|
||||
* System Control Unit (SCU)
|
||||
* SRAM mapping
|
||||
* X-DMA Controller (basic interface)
|
||||
@ -57,6 +60,10 @@ Supported devices
|
||||
* LPC Peripheral Controller (a subset of subdevices are supported)
|
||||
* Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA
|
||||
* ADC
|
||||
* Secure Boot Controller (AST2600)
|
||||
* eMMC Boot Controller (dummy)
|
||||
* PECI Controller (minimal)
|
||||
* I3C Controller
|
||||
|
||||
|
||||
Missing devices
|
||||
@ -68,12 +75,10 @@ Missing devices
|
||||
* Super I/O Controller
|
||||
* PCI-Express 1 Controller
|
||||
* Graphic Display Controller
|
||||
* PECI Controller
|
||||
* MCTP Controller
|
||||
* Mailbox Controller
|
||||
* Virtual UART
|
||||
* eSPI Controller
|
||||
* I3C Controller
|
||||
|
||||
Boot options
|
||||
------------
|
||||
@ -154,6 +159,8 @@ Supported devices
|
||||
* LPC Peripheral Controller (a subset of subdevices are supported)
|
||||
* Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA
|
||||
* ADC
|
||||
* Secure Boot Controller
|
||||
* PECI Controller (minimal)
|
||||
|
||||
|
||||
Missing devices
|
||||
@ -161,7 +168,6 @@ Missing devices
|
||||
|
||||
* PWM and Fan Controller
|
||||
* Slave GPIO Controller
|
||||
* PECI Controller
|
||||
* Mailbox Controller
|
||||
* Virtual UART
|
||||
* eSPI Controller
|
||||
@ -182,3 +188,51 @@ To boot a kernel directly from a Zephyr build tree:
|
||||
|
||||
$ qemu-system-arm -M ast1030-evb -nographic \
|
||||
-kernel zephyr.elf
|
||||
|
||||
Facebook Yosemite v3.5 Platform and CraterLake Server (``fby35``)
|
||||
==================================================================
|
||||
|
||||
Facebook has a series of multi-node compute server designs named
|
||||
Yosemite. The most recent version released was
|
||||
`Yosemite v3 <https://www.opencompute.org/documents/ocp-yosemite-v3-platform-design-specification-1v16-pdf>`__.
|
||||
|
||||
Yosemite v3.5 is an iteration on this design, and is very similar: there's a
|
||||
baseboard with a BMC, and 4 server slots. The new server board design termed
|
||||
"CraterLake" includes a Bridge IC (BIC), with room for expansion boards to
|
||||
include various compute accelerators (video, inferencing, etc). At the moment,
|
||||
only the first server slot's BIC is included.
|
||||
|
||||
Yosemite v3.5 is itself a sled which fits into a 40U chassis, and 3 sleds
|
||||
can be fit into a chassis. See `here <https://www.opencompute.org/products/423/wiwynn-yosemite-v3-server>`__
|
||||
for an example.
|
||||
|
||||
In this generation, the BMC is an AST2600 and each BIC is an AST1030. The BMC
|
||||
runs `OpenBMC <https://github.com/facebook/openbmc>`__, and the BIC runs
|
||||
`OpenBIC <https://github.com/facebook/openbic>`__.
|
||||
|
||||
Firmware images can be retrieved from the Github releases or built from the
|
||||
source code, see the README's for instructions on that. This image uses the
|
||||
"fby35" machine recipe from OpenBMC, and the "yv35-cl" target from OpenBIC.
|
||||
Some reference images can also be found here:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ wget https://github.com/facebook/openbmc/releases/download/openbmc-e2294ff5d31d/fby35.mtd
|
||||
$ wget https://github.com/peterdelevoryas/OpenBIC/releases/download/oby35-cl-2022.13.01/Y35BCL.elf
|
||||
|
||||
Since this machine has multiple SoC's, each with their own serial console, the
|
||||
recommended way to run it is to allocate a pseudoterminal for each serial
|
||||
console and let the monitor use stdio. Also, starting in a paused state is
|
||||
useful because it allows you to attach to the pseudoterminals before the boot
|
||||
process starts.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-arm -machine fby35 \
|
||||
-drive file=fby35.mtd,format=raw,if=mtd \
|
||||
-device loader,file=Y35BCL.elf,addr=0,cpu-num=2 \
|
||||
-serial pty -serial pty -serial mon:stdio \
|
||||
-display none -S
|
||||
$ screen /dev/tty0 # In a separate TMUX pane, terminal window, etc.
|
||||
$ screen /dev/tty1
|
||||
$ (qemu) c # Start the boot process once screen is setup.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
static struct arm_boot_info aspeed_board_binfo = {
|
||||
.board_id = -1, /* device-tree-only board */
|
||||
@ -261,7 +262,7 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
|
||||
rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
|
||||
}
|
||||
|
||||
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
unsigned int count, int unit0)
|
||||
{
|
||||
int i;
|
||||
@ -301,6 +302,21 @@ static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo)
|
||||
&error_fatal);
|
||||
}
|
||||
|
||||
static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
|
||||
{
|
||||
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
|
||||
AspeedSoCState *s = &bmc->soc;
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
|
||||
aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
|
||||
for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
|
||||
if (uart == amc->uart_default) {
|
||||
continue;
|
||||
}
|
||||
aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_machine_init(MachineState *machine)
|
||||
{
|
||||
AspeedMachineState *bmc = ASPEED_MACHINE(machine);
|
||||
@ -346,8 +362,7 @@ static void aspeed_machine_init(MachineState *machine)
|
||||
object_property_set_int(OBJECT(&bmc->soc), "hw-prot-key",
|
||||
ASPEED_SCU_PROT_KEY, &error_abort);
|
||||
}
|
||||
qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default",
|
||||
amc->uart_default);
|
||||
connect_serial_hds_to_uarts(bmc);
|
||||
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc,
|
||||
@ -1343,11 +1358,23 @@ static void fby35_reset(MachineState *state)
|
||||
|
||||
qemu_devices_reset();
|
||||
|
||||
/* Board ID */
|
||||
/* Board ID: 7 (Class-1, 4 slots) */
|
||||
object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioV5", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioV6", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioV7", false, &error_fatal);
|
||||
|
||||
/* Slot presence pins, inverse polarity. (False means present) */
|
||||
object_property_set_bool(OBJECT(gpio), "gpioH4", false, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioH5", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioH6", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioH7", true, &error_fatal);
|
||||
|
||||
/* Slot 12v power pins, normal polarity. (True means powered-on) */
|
||||
object_property_set_bool(OBJECT(gpio), "gpioB2", true, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioB3", false, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioB4", false, &error_fatal);
|
||||
object_property_set_bool(OBJECT(gpio), "gpioB5", false, &error_fatal);
|
||||
}
|
||||
|
||||
static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data)
|
||||
@ -1383,8 +1410,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
|
||||
|
||||
object_property_set_link(OBJECT(&bmc->soc), "memory",
|
||||
OBJECT(get_system_memory()), &error_abort);
|
||||
qdev_prop_set_uint32(DEVICE(&bmc->soc), "uart-default",
|
||||
amc->uart_default);
|
||||
connect_serial_hds_to_uarts(bmc);
|
||||
qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc,
|
||||
|
@ -144,6 +144,10 @@ static void aspeed_soc_ast1030_init(Object *obj)
|
||||
object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->uarts_num; i++) {
|
||||
object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
|
||||
}
|
||||
|
||||
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
|
||||
object_initialize_child(obj, "gpio", &s->gpio, typename);
|
||||
|
||||
@ -159,6 +163,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
|
||||
DeviceState *armv7m;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
g_autofree char *sram_name = NULL;
|
||||
|
||||
if (!clock_has_source(s->sysclk)) {
|
||||
error_setg(errp, "sysclk clock must be wired up by the board code");
|
||||
@ -183,7 +188,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), &error_abort);
|
||||
|
||||
/* Internal SRAM */
|
||||
memory_region_init_ram(&s->sram, NULL, "aspeed.sram", sc->sram_size, &err);
|
||||
sram_name = g_strdup_printf("aspeed.sram.%d",
|
||||
CPU(s->armv7m.cpu)->cpu_index);
|
||||
memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@ -252,7 +259,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp)
|
||||
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4));
|
||||
|
||||
/* UART */
|
||||
aspeed_soc_uart_init(s);
|
||||
if (!aspeed_soc_uart_realize(s, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu),
|
||||
|
@ -214,6 +214,10 @@ static void aspeed_soc_ast2600_init(Object *obj)
|
||||
object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->uarts_num; i++) {
|
||||
object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
|
||||
}
|
||||
|
||||
snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
|
||||
object_initialize_child(obj, "xdma", &s->xdma, typename);
|
||||
|
||||
@ -276,6 +280,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
Error *err = NULL;
|
||||
qemu_irq irq;
|
||||
g_autofree char *sram_name = NULL;
|
||||
|
||||
/* IO space */
|
||||
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
|
||||
@ -335,8 +340,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
|
||||
sc->sram_size, &err);
|
||||
sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index);
|
||||
memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@ -385,7 +390,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
|
||||
|
||||
/* UART */
|
||||
aspeed_soc_uart_init(s);
|
||||
if (!aspeed_soc_uart_realize(s, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
|
||||
|
@ -208,6 +208,10 @@ static void aspeed_soc_init(Object *obj)
|
||||
TYPE_FTGMAC100);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->uarts_num; i++) {
|
||||
object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
|
||||
}
|
||||
|
||||
snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
|
||||
object_initialize_child(obj, "xdma", &s->xdma, typename);
|
||||
|
||||
@ -239,6 +243,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
AspeedSoCState *s = ASPEED_SOC(dev);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
Error *err = NULL;
|
||||
g_autofree char *sram_name = NULL;
|
||||
|
||||
/* IO space */
|
||||
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
|
||||
@ -259,8 +264,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
|
||||
sc->sram_size, &err);
|
||||
sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&s->cpu[0])->cpu_index);
|
||||
memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@ -314,7 +319,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
|
||||
|
||||
/* UART */
|
||||
aspeed_soc_uart_init(s);
|
||||
if (!aspeed_soc_uart_realize(s, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
|
||||
@ -481,8 +488,6 @@ static Property aspeed_soc_properties[] = {
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_UINT32("uart-default", AspeedSoCState, uart_default,
|
||||
ASPEED_DEV_UART5),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -572,23 +577,37 @@ qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev)
|
||||
return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev);
|
||||
}
|
||||
|
||||
void aspeed_soc_uart_init(AspeedSoCState *s)
|
||||
bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp)
|
||||
{
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
int i, uart;
|
||||
SerialMM *smm;
|
||||
|
||||
/* Attach an 8250 to the IO space as our UART */
|
||||
serial_mm_init(s->memory, sc->memmap[s->uart_default], 2,
|
||||
aspeed_soc_get_irq(s, s->uart_default), 38400,
|
||||
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
for (i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
|
||||
if (uart == s->uart_default) {
|
||||
uart++;
|
||||
for (int i = 0, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
|
||||
smm = &s->uart[i];
|
||||
|
||||
/* Chardev property is set by the machine. */
|
||||
qdev_prop_set_uint8(DEVICE(smm), "regshift", 2);
|
||||
qdev_prop_set_uint32(DEVICE(smm), "baudbase", 38400);
|
||||
qdev_set_legacy_instance_id(DEVICE(smm), sc->memmap[uart], 2);
|
||||
qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(smm), errp)) {
|
||||
return false;
|
||||
}
|
||||
serial_mm_init(s->memory, sc->memmap[uart], 2,
|
||||
aspeed_soc_get_irq(s, uart), 38400,
|
||||
serial_hd(i), DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, aspeed_soc_get_irq(s, uart));
|
||||
aspeed_mmio_map(s, SYS_BUS_DEVICE(smm), 0, sc->memmap[uart]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr)
|
||||
{
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
int i = dev - ASPEED_DEV_UART1;
|
||||
|
||||
g_assert(0 <= i && i < ARRAY_SIZE(s->uart) && i < sc->uarts_num);
|
||||
qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
188
hw/arm/fby35.c
Normal file
188
hw/arm/fby35.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the COPYING
|
||||
* file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/arm/aspeed_soc.h"
|
||||
#include "hw/arm/boot.h"
|
||||
|
||||
#define TYPE_FBY35 MACHINE_TYPE_NAME("fby35")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Fby35State, FBY35);
|
||||
|
||||
struct Fby35State {
|
||||
MachineState parent_obj;
|
||||
|
||||
MemoryRegion bmc_memory;
|
||||
MemoryRegion bmc_dram;
|
||||
MemoryRegion bmc_boot_rom;
|
||||
MemoryRegion bic_memory;
|
||||
Clock *bic_sysclk;
|
||||
|
||||
AspeedSoCState bmc;
|
||||
AspeedSoCState bic;
|
||||
|
||||
bool mmio_exec;
|
||||
};
|
||||
|
||||
#define FBY35_BMC_RAM_SIZE (2 * GiB)
|
||||
#define FBY35_BMC_FIRMWARE_ADDR 0x0
|
||||
|
||||
static void fby35_bmc_write_boot_rom(DriveInfo *dinfo, MemoryRegion *mr,
|
||||
hwaddr offset, size_t rom_size,
|
||||
Error **errp)
|
||||
{
|
||||
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||
g_autofree void *storage = NULL;
|
||||
int64_t size;
|
||||
|
||||
/*
|
||||
* The block backend size should have already been 'validated' by
|
||||
* the creation of the m25p80 object.
|
||||
*/
|
||||
size = blk_getlength(blk);
|
||||
if (size <= 0) {
|
||||
error_setg(errp, "failed to get flash size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rom_size > size) {
|
||||
rom_size = size;
|
||||
}
|
||||
|
||||
storage = g_malloc0(rom_size);
|
||||
if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
|
||||
error_setg(errp, "failed to read the initial flash content");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: find a better way to install the ROM */
|
||||
memcpy(memory_region_get_ram_ptr(mr) + offset, storage, rom_size);
|
||||
}
|
||||
|
||||
static void fby35_bmc_init(Fby35State *s)
|
||||
{
|
||||
DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
|
||||
|
||||
memory_region_init(&s->bmc_memory, OBJECT(s), "bmc-memory", UINT64_MAX);
|
||||
memory_region_init_ram(&s->bmc_dram, OBJECT(s), "bmc-dram",
|
||||
FBY35_BMC_RAM_SIZE, &error_abort);
|
||||
|
||||
object_initialize_child(OBJECT(s), "bmc", &s->bmc, "ast2600-a3");
|
||||
object_property_set_int(OBJECT(&s->bmc), "ram-size", FBY35_BMC_RAM_SIZE,
|
||||
&error_abort);
|
||||
object_property_set_link(OBJECT(&s->bmc), "memory", OBJECT(&s->bmc_memory),
|
||||
&error_abort);
|
||||
object_property_set_link(OBJECT(&s->bmc), "dram", OBJECT(&s->bmc_dram),
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->bmc), "hw-strap1", 0x000000C0,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->bmc), "hw-strap2", 0x00000003,
|
||||
&error_abort);
|
||||
aspeed_soc_uart_set_chr(&s->bmc, ASPEED_DEV_UART5, serial_hd(0));
|
||||
qdev_realize(DEVICE(&s->bmc), NULL, &error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&s->bmc.fmc, "n25q00", 2, 0);
|
||||
|
||||
/* Install first FMC flash content as a boot rom. */
|
||||
if (drive0) {
|
||||
AspeedSMCFlash *fl = &s->bmc.fmc.flashes[0];
|
||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
||||
uint64_t size = memory_region_size(&fl->mmio);
|
||||
|
||||
if (s->mmio_exec) {
|
||||
memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom",
|
||||
&fl->mmio, 0, size);
|
||||
memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR,
|
||||
boot_rom);
|
||||
} else {
|
||||
|
||||
memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom",
|
||||
size, &error_abort);
|
||||
memory_region_add_subregion(&s->bmc_memory, FBY35_BMC_FIRMWARE_ADDR,
|
||||
boot_rom);
|
||||
fby35_bmc_write_boot_rom(drive0, boot_rom, FBY35_BMC_FIRMWARE_ADDR,
|
||||
size, &error_abort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fby35_bic_init(Fby35State *s)
|
||||
{
|
||||
s->bic_sysclk = clock_new(OBJECT(s), "SYSCLK");
|
||||
clock_set_hz(s->bic_sysclk, 200000000ULL);
|
||||
|
||||
memory_region_init(&s->bic_memory, OBJECT(s), "bic-memory", UINT64_MAX);
|
||||
|
||||
object_initialize_child(OBJECT(s), "bic", &s->bic, "ast1030-a1");
|
||||
qdev_connect_clock_in(DEVICE(&s->bic), "sysclk", s->bic_sysclk);
|
||||
object_property_set_link(OBJECT(&s->bic), "memory", OBJECT(&s->bic_memory),
|
||||
&error_abort);
|
||||
aspeed_soc_uart_set_chr(&s->bic, ASPEED_DEV_UART5, serial_hd(1));
|
||||
qdev_realize(DEVICE(&s->bic), NULL, &error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&s->bic.fmc, "sst25vf032b", 2, 2);
|
||||
aspeed_board_init_flashes(&s->bic.spi[0], "sst25vf032b", 2, 4);
|
||||
aspeed_board_init_flashes(&s->bic.spi[1], "sst25vf032b", 2, 6);
|
||||
}
|
||||
|
||||
static void fby35_init(MachineState *machine)
|
||||
{
|
||||
Fby35State *s = FBY35(machine);
|
||||
|
||||
fby35_bmc_init(s);
|
||||
fby35_bic_init(s);
|
||||
}
|
||||
|
||||
|
||||
static bool fby35_get_mmio_exec(Object *obj, Error **errp)
|
||||
{
|
||||
return FBY35(obj)->mmio_exec;
|
||||
}
|
||||
|
||||
static void fby35_set_mmio_exec(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
FBY35(obj)->mmio_exec = value;
|
||||
}
|
||||
|
||||
static void fby35_instance_init(Object *obj)
|
||||
{
|
||||
FBY35(obj)->mmio_exec = false;
|
||||
}
|
||||
|
||||
static void fby35_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Meta Platforms fby35";
|
||||
mc->init = fby35_init;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->min_cpus = mc->max_cpus = mc->default_cpus = 3;
|
||||
|
||||
object_class_property_add_bool(oc, "execute-in-place",
|
||||
fby35_get_mmio_exec,
|
||||
fby35_set_mmio_exec);
|
||||
object_class_property_set_description(oc, "execute-in-place",
|
||||
"boot directly from CE0 flash device");
|
||||
}
|
||||
|
||||
static const TypeInfo fby35_types[] = {
|
||||
{
|
||||
.name = MACHINE_TYPE_NAME("fby35"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = fby35_class_init,
|
||||
.instance_size = sizeof(Fby35State),
|
||||
.instance_init = fby35_instance_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(fby35_types);
|
@ -51,7 +51,8 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
|
||||
'aspeed_soc.c',
|
||||
'aspeed.c',
|
||||
'aspeed_ast2600.c',
|
||||
'aspeed_ast10x0.c'))
|
||||
'aspeed_ast10x0.c',
|
||||
'fby35.c'))
|
||||
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c'))
|
||||
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c'))
|
||||
arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
|
||||
|
@ -36,21 +36,19 @@
|
||||
#include "trace.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Fields for FlashPartInfo->flags */
|
||||
|
||||
/* erase capabilities */
|
||||
#define ER_4K 1
|
||||
#define ER_32K 2
|
||||
/* set to allow the page program command to write 0s back to 1. Useful for
|
||||
* modelling EEPROM with SPI flash command set
|
||||
*/
|
||||
#define EEPROM 0x100
|
||||
|
||||
/* 16 MiB max in 3 byte address mode */
|
||||
#define MAX_3BYTES_SIZE 0x1000000
|
||||
|
||||
#define SPI_NOR_MAX_ID_LEN 6
|
||||
|
||||
/* Fields for FlashPartInfo->flags */
|
||||
enum spi_flash_option_flags {
|
||||
ER_4K = BIT(0),
|
||||
ER_32K = BIT(1),
|
||||
EEPROM = BIT(2),
|
||||
HAS_SR_TB = BIT(3),
|
||||
HAS_SR_BP3_BIT6 = BIT(4),
|
||||
};
|
||||
|
||||
typedef struct FlashPartInfo {
|
||||
const char *part_name;
|
||||
/*
|
||||
@ -251,7 +249,8 @@ static const FlashPartInfo known_devices[] = {
|
||||
{ INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512,
|
||||
ER_4K | HAS_SR_BP3_BIT6 | HAS_SR_TB) },
|
||||
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
|
||||
@ -478,6 +477,11 @@ struct Flash {
|
||||
bool reset_enable;
|
||||
bool quad_enable;
|
||||
bool aai_enable;
|
||||
bool block_protect0;
|
||||
bool block_protect1;
|
||||
bool block_protect2;
|
||||
bool block_protect3;
|
||||
bool top_bottom_bit;
|
||||
bool status_register_write_disabled;
|
||||
uint8_t ear;
|
||||
|
||||
@ -623,12 +627,36 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data)
|
||||
{
|
||||
uint32_t page = addr / s->pi->page_size;
|
||||
uint8_t prev = s->storage[s->cur_addr];
|
||||
uint32_t block_protect_value = (s->block_protect3 << 3) |
|
||||
(s->block_protect2 << 2) |
|
||||
(s->block_protect1 << 1) |
|
||||
(s->block_protect0 << 0);
|
||||
|
||||
if (!s->write_enable) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_protect_value > 0) {
|
||||
uint32_t num_protected_sectors = 1 << (block_protect_value - 1);
|
||||
uint32_t sector = addr / s->pi->sector_size;
|
||||
|
||||
/* top_bottom_bit == 0 means TOP */
|
||||
if (!s->top_bottom_bit) {
|
||||
if (s->pi->n_sectors <= sector + num_protected_sectors) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (sector < num_protected_sectors) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((prev ^ data) & data) {
|
||||
trace_m25p80_programming_zero_to_one(s, addr, prev, data);
|
||||
}
|
||||
@ -726,6 +754,15 @@ static void complete_collecting_data(Flash *s)
|
||||
break;
|
||||
case WRSR:
|
||||
s->status_register_write_disabled = extract32(s->data[0], 7, 1);
|
||||
s->block_protect0 = extract32(s->data[0], 2, 1);
|
||||
s->block_protect1 = extract32(s->data[0], 3, 1);
|
||||
s->block_protect2 = extract32(s->data[0], 4, 1);
|
||||
if (s->pi->flags & HAS_SR_TB) {
|
||||
s->top_bottom_bit = extract32(s->data[0], 5, 1);
|
||||
}
|
||||
if (s->pi->flags & HAS_SR_BP3_BIT6) {
|
||||
s->block_protect3 = extract32(s->data[0], 6, 1);
|
||||
}
|
||||
|
||||
switch (get_man(s)) {
|
||||
case MAN_SPANSION:
|
||||
@ -1212,6 +1249,15 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
case RDSR:
|
||||
s->data[0] = (!!s->write_enable) << 1;
|
||||
s->data[0] |= (!!s->status_register_write_disabled) << 7;
|
||||
s->data[0] |= (!!s->block_protect0) << 2;
|
||||
s->data[0] |= (!!s->block_protect1) << 3;
|
||||
s->data[0] |= (!!s->block_protect2) << 4;
|
||||
if (s->pi->flags & HAS_SR_TB) {
|
||||
s->data[0] |= (!!s->top_bottom_bit) << 5;
|
||||
}
|
||||
if (s->pi->flags & HAS_SR_BP3_BIT6) {
|
||||
s->data[0] |= (!!s->block_protect3) << 6;
|
||||
}
|
||||
|
||||
if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
|
||||
s->data[0] |= (!!s->quad_enable) << 6;
|
||||
@ -1552,6 +1598,11 @@ static void m25p80_reset(DeviceState *d)
|
||||
|
||||
s->wp_level = true;
|
||||
s->status_register_write_disabled = false;
|
||||
s->block_protect0 = false;
|
||||
s->block_protect1 = false;
|
||||
s->block_protect2 = false;
|
||||
s->block_protect3 = false;
|
||||
s->top_bottom_bit = false;
|
||||
|
||||
reset_memory(s);
|
||||
}
|
||||
@ -1638,6 +1689,32 @@ static const VMStateDescription vmstate_m25p80_write_protect = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool m25p80_block_protect_needed(void *opaque)
|
||||
{
|
||||
Flash *s = (Flash *)opaque;
|
||||
|
||||
return s->block_protect0 ||
|
||||
s->block_protect1 ||
|
||||
s->block_protect2 ||
|
||||
s->block_protect3 ||
|
||||
s->top_bottom_bit;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_m25p80_block_protect = {
|
||||
.name = "m25p80/block_protect",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = m25p80_block_protect_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(block_protect0, Flash),
|
||||
VMSTATE_BOOL(block_protect1, Flash),
|
||||
VMSTATE_BOOL(block_protect2, Flash),
|
||||
VMSTATE_BOOL(block_protect3, Flash),
|
||||
VMSTATE_BOOL(top_bottom_bit, Flash),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_m25p80 = {
|
||||
.name = "m25p80",
|
||||
.version_id = 0,
|
||||
@ -1670,6 +1747,7 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
&vmstate_m25p80_data_read_loop,
|
||||
&vmstate_m25p80_aai_enable,
|
||||
&vmstate_m25p80_write_protect,
|
||||
&vmstate_m25p80_block_protect,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
@ -268,7 +268,7 @@ static ptrdiff_t aspeed_gpio_set_idx(AspeedGPIOState *s, GPIOSets *regs)
|
||||
}
|
||||
|
||||
static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
|
||||
uint32_t value)
|
||||
uint32_t value, uint32_t mode_mask)
|
||||
{
|
||||
uint32_t input_mask = regs->input_mask;
|
||||
uint32_t direction = regs->direction;
|
||||
@ -277,7 +277,8 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
|
||||
uint32_t diff;
|
||||
int gpio;
|
||||
|
||||
diff = old ^ new;
|
||||
diff = (old ^ new);
|
||||
diff &= mode_mask;
|
||||
if (diff) {
|
||||
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
|
||||
uint32_t mask = 1 << gpio;
|
||||
@ -339,7 +340,7 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx,
|
||||
value &= ~pin_mask;
|
||||
}
|
||||
|
||||
aspeed_gpio_update(s, &s->sets[set_idx], value);
|
||||
aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -653,7 +654,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
|
||||
reg_value = update_value_control_source(set, set->data_value,
|
||||
reg_value);
|
||||
set->data_read = reg_value;
|
||||
aspeed_gpio_update(s, set, reg_value);
|
||||
aspeed_gpio_update(s, set, reg_value, set->direction);
|
||||
return;
|
||||
case gpio_reg_idx_direction:
|
||||
reg_value = set->direction;
|
||||
@ -753,7 +754,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
|
||||
__func__, offset, data, reg_idx_type);
|
||||
return;
|
||||
}
|
||||
aspeed_gpio_update(s, set, set->data_value);
|
||||
aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -799,7 +800,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
data &= props->output;
|
||||
data = update_value_control_source(set, set->data_value, data);
|
||||
set->data_read = data;
|
||||
aspeed_gpio_update(s, set, data);
|
||||
aspeed_gpio_update(s, set, data, set->direction);
|
||||
return;
|
||||
case gpio_reg_direction:
|
||||
/*
|
||||
@ -875,7 +876,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
PRIx64"\n", __func__, offset);
|
||||
return;
|
||||
}
|
||||
aspeed_gpio_update(s, set, set->data_value);
|
||||
aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -261,6 +261,11 @@ void pmbus_check_limits(PMBusDevice *pmdev)
|
||||
}
|
||||
}
|
||||
|
||||
void pmbus_idle(PMBusDevice *pmdev)
|
||||
{
|
||||
pmdev->code = PMBUS_IDLE_STATE;
|
||||
}
|
||||
|
||||
/* assert the status_cml error upon receipt of malformed command */
|
||||
static void pmbus_cml_error(PMBusDevice *pmdev)
|
||||
{
|
||||
@ -980,6 +985,10 @@ static uint8_t pmbus_receive_byte(SMBusDevice *smd)
|
||||
}
|
||||
break;
|
||||
|
||||
case PMBUS_IDLE_STATE:
|
||||
pmbus_send8(pmdev, PMBUS_ERR_BYTE);
|
||||
break;
|
||||
|
||||
case PMBUS_CLEAR_FAULTS: /* Send Byte */
|
||||
case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */
|
||||
case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/misc/aspeed_sbc.h"
|
||||
#include "qapi/error.h"
|
||||
#include "migration/vmstate.h"
|
||||
@ -19,6 +20,27 @@
|
||||
#define R_STATUS (0x014 / 4)
|
||||
#define R_QSR (0x040 / 4)
|
||||
|
||||
/* R_STATUS */
|
||||
#define ABR_EN BIT(14) /* Mirrors SCU510[11] */
|
||||
#define ABR_IMAGE_SOURCE BIT(13)
|
||||
#define SPI_ABR_IMAGE_SOURCE BIT(12)
|
||||
#define SB_CRYPTO_KEY_EXP_DONE BIT(11)
|
||||
#define SB_CRYPTO_BUSY BIT(10)
|
||||
#define OTP_WP_EN BIT(9)
|
||||
#define OTP_ADDR_WP_EN BIT(8)
|
||||
#define LOW_SEC_KEY_EN BIT(7)
|
||||
#define SECURE_BOOT_EN BIT(6)
|
||||
#define UART_BOOT_EN BIT(5)
|
||||
/* bit 4 reserved*/
|
||||
#define OTP_CHARGE_PUMP_READY BIT(3)
|
||||
#define OTP_IDLE BIT(2)
|
||||
#define OTP_MEM_IDLE BIT(1)
|
||||
#define OTP_COMPARE_STATUS BIT(0)
|
||||
|
||||
/* QSR */
|
||||
#define QSR_RSA_MASK (0x3 << 12)
|
||||
#define QSR_HASH_MASK (0x3 << 10)
|
||||
|
||||
static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
AspeedSBCState *s = ASPEED_SBC(opaque);
|
||||
@ -80,8 +102,17 @@ static void aspeed_sbc_reset(DeviceState *dev)
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
/* Set secure boot enabled with RSA4096_SHA256 and enable eMMC ABR */
|
||||
s->regs[R_STATUS] = 0x000044C6;
|
||||
s->regs[R_QSR] = 0x07C07C89;
|
||||
s->regs[R_STATUS] = OTP_IDLE | OTP_MEM_IDLE;
|
||||
|
||||
if (s->emmc_abr) {
|
||||
s->regs[R_STATUS] &= ABR_EN;
|
||||
}
|
||||
|
||||
if (s->signing_settings) {
|
||||
s->regs[R_STATUS] &= SECURE_BOOT_EN;
|
||||
}
|
||||
|
||||
s->regs[R_QSR] = s->signing_settings;
|
||||
}
|
||||
|
||||
static void aspeed_sbc_realize(DeviceState *dev, Error **errp)
|
||||
@ -105,6 +136,12 @@ static const VMStateDescription vmstate_aspeed_sbc = {
|
||||
}
|
||||
};
|
||||
|
||||
static Property aspeed_sbc_properties[] = {
|
||||
DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0),
|
||||
DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -112,6 +149,7 @@ static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = aspeed_sbc_realize;
|
||||
dc->reset = aspeed_sbc_reset;
|
||||
dc->vmsd = &vmstate_aspeed_sbc;
|
||||
device_class_set_props(dc, aspeed_sbc_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_sbc_info = {
|
||||
|
@ -15,6 +15,18 @@
|
||||
|
||||
static uint8_t isl_pmbus_vr_read_byte(PMBusDevice *pmdev)
|
||||
{
|
||||
ISLState *s = ISL69260(pmdev);
|
||||
|
||||
switch (pmdev->code) {
|
||||
case PMBUS_IC_DEVICE_ID:
|
||||
if (!s->ic_device_id_len) {
|
||||
break;
|
||||
}
|
||||
pmbus_send(pmdev, s->ic_device_id, s->ic_device_id_len);
|
||||
pmbus_idle(pmdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: reading from unsupported register: 0x%02x\n",
|
||||
__func__, pmdev->code);
|
||||
@ -107,6 +119,18 @@ static void raa228000_exit_reset(Object *obj)
|
||||
pmdev->pages[0].read_temperature_3 = 0;
|
||||
}
|
||||
|
||||
static void isl69259_exit_reset(Object *obj)
|
||||
{
|
||||
ISLState *s = ISL69260(obj);
|
||||
static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c};
|
||||
g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id));
|
||||
|
||||
isl_pmbus_vr_exit_reset(obj);
|
||||
|
||||
s->ic_device_id_len = sizeof(ic_device_id);
|
||||
memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id));
|
||||
}
|
||||
|
||||
static void isl_pmbus_vr_add_props(Object *obj, uint64_t *flags, uint8_t pages)
|
||||
{
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
@ -245,6 +269,21 @@ static void raa229004_class_init(ObjectClass *klass, void *data)
|
||||
isl_pmbus_vr_class_init(klass, data, 2);
|
||||
}
|
||||
|
||||
static void isl69259_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->desc = "Renesas ISL69259 Digital Multiphase Voltage Regulator";
|
||||
rc->phases.exit = isl69259_exit_reset;
|
||||
isl_pmbus_vr_class_init(klass, data, 2);
|
||||
}
|
||||
|
||||
static const TypeInfo isl69259_info = {
|
||||
.name = TYPE_ISL69259,
|
||||
.parent = TYPE_ISL69260,
|
||||
.class_init = isl69259_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo isl69260_info = {
|
||||
.name = TYPE_ISL69260,
|
||||
.parent = TYPE_PMBUS_DEVICE,
|
||||
@ -271,6 +310,7 @@ static const TypeInfo raa228000_info = {
|
||||
|
||||
static void isl_pmbus_vr_register_types(void)
|
||||
{
|
||||
type_register_static(&isl69259_info);
|
||||
type_register_static(&isl69260_info);
|
||||
type_register_static(&raa228000_info);
|
||||
type_register_static(&raa229004_info);
|
||||
|
@ -36,12 +36,14 @@
|
||||
#include "hw/misc/aspeed_lpc.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/misc/aspeed_peci.h"
|
||||
#include "hw/char/serial.h"
|
||||
|
||||
#define ASPEED_SPIS_NUM 2
|
||||
#define ASPEED_EHCIS_NUM 2
|
||||
#define ASPEED_WDTS_NUM 4
|
||||
#define ASPEED_CPUS_NUM 2
|
||||
#define ASPEED_MACS_NUM 4
|
||||
#define ASPEED_UARTS_NUM 13
|
||||
|
||||
struct AspeedSoCState {
|
||||
/*< private >*/
|
||||
@ -79,7 +81,7 @@ struct AspeedSoCState {
|
||||
AspeedSDHCIState emmc;
|
||||
AspeedLPCState lpc;
|
||||
AspeedPECIState peci;
|
||||
uint32_t uart_default;
|
||||
SerialMM uart[ASPEED_UARTS_NUM];
|
||||
Clock *sysclk;
|
||||
UnimplementedDeviceState iomem;
|
||||
UnimplementedDeviceState video;
|
||||
@ -175,11 +177,14 @@ enum {
|
||||
};
|
||||
|
||||
qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);
|
||||
void aspeed_soc_uart_init(AspeedSoCState *s);
|
||||
bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp);
|
||||
void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr);
|
||||
bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp);
|
||||
void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr);
|
||||
void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev,
|
||||
const char *name, hwaddr addr,
|
||||
uint64_t size);
|
||||
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
unsigned int count, int unit0);
|
||||
|
||||
#endif /* ASPEED_SOC_H */
|
||||
|
@ -155,6 +155,7 @@ enum pmbus_registers {
|
||||
PMBUS_MFR_MAX_TEMP_1 = 0xC0, /* R/W word */
|
||||
PMBUS_MFR_MAX_TEMP_2 = 0xC1, /* R/W word */
|
||||
PMBUS_MFR_MAX_TEMP_3 = 0xC2, /* R/W word */
|
||||
PMBUS_IDLE_STATE = 0xFF,
|
||||
};
|
||||
|
||||
/* STATUS_WORD */
|
||||
@ -527,6 +528,12 @@ int pmbus_page_config(PMBusDevice *pmdev, uint8_t page_index, uint64_t flags);
|
||||
*/
|
||||
void pmbus_check_limits(PMBusDevice *pmdev);
|
||||
|
||||
/**
|
||||
* Enter an idle state where only the PMBUS_ERR_BYTE will be returned
|
||||
* indefinitely until a new command is issued.
|
||||
*/
|
||||
void pmbus_idle(PMBusDevice *pmdev);
|
||||
|
||||
extern const VMStateDescription vmstate_pmbus_device;
|
||||
|
||||
#define VMSTATE_PMBUS_DEVICE(_field, _state) { \
|
||||
|
@ -17,9 +17,22 @@ OBJECT_DECLARE_TYPE(AspeedSBCState, AspeedSBCClass, ASPEED_SBC)
|
||||
|
||||
#define ASPEED_SBC_NR_REGS (0x93c >> 2)
|
||||
|
||||
#define QSR_AES BIT(27)
|
||||
#define QSR_RSA1024 (0x0 << 12)
|
||||
#define QSR_RSA2048 (0x1 << 12)
|
||||
#define QSR_RSA3072 (0x2 << 12)
|
||||
#define QSR_RSA4096 (0x3 << 12)
|
||||
#define QSR_SHA224 (0x0 << 10)
|
||||
#define QSR_SHA256 (0x1 << 10)
|
||||
#define QSR_SHA384 (0x2 << 10)
|
||||
#define QSR_SHA512 (0x3 << 10)
|
||||
|
||||
struct AspeedSBCState {
|
||||
SysBusDevice parent;
|
||||
|
||||
bool emmc_abr;
|
||||
uint32_t signing_settings;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t regs[ASPEED_SBC_NR_REGS];
|
||||
|
@ -12,12 +12,17 @@
|
||||
#include "hw/i2c/pmbus_device.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_ISL69259 "isl69259"
|
||||
#define TYPE_ISL69260 "isl69260"
|
||||
#define TYPE_RAA228000 "raa228000"
|
||||
#define TYPE_RAA229004 "raa229004"
|
||||
#define ISL_MAX_IC_DEVICE_ID_LEN 16
|
||||
|
||||
struct ISLState {
|
||||
PMBusDevice parent;
|
||||
|
||||
uint8_t ic_device_id[ISL_MAX_IC_DEVICE_ID_LEN];
|
||||
uint8_t ic_device_id_len;
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ISLState, ISL69260)
|
||||
|
@ -170,3 +170,71 @@ class AST2x00Machine(QemuSystemTest):
|
||||
exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
|
||||
|
||||
self.do_test_arm_aspeed_buidroot_poweroff()
|
||||
|
||||
|
||||
def do_test_arm_aspeed_sdk_start(self, image, cpu_id):
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
|
||||
'-net', 'nic', '-net', 'user')
|
||||
self.vm.launch()
|
||||
|
||||
self.wait_for_console_pattern('U-Boot 2019.04')
|
||||
self.wait_for_console_pattern('## Loading kernel from FIT Image')
|
||||
self.wait_for_console_pattern('Starting kernel ...')
|
||||
self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
|
||||
|
||||
def test_arm_ast2500_evb_sdk(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:ast2500-evb
|
||||
"""
|
||||
|
||||
image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
|
||||
'download/v08.01/ast2500-default-obmc.tar.gz')
|
||||
image_hash = ('5375f82b4c43a79427909342a1e18b4e48bd663e38466862145d27bb358796fd')
|
||||
image_path = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
archive.extract(image_path, self.workdir)
|
||||
|
||||
self.do_test_arm_aspeed_sdk_start(
|
||||
self.workdir + '/ast2500-default/image-bmc', '0x0')
|
||||
self.wait_for_console_pattern('ast2500-default login:')
|
||||
|
||||
def test_arm_ast2600_evb_sdk(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:ast2600-evb
|
||||
"""
|
||||
|
||||
image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
|
||||
'download/v08.01/ast2600-default-obmc.tar.gz')
|
||||
image_hash = ('f12ef15e8c1f03a214df3b91c814515c5e2b2f56119021398c1dbdd626817d15')
|
||||
image_path = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
archive.extract(image_path, self.workdir)
|
||||
|
||||
self.vm.add_args('-device',
|
||||
'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test');
|
||||
self.vm.add_args('-device',
|
||||
'ds1338,bus=aspeed.i2c.bus.5,address=0x32');
|
||||
self.do_test_arm_aspeed_sdk_start(
|
||||
self.workdir + '/ast2600-default/image-bmc', '0xf00')
|
||||
self.wait_for_console_pattern('ast2600-default login:')
|
||||
exec_command_and_wait_for_pattern(self, 'root', 'Password:')
|
||||
exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-default:~#')
|
||||
|
||||
exec_command_and_wait_for_pattern(self,
|
||||
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device',
|
||||
'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d');
|
||||
exec_command_and_wait_for_pattern(self,
|
||||
'cat /sys/class/hwmon/hwmon19/temp1_input', '0')
|
||||
self.vm.command('qom-set', path='/machine/peripheral/tmp-test',
|
||||
property='temperature', value=18000);
|
||||
exec_command_and_wait_for_pattern(self,
|
||||
'cat /sys/class/hwmon/hwmon19/temp1_input', '18000')
|
||||
|
||||
exec_command_and_wait_for_pattern(self,
|
||||
'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device',
|
||||
'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
|
||||
year = time.strftime("%Y")
|
||||
exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
|
||||
|
@ -28,6 +28,11 @@
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "libqtest-single.h"
|
||||
|
||||
#define AST2600_GPIO_BASE 0x1E780000
|
||||
|
||||
#define GPIO_ABCD_DATA_VALUE 0x000
|
||||
#define GPIO_ABCD_DIRECTION 0x004
|
||||
|
||||
static void test_set_colocated_pins(const void *data)
|
||||
{
|
||||
QTestState *s = (QTestState *)data;
|
||||
@ -46,6 +51,27 @@ static void test_set_colocated_pins(const void *data)
|
||||
g_assert(!qtest_qom_get_bool(s, "/machine/soc/gpio", "gpioV7"));
|
||||
}
|
||||
|
||||
static void test_set_input_pins(const void *data)
|
||||
{
|
||||
QTestState *s = (QTestState *)data;
|
||||
char name[16];
|
||||
uint32_t value;
|
||||
|
||||
qtest_writel(s, AST2600_GPIO_BASE + GPIO_ABCD_DIRECTION, 0x00000000);
|
||||
for (char c = 'A'; c <= 'D'; c++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sprintf(name, "gpio%c%d", c, i);
|
||||
qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
|
||||
}
|
||||
}
|
||||
value = qtest_readl(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE);
|
||||
g_assert_cmphex(value, ==, 0xffffffff);
|
||||
|
||||
qtest_writel(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE, 0x00000000);
|
||||
value = qtest_readl(s, AST2600_GPIO_BASE + GPIO_ABCD_DATA_VALUE);
|
||||
g_assert_cmphex(value, ==, 0xffffffff);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QTestState *s;
|
||||
@ -56,6 +82,7 @@ int main(int argc, char **argv)
|
||||
s = qtest_init("-machine ast2600-evb");
|
||||
qtest_add_data_func("/ast2600/gpio/set_colocated_pins", s,
|
||||
test_set_colocated_pins);
|
||||
qtest_add_data_func("/ast2600/gpio/set_input_pins", s, test_set_input_pins);
|
||||
r = g_test_run();
|
||||
qtest_quit(s);
|
||||
|
||||
|
@ -192,6 +192,24 @@ static void read_page_mem(uint32_t addr, uint32_t *page)
|
||||
}
|
||||
}
|
||||
|
||||
static void write_page_mem(uint32_t addr, uint32_t write_value)
|
||||
{
|
||||
spi_ctrl_setmode(CTRL_WRITEMODE, PP);
|
||||
|
||||
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
|
||||
writel(ASPEED_FLASH_BASE + addr + i * 4, write_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void assert_page_mem(uint32_t addr, uint32_t expected_value)
|
||||
{
|
||||
uint32_t page[FLASH_PAGE_SIZE / 4];
|
||||
read_page_mem(addr, page);
|
||||
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
|
||||
g_assert_cmphex(page[i], ==, expected_value);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_erase_sector(void)
|
||||
{
|
||||
uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
|
||||
@ -501,6 +519,95 @@ static void test_status_reg_write_protection(void)
|
||||
flash_reset();
|
||||
}
|
||||
|
||||
static void test_write_block_protect(void)
|
||||
{
|
||||
uint32_t sector_size = 65536;
|
||||
uint32_t n_sectors = 512;
|
||||
|
||||
spi_ce_ctrl(1 << CRTL_EXTENDED0);
|
||||
spi_conf(CONF_ENABLE_W0);
|
||||
|
||||
uint32_t bp_bits = 0b0;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
|
||||
|
||||
spi_ctrl_start_user();
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
writeb(ASPEED_FLASH_BASE, WRSR);
|
||||
writeb(ASPEED_FLASH_BASE, bp_bits);
|
||||
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
spi_ctrl_stop_user();
|
||||
|
||||
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
|
||||
uint32_t protection_start = n_sectors - num_protected_sectors;
|
||||
uint32_t protection_end = n_sectors;
|
||||
|
||||
for (int sector = 0; sector < n_sectors; sector++) {
|
||||
uint32_t addr = sector * sector_size;
|
||||
|
||||
assert_page_mem(addr, 0xffffffff);
|
||||
write_page_mem(addr, make_be32(0xabcdef12));
|
||||
|
||||
uint32_t expected_value = protection_start <= sector
|
||||
&& sector < protection_end
|
||||
? 0xffffffff : 0xabcdef12;
|
||||
|
||||
assert_page_mem(addr, expected_value);
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset();
|
||||
}
|
||||
|
||||
static void test_write_block_protect_bottom_bit(void)
|
||||
{
|
||||
uint32_t sector_size = 65536;
|
||||
uint32_t n_sectors = 512;
|
||||
|
||||
spi_ce_ctrl(1 << CRTL_EXTENDED0);
|
||||
spi_conf(CONF_ENABLE_W0);
|
||||
|
||||
/* top bottom bit is enabled */
|
||||
uint32_t bp_bits = 0b00100 << 3;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
|
||||
|
||||
spi_ctrl_start_user();
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
writeb(ASPEED_FLASH_BASE, WRSR);
|
||||
writeb(ASPEED_FLASH_BASE, bp_bits);
|
||||
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
||||
writeb(ASPEED_FLASH_BASE, WREN);
|
||||
spi_ctrl_stop_user();
|
||||
|
||||
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
|
||||
uint32_t protection_start = 0;
|
||||
uint32_t protection_end = num_protected_sectors;
|
||||
|
||||
for (int sector = 0; sector < n_sectors; sector++) {
|
||||
uint32_t addr = sector * sector_size;
|
||||
|
||||
assert_page_mem(addr, 0xffffffff);
|
||||
write_page_mem(addr, make_be32(0xabcdef12));
|
||||
|
||||
uint32_t expected_value = protection_start <= sector
|
||||
&& sector < protection_end
|
||||
? 0xffffffff : 0xabcdef12;
|
||||
|
||||
assert_page_mem(addr, expected_value);
|
||||
}
|
||||
}
|
||||
|
||||
flash_reset();
|
||||
}
|
||||
|
||||
static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@ -529,6 +636,10 @@ int main(int argc, char **argv)
|
||||
qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
|
||||
qtest_add_func("/ast2400/smc/status_reg_write_protection",
|
||||
test_status_reg_write_protection);
|
||||
qtest_add_func("/ast2400/smc/write_block_protect",
|
||||
test_write_block_protect);
|
||||
qtest_add_func("/ast2400/smc/write_block_protect_bottom_bit",
|
||||
test_write_block_protect_bottom_bit);
|
||||
|
||||
flash_reset();
|
||||
ret = g_test_run();
|
||||
|
Loading…
Reference in New Issue
Block a user