* [PATCH v2 00/18] Fix write incorrect data into flash in user mode
@ 2024-10-22 9:40 Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
` (18 more replies)
0 siblings, 19 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
change from v1:
1. Fix write incorrect data into flash in user mode.
2. Refactor aspeed smc qtest testcases to support AST2600, AST2500 and
AST1030.
3. Add ast2700 smc qtest testcase to support AST2700.
change from v2:
1. Introduce a new aspeed-smc-utils.c to place common testcases.
2. Fix hardcode attach flash model of spi controllers
3. Add reviewers suggestion and fix review issue.
QEMU version: https://github.com/qemu/qemu/commit/95a16ee753d6da651fce8df876333bf7fcf134d9
Depend patch series:
To successfully apply this patch series, it is required to apply this
patch series first, https://patchwork.kernel.org/project/qemu-devel/list/?series=894520
Jamin Lin (18):
aspeed/smc: Fix write incorrect data into flash in user mode
hw/block:m25p80: Fix coding style
hw/block:m25p80: Support write status register 2 command (0x31) for
w25q01jvq
hw/block/m25p80: Add SFDP table for w25q80bl flash
hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB.
hw/arm/aspeed: Correct fmc_model w25q80bl for ast1030-a1 EVB
aspeed: Fix hardcode attach flash model of spi controllers
test/qtest/aspeed_smc-test: Fix coding style
test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc
function
test/qtest/aspeed_smc-test: Introduce a new TestData to test different
BMC SOCs
test/qtest/aspeed_smc-test: Support to test all CE pins
test/qtest/aspeed_smc-test: Introducing a "page_addr" data field
test/qtest/aspeed_smc-test: Support to test AST2500
test/qtest/aspeed_smc-test: Support to test AST2600
test/qtest/aspeed_smc-test: Support to test AST1030
test/qtest/aspeed_smc-test: Support write page command with QPI mode
test/qtest: Introduce a new aspeed-smc-utils.c to place common
testcases
test/qtest/ast2700-smc-test: Support to test AST2700
hw/arm/aspeed.c | 25 +-
hw/block/m25p80.c | 63 ++-
hw/block/m25p80_sfdp.c | 36 ++
hw/block/m25p80_sfdp.h | 2 +-
hw/ssi/aspeed_smc.c | 40 +-
include/hw/ssi/aspeed_smc.h | 1 +
tests/qtest/aspeed-smc-utils.c | 681 +++++++++++++++++++++++++++++
tests/qtest/aspeed-smc-utils.h | 95 +++++
tests/qtest/aspeed_smc-test.c | 757 +++++++--------------------------
tests/qtest/ast2700-smc-test.c | 67 +++
tests/qtest/meson.build | 5 +-
11 files changed, 1143 insertions(+), 629 deletions(-)
create mode 100644 tests/qtest/aspeed-smc-utils.c
create mode 100644 tests/qtest/aspeed-smc-utils.h
create mode 100644 tests/qtest/ast2700-smc-test.c
--
2.34.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 10:49 ` Kevin Wolf
2024-10-22 9:40 ` [PATCH v2 02/18] hw/block:m25p80: Fix coding style Jamin Lin via
` (17 subsequent siblings)
18 siblings, 2 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
According to the design of ASPEED SPI controllers user mode, users write the
data to flash, the SPI drivers set the Control Register(0x10) bit 0 and 1
enter user mode. Then, SPI drivers send flash commands for writing data.
Finally, SPI drivers set the Control Register (0x10) bit 2 to stop
active control and restore bit 0 and 1.
According to the design of ASPEED SMC model, firmware writes the
Control Register and the "aspeed_smc_flash_update_ctrl" function is called.
Then, this function verify Control Register(0x10) bit 0 and 1. If it set user
mode, the value of s->snoop_index is SNOOP_START else SNOOP_OFF.
If s->snoop_index is SNOOP_START, the "aspeed_smc_do_snoop" function verify
the first incomming data is a new flash command and writes the corresponding
dummy bytes if need.
However, it did not check the current unselect status. If current unselect
status is "false" and firmware set the IO MODE by Control Register bit 31:28,
the value of s->snoop_index will be changed to SNOOP_START again and
"aspeed_smc_do_snoop" misunderstand that the incomming data is the new flash
command and it causes writing unexpected data into flash.
Example:
1. Firmware set user mode by Control Register bit 0 and 1(0x03)
2. SMC model set s->snoop SNOOP_START
3. Firmware set Quad Page Program with 4-Byte Address command (0x34)
4. SMC model verify this flash command and it needs 4 dummy bytes.
5. Firmware send 4 bytes address.
6. SMC model receives 4 bytes address
7. Firmware set QPI IO MODE by Control Register bit 31. (0x80000003)
8. SMC model verify new user mode by Control Register bit 0 and 1.
Then, set s->snoop SNOOP_START again. (It is the wrong behavior.)
9. Firmware send 0xebd8c134 data and it should be written into flash.
However, SMC model misunderstand that the first incoming data, 0x34,
is the new command because the value of s->snoop is changed to SNOOP_START.
Finally, SMC sned the incorrect data to flash model.
Introduce a new unselect attribute in AspeedSMCState to save the current
unselect status for user mode and set it "true" by default.
Update "aspeed_smc_flash_update_ctrl" function to check the previous unselect
status. If both new unselect status and previous unselect status is different,
update s->snoop_index value and call "aspeed_smc_flash_do_select".
Increase VMStateDescription version.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/ssi/aspeed_smc.c | 40 ++++++++++++++++++++++++++-----------
include/hw/ssi/aspeed_smc.h | 1 +
2 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index e3fdc66cb2..7b0f6599f9 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -417,7 +417,7 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect)
AspeedSMCState *s = fl->controller;
trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : "");
-
+ s->unselect = unselect;
qemu_set_irq(s->cs_lines[fl->cs], unselect);
}
@@ -677,22 +677,35 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value)
{
AspeedSMCState *s = fl->controller;
- bool unselect;
+ bool unselect = false;
+ uint32_t old_mode;
+ uint32_t new_mode;
+
+ old_mode = s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK;
+ new_mode = value & CTRL_CMD_MODE_MASK;
- /* User mode selects the CS, other modes unselect */
- unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE;
+ if (old_mode == CTRL_USERMODE) {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
- /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
- if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
- value & CTRL_CE_STOP_ACTIVE) {
- unselect = true;
+ /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
+ if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
+ value & CTRL_CE_STOP_ACTIVE) {
+ unselect = true;
+ }
+ } else {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
}
s->regs[s->r_ctrl0 + fl->cs] = value;
- s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
-
- aspeed_smc_flash_do_select(fl, unselect);
+ if (unselect != s->unselect) {
+ s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
+ aspeed_smc_flash_do_select(fl, unselect);
+ }
}
static void aspeed_smc_reset(DeviceState *d)
@@ -729,6 +742,8 @@ static void aspeed_smc_reset(DeviceState *d)
qemu_set_irq(s->cs_lines[i], true);
}
+ s->unselect = true;
+
/* setup the default segment register values and regions for all */
for (i = 0; i < asc->cs_num_max; ++i) {
aspeed_smc_flash_set_segment_region(s, i,
@@ -1261,12 +1276,13 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_smc = {
.name = "aspeed.smc",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
VMSTATE_UINT8(snoop_index, AspeedSMCState),
VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
+ VMSTATE_BOOL(unselect, AspeedSMCState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 234dca32b0..25b95e7406 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -82,6 +82,7 @@ struct AspeedSMCState {
uint8_t snoop_index;
uint8_t snoop_dummies;
+ bool unselect;
};
typedef struct AspeedSegments {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 02/18] hw/block:m25p80: Fix coding style
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-11-15 16:44 ` Philippe Mathieu-Daudé
2024-10-22 9:40 ` [PATCH v2 03/18] hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq Jamin Lin via
` (16 subsequent siblings)
18 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Fix coding style issues from checkpatch.pl
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/block/m25p80.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index f7123f9e68..3f55b8f385 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -61,7 +61,8 @@ typedef struct FlashPartInfo {
*/
uint8_t id[SPI_NOR_MAX_ID_LEN];
uint8_t id_len;
- /* there is confusion between manufacturers as to what a sector is. In this
+ /*
+ * there is confusion between manufacturers as to what a sector is. In this
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
* command (opcode 0xd8).
*/
@@ -168,7 +169,7 @@ typedef struct FlashPartInfo {
/*
* Spansion read mode command length in bytes,
* the mode is currently not supported.
-*/
+ */
#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1
#define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1
@@ -189,7 +190,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
- /* Atmel EEPROMS - it is assumed, that don't care bit in command
+ /*
+ * Atmel EEPROMS - it is assumed, that don't care bit in command
* is set to 0. Block protection is not supported.
*/
{ INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
@@ -275,10 +277,13 @@ static const FlashPartInfo known_devices[] = {
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
- { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
- { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
- /* Spansion -- single (large) sector size only, at least
+ /*
+ * Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
{ INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) },
@@ -549,7 +554,8 @@ static void blk_sync_complete(void *opaque, int ret)
qemu_iovec_destroy(iov);
g_free(iov);
- /* do nothing. Masters do not directly interact with the backing store,
+ /*
+ * do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required.
*/
}
@@ -1843,7 +1849,7 @@ static void m25p80_register_types(void)
type_register_static(&m25p80_info);
for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
- TypeInfo ti = {
+ const TypeInfo ti = {
.name = known_devices[i].part_name,
.parent = TYPE_M25P80,
.class_init = m25p80_class_init,
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 03/18] hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 02/18] hw/block:m25p80: Fix coding style Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 04/18] hw/block/m25p80: Add SFDP table for w25q80bl flash Jamin Lin via
` (15 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
According to the w25q01jv datasheet at page 16, it is required to set QE bit
in "Status Register 2" to enable quad mode.
Currently, m25p80 support users utilize "Write Status Register 1(0x01)" command
to set QE bit in "Status Register 2" and utilize "Read Status Register 2(0x35)"
command to get the QE bit status.
However, some firmware directly utilize "Status Register 2(0x31)" command to
set QE bit. To fully support quad mode for w25q01jvq, adds WRSR2 command.
Update collecting data needed 1 byte for WRSR2 command in decode_new_cmd
function and verify QE bit at the first byte of collecting data bit 2 in
complete_collecting_data.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/block/m25p80.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 3f55b8f385..411d810d3b 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -430,6 +430,11 @@ typedef enum {
RDCR_EQIO = 0x35,
RSTQIO = 0xf5,
+ /*
+ * Winbond: 0x31 - write status register 2
+ */
+ WRSR2 = 0x31,
+
RNVCR = 0xB5,
WNVCR = 0xB1,
@@ -821,6 +826,15 @@ static void complete_collecting_data(Flash *s)
s->write_enable = false;
}
break;
+ case WRSR2:
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->quad_enable = !!(s->data[0] & 0x02);
+ break;
+ default:
+ break;
+ }
+ break;
case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
@@ -1280,7 +1294,31 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
break;
+ case WRSR2:
+ /*
+ * If WP# is low and status_register_write_disabled is high,
+ * status register writes are disabled.
+ * This is also called "hardware protected mode" (HPM). All other
+ * combinations of the two states are called "software protected mode"
+ * (SPM), and status register writes are permitted.
+ */
+ if ((s->wp_level == 0 && s->status_register_write_disabled)
+ || !s->write_enable) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Status register 2 write is disabled!\n");
+ break;
+ }
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->needed_bytes = 1;
+ s->state = STATE_COLLECTING_DATA;
+ s->pos = 0;
+ break;
+ default:
+ break;
+ }
+ break;
case WRDI:
s->write_enable = false;
if (get_man(s) == MAN_SST) {
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 04/18] hw/block/m25p80: Add SFDP table for w25q80bl flash
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (2 preceding siblings ...)
2024-10-22 9:40 ` [PATCH v2 03/18] hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 05/18] hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB Jamin Lin via
` (14 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Add the SFDP table for the Windbond w25q80bl flash.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/block/m25p80.c | 3 ++-
hw/block/m25p80_sfdp.c | 36 ++++++++++++++++++++++++++++++++++++
hw/block/m25p80_sfdp.h | 2 +-
3 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 411d810d3b..e2e84f8b5f 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -356,7 +356,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
+ { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K),
+ .sfdp_read = m25p80_sfdp_w25q80bl },
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K),
.sfdp_read = m25p80_sfdp_w25q256 },
{ INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K),
diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c
index 82d84cc21f..a03a291a09 100644
--- a/hw/block/m25p80_sfdp.c
+++ b/hw/block/m25p80_sfdp.c
@@ -404,6 +404,42 @@ static const uint8_t sfdp_w25q01jvq[] = {
};
define_sfdp_read(w25q01jvq);
+static const uint8_t sfdp_w25q80bl[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x05, 0x01, 0x00, 0xff,
+ 0x00, 0x05, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0x00,
+ 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x0f, 0x52,
+ 0x10, 0xd8, 0x00, 0x00, 0x23, 0x02, 0xa6, 0x00,
+ 0x81, 0x6c, 0x14, 0xa7, 0xed, 0x61, 0x76, 0x33,
+ 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c,
+ 0x00, 0xf7, 0x1d, 0xff, 0xe9, 0x30, 0xc0, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+define_sfdp_read(w25q80bl);
+
/*
* Integrated Silicon Solution (ISSI)
*/
diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h
index 89c2d8f72d..35785686a0 100644
--- a/hw/block/m25p80_sfdp.h
+++ b/hw/block/m25p80_sfdp.h
@@ -25,7 +25,7 @@ uint8_t m25p80_sfdp_mx66l1g45g(uint32_t addr);
uint8_t m25p80_sfdp_w25q256(uint32_t addr);
uint8_t m25p80_sfdp_w25q512jv(uint32_t addr);
-
+uint8_t m25p80_sfdp_w25q80bl(uint32_t addr);
uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr);
uint8_t m25p80_sfdp_is25wp256(uint32_t addr);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 05/18] hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB.
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (3 preceding siblings ...)
2024-10-22 9:40 ` [PATCH v2 04/18] hw/block/m25p80: Add SFDP table for w25q80bl flash Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 06/18] hw/arm/aspeed: Correct fmc_model w25q80bl " Jamin Lin via
` (13 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Currently, the default spi_model was "sst25vf032b" whose size was 4MB for
ast1030-a1 EVB. However, according to the schematic of ast1030-a1 EVB,
ASPEED shipped default flash of spi1 and spi2 were w25q256 whose size
was 32MB.
Correct spi_model default flash to w25q256 for ast1030-a1 EVB.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/arm/aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index cf0c6c580b..bf68224295 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1643,7 +1643,7 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
amc->i2c_init = ast1030_evb_i2c_init;
mc->default_ram_size = 0;
amc->fmc_model = "sst25vf032b";
- amc->spi_model = "sst25vf032b";
+ amc->spi_model = "w25q256";
amc->num_cs = 2;
amc->macs_mask = 0;
aspeed_machine_class_init_cpus_defaults(mc);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 06/18] hw/arm/aspeed: Correct fmc_model w25q80bl for ast1030-a1 EVB
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (4 preceding siblings ...)
2024-10-22 9:40 ` [PATCH v2 05/18] hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers Jamin Lin via
` (12 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Currently, the default fmc_model was "sst25vf032b" whose size was 4MB for
ast1030-a1 EVB. However, according to the schematic of ast1030-a1 EVB,
ASPEED shipped default flash of fmc_cs0 and fmc_cs1 were "w25q80bl" and
"w25q256", respectively. The size of w25q80bl is 1MB and the size of w25q256
is 32MB.
The fmc_cs0 was connected to AST1030 A1 internal flash and the fmc_cs1 was
connected to external flash. The internal flash could not be changed because
it was placed into AST1030 A1 chip. Users only can change fmc_cs1 external
flash.
So far, only supports to set the default fmc_model for all chip select pins.
In other words, users cannot set the different default flash model for
fmc_cs0 and fmc_cs1, respectively.
Correct fmc_model default flash to w25q80bl the same as AST1030 A1
internal flash for ast1030-a1 EVB.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/arm/aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index bf68224295..b4b1ce9efb 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1642,7 +1642,7 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
mc->init = aspeed_minibmc_machine_init;
amc->i2c_init = ast1030_evb_i2c_init;
mc->default_ram_size = 0;
- amc->fmc_model = "sst25vf032b";
+ amc->fmc_model = "w25q80bl";
amc->spi_model = "w25q256";
amc->num_cs = 2;
amc->macs_mask = 0;
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (5 preceding siblings ...)
2024-10-22 9:40 ` [PATCH v2 06/18] hw/arm/aspeed: Correct fmc_model w25q80bl " Jamin Lin via
@ 2024-10-22 9:40 ` Jamin Lin via
2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 9:41 ` [PATCH v2 08/18] test/qtest/aspeed_smc-test: Fix coding style Jamin Lin via
` (11 subsequent siblings)
18 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
It only attached flash model of fmc and spi[0] in aspeed_machine_init function.
However, AST2500 and AST2600 have one fmc and two spi(spi1 and spi2)
controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2) controllers.
Besides, it used hardcode to attach flash model of fmc, spi[0] and spi[1] in
aspeed_minibmc_machine_init for AST1030.
To make both functions more flexible and support all ASPEED SOCs spi
controllers, adds a for loop with sc->spis_num to attach flash model of
all supported spi controllers. The sc->spis_num is from AspeedSoCClass.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/arm/aspeed.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index b4b1ce9efb..7ac01a3562 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState *machine)
aspeed_board_init_flashes(&bmc->soc->fmc,
bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
amc->num_cs, 0);
- aspeed_board_init_flashes(&bmc->soc->spi[0],
- bmc->spi_model ? bmc->spi_model : amc->spi_model,
- 1, amc->num_cs);
+ for (i = 0; i < sc->spis_num; i++) {
+ aspeed_board_init_flashes(&bmc->soc->spi[i],
+ bmc->spi_model ? bmc->spi_model : amc->spi_model,
+ amc->num_cs, amc->num_cs + (amc->num_cs * i));
+ }
}
if (machine->kernel_filename && sc->num_cpus > 1) {
@@ -1579,7 +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
{
AspeedMachineState *bmc = ASPEED_MACHINE(machine);
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
+ AspeedSoCClass *sc;
Clock *sysclk;
+ int i;
sysclk = clock_new(OBJECT(machine), "SYSCLK");
clock_set_hz(sysclk, SYSCLK_FRQ);
@@ -1587,6 +1591,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
object_property_add_child(OBJECT(machine), "soc", OBJECT(bmc->soc));
object_unref(OBJECT(bmc->soc));
+ sc = ASPEED_SOC_GET_CLASS(bmc->soc);
qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
object_property_set_link(OBJECT(bmc->soc), "memory",
@@ -1599,13 +1604,11 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
amc->num_cs,
0);
- aspeed_board_init_flashes(&bmc->soc->spi[0],
- bmc->spi_model ? bmc->spi_model : amc->spi_model,
- amc->num_cs, amc->num_cs);
-
- aspeed_board_init_flashes(&bmc->soc->spi[1],
+ for (i = 0; i < sc->spis_num; i++) {
+ aspeed_board_init_flashes(&bmc->soc->spi[i],
bmc->spi_model ? bmc->spi_model : amc->spi_model,
- amc->num_cs, (amc->num_cs * 2));
+ amc->num_cs, amc->num_cs + (amc->num_cs * i));
+ }
if (amc->i2c_init) {
amc->i2c_init(bmc);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 08/18] test/qtest/aspeed_smc-test: Fix coding style
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (6 preceding siblings ...)
2024-10-22 9:40 ` [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 09/18] test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc function Jamin Lin via
` (10 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Fix coding style issues from checkpatch.pl
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index c713a3700b..4673371d95 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -353,7 +353,8 @@ static void test_read_page_mem(void)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
@@ -394,7 +395,8 @@ static void test_write_page_mem(void)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 09/18] test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc function
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (7 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 08/18] test/qtest/aspeed_smc-test: Fix coding style Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 10/18] test/qtest/aspeed_smc-test: Introduce a new TestData to test different BMC SOCs Jamin Lin via
` (9 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
So far, the test cases are used for testing SMC model with AST2400 BMC.
However, AST2400 is end off live and ASPEED is no longer support this SOC.
To test SMC model for AST2500, AST2600 and AST1030, move the test cases
from main to test_palmetto_bmc function.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 4673371d95..ec1fa6ec15 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -610,14 +610,12 @@ static void test_write_block_protect_bottom_bit(void)
flash_reset();
}
-int main(int argc, char **argv)
+static int test_palmetto_bmc(void)
{
g_autofree char *tmp_path = NULL;
int ret;
int fd;
- g_test_init(&argc, &argv, NULL);
-
fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL);
g_assert(fd >= 0);
ret = ftruncate(fd, FLASH_SIZE);
@@ -644,8 +642,18 @@ int main(int argc, char **argv)
flash_reset();
ret = g_test_run();
-
qtest_quit(global_qtest);
unlink(tmp_path);
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ ret = test_palmetto_bmc();
+
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 10/18] test/qtest/aspeed_smc-test: Introduce a new TestData to test different BMC SOCs
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (8 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 09/18] test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc function Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 11/18] test/qtest/aspeed_smc-test: Support to test all CE pins Jamin Lin via
` (8 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Currently, these test cases are only used for testing fmc_cs0 for AST2400.
To test others BMC SOCs, introduces a new TestData structure.
Users can set the spi base address, flash base address, jedesc id and so on
for different BMC SOCs and flash model testing.
Introduce new helper functions to make the test case more readable.
Set spi base address 0x1E620000, flash_base address 0x20000000
and jedec id 0x20ba19 for fmc_cs0 with n25q256a flash for AST2400
SMC model testing.
To pass the TestData into the test case, replace qtest_add_func with
qtest_add_data_func.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 546 +++++++++++++++++++---------------
1 file changed, 299 insertions(+), 247 deletions(-)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index ec1fa6ec15..4c62009605 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -43,9 +43,6 @@
#define CTRL_USERMODE 0x3
#define SR_WEL BIT(1)
-#define ASPEED_FMC_BASE 0x1E620000
-#define ASPEED_FLASH_BASE 0x20000000
-
/*
* Flash commands
*/
@@ -65,11 +62,16 @@ enum {
ERASE_SECTOR = 0xd8,
};
-#define FLASH_JEDEC 0x20ba19 /* n25q256a */
-#define FLASH_SIZE (32 * 1024 * 1024)
-
#define FLASH_PAGE_SIZE 256
+typedef struct TestData {
+ QTestState *s;
+ uint64_t spi_base;
+ uint64_t flash_base;
+ uint32_t jedec_id;
+ char *tmp_path;
+} TestData;
+
/*
* Use an explicit bswap for the values read/wrote to the flash region
* as they are BE and the Aspeed CPU is LE.
@@ -79,275 +81,315 @@ static inline uint32_t make_be32(uint32_t data)
return bswap32(data);
}
-static void spi_conf(uint32_t value)
+static inline void spi_writel(const TestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->spi_base + offset, value);
+}
+
+static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
+{
+ return qtest_readl(data->s, data->spi_base + offset);
+}
+
+static inline void flash_writeb(const TestData *data, uint64_t offset,
+ uint8_t value)
+{
+ qtest_writeb(data->s, data->flash_base + offset, value);
+}
+
+static inline void flash_writel(const TestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->flash_base + offset, value);
+}
+
+static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
{
- uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
+ return qtest_readb(data->s, data->flash_base + offset);
+}
+
+static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
+{
+ return qtest_readl(data->s, data->flash_base + offset);
+}
+
+static void spi_conf(const TestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CONF);
conf |= value;
- writel(ASPEED_FMC_BASE + R_CONF, conf);
+ spi_writel(data, R_CONF, conf);
}
-static void spi_conf_remove(uint32_t value)
+static void spi_conf_remove(const TestData *data, uint32_t value)
{
- uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
+ uint32_t conf = spi_readl(data, R_CONF);
conf &= ~value;
- writel(ASPEED_FMC_BASE + R_CONF, conf);
+ spi_writel(data, R_CONF, conf);
}
-static void spi_ce_ctrl(uint32_t value)
+static void spi_ce_ctrl(const TestData *data, uint32_t value)
{
- uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
+ uint32_t conf = spi_readl(data, R_CE_CTRL);
conf |= value;
- writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
+ spi_writel(data, R_CE_CTRL, conf);
}
-static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
+static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
{
- uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+ uint32_t ctrl = spi_readl(data, R_CTRL0);
ctrl &= ~(CTRL_USERMODE | 0xff << 16);
ctrl |= mode | (cmd << 16);
- writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+ spi_writel(data, R_CTRL0, ctrl);
}
-static void spi_ctrl_start_user(void)
+static void spi_ctrl_start_user(const TestData *data)
{
- uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+ uint32_t ctrl = spi_readl(data, R_CTRL0);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+ spi_writel(data, R_CTRL0, ctrl);
ctrl &= ~CTRL_CE_STOP_ACTIVE;
- writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+ spi_writel(data, R_CTRL0, ctrl);
}
-static void spi_ctrl_stop_user(void)
+static void spi_ctrl_stop_user(const TestData *data)
{
- uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
+ uint32_t ctrl = spi_readl(data, R_CTRL0);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
+ spi_writel(data, R_CTRL0, ctrl);
}
-static void flash_reset(void)
+static void flash_reset(const TestData *data)
{
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(data, CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
- writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- writeb(ASPEED_FLASH_BASE, WRDI);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(data);
+ flash_writeb(data, 0, RESET_ENABLE);
+ flash_writeb(data, 0, RESET_MEMORY);
+ flash_writeb(data, 0, WREN);
+ flash_writeb(data, 0, BULK_ERASE);
+ flash_writeb(data, 0, WRDI);
+ spi_ctrl_stop_user(data);
- spi_conf_remove(CONF_ENABLE_W0);
+ spi_conf_remove(data, CONF_ENABLE_W0);
}
-static void test_read_jedec(void)
+static void test_read_jedec(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t jedec = 0x0;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, JEDEC_READ);
- jedec |= readb(ASPEED_FLASH_BASE) << 16;
- jedec |= readb(ASPEED_FLASH_BASE) << 8;
- jedec |= readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, JEDEC_READ);
+ jedec |= flash_readb(test_data, 0) << 16;
+ jedec |= flash_readb(test_data, 0) << 8;
+ jedec |= flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
- flash_reset();
+ flash_reset(test_data);
- g_assert_cmphex(jedec, ==, FLASH_JEDEC);
+ g_assert_cmphex(jedec, ==, test_data->jedec_id);
}
-static void read_page(uint32_t addr, uint32_t *page)
+static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
{
int i;
- spi_ctrl_start_user();
+ spi_ctrl_start_user(data);
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, READ);
- writel(ASPEED_FLASH_BASE, make_be32(addr));
+ flash_writeb(data, 0, EN_4BYTE_ADDR);
+ flash_writeb(data, 0, READ);
+ flash_writel(data, 0, make_be32(addr));
/* Continuous read are supported */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- page[i] = make_be32(readl(ASPEED_FLASH_BASE));
+ page[i] = make_be32(flash_readl(data, 0));
}
- spi_ctrl_stop_user();
+ spi_ctrl_stop_user(data);
}
-static void read_page_mem(uint32_t addr, uint32_t *page)
+static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
{
int i;
/* move out USER mode to use direct reads from the AHB bus */
- spi_ctrl_setmode(CTRL_READMODE, READ);
+ spi_ctrl_setmode(data, CTRL_READMODE, READ);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
+ page[i] = make_be32(flash_readl(data, addr + i * 4));
}
}
-static void write_page_mem(uint32_t addr, uint32_t write_value)
+static void write_page_mem(const TestData *data, uint32_t addr,
+ uint32_t write_value)
{
- spi_ctrl_setmode(CTRL_WRITEMODE, PP);
+ spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE + addr + i * 4, write_value);
+ flash_writel(data, addr + i * 4, write_value);
}
}
-static void assert_page_mem(uint32_t addr, uint32_t expected_value)
+static void assert_page_mem(const TestData *data, uint32_t addr,
+ uint32_t expected_value)
{
uint32_t page[FLASH_PAGE_SIZE / 4];
- read_page_mem(addr, page);
+ read_page_mem(data, 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)
+static void test_erase_sector(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
- read_page(some_page_addr - FLASH_PAGE_SIZE, page);
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, PP);
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
}
- spi_ctrl_stop_user();
+ spi_ctrl_stop_user(test_data);
/* Check the page is correctly written */
- read_page(some_page_addr, page);
+ read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, ERASE_SECTOR);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+ spi_ctrl_stop_user(test_data);
/* Check the page is erased */
- read_page(some_page_addr, page);
+ read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_erase_all(void)
+static void test_erase_all(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
- read_page(some_page_addr - FLASH_PAGE_SIZE, page);
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, PP);
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
}
- spi_ctrl_stop_user();
+ spi_ctrl_stop_user(test_data);
/* Check the page is correctly written */
- read_page(some_page_addr, page);
+ read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, BULK_ERASE);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ spi_ctrl_stop_user(test_data);
/* Check the page is erased */
- read_page(some_page_addr, page);
+ read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_write_page(void)
+static void test_write_page(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, PP);
- writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
- spi_ctrl_stop_user();
+ spi_ctrl_stop_user(test_data);
/* Check what was written */
- read_page(my_page_addr, page);
+ read_page(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
- read_page(some_page_addr, page);
+ read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_read_page_mem(void)
+static void test_read_page_mem(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
@@ -357,40 +399,41 @@ static void test_read_page_mem(void)
* Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
+ spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
/* Enable 4BYTE mode for flash. */
- spi_conf(CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, PP);
- writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
+ spi_conf(test_data, CONF_ENABLE_W0);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
- spi_ctrl_stop_user();
- spi_conf_remove(CONF_ENABLE_W0);
+ spi_ctrl_stop_user(test_data);
+ spi_conf_remove(test_data, CONF_ENABLE_W0);
/* Check what was written */
- read_page_mem(my_page_addr, page);
+ read_page_mem(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
- read_page_mem(some_page_addr, page);
+ read_page_mem(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_write_page_mem(void)
+static void test_write_page_mem(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -399,150 +442,153 @@ static void test_write_page_mem(void)
* Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
+ spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
/* Enable 4BYTE mode for flash. */
- spi_conf(CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
- writeb(ASPEED_FLASH_BASE, WREN);
- spi_ctrl_stop_user();
+ spi_conf(test_data, CONF_ENABLE_W0);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
/* move out USER mode to use direct writes to the AHB bus */
- spi_ctrl_setmode(CTRL_WRITEMODE, PP);
+ spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
+ flash_writel(test_data, my_page_addr + i * 4,
make_be32(my_page_addr + i * 4));
}
/* Check what was written */
- read_page_mem(my_page_addr, page);
+ read_page_mem(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_read_status_reg(void)
+static void test_read_status_reg(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint8_t r;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
g_assert(qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WRDI);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WRDI);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
- (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
- flash_reset();
+ flash_reset(test_data);
}
-static void test_status_reg_write_protection(void)
+static void test_status_reg_write_protection(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint8_t r;
- spi_conf(CONF_ENABLE_W0);
+ spi_conf(test_data, CONF_ENABLE_W0);
/* default case: WP# is high and SRWD is low -> status register writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, SRWD);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# high and SRWD high -> status register writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, 0);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, 0);
/* WP# low and SRWD low -> status register writable */
- qtest_set_irq_in(global_qtest,
+ qtest_set_irq_in(test_data->s,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, SRWD);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# low and SRWD high -> status register NOT writable */
- spi_ctrl_start_user();
- writeb(ASPEED_FLASH_BASE, WREN);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0 , WREN);
/* test ability to write SRWD */
- writeb(ASPEED_FLASH_BASE, WRSR);
- writeb(ASPEED_FLASH_BASE, 0);
- writeb(ASPEED_FLASH_BASE, RDSR);
- r = readb(ASPEED_FLASH_BASE);
- spi_ctrl_stop_user();
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
/* write is not successful */
g_assert_cmphex(r & SRWD, ==, SRWD);
- qtest_set_irq_in(global_qtest,
+ qtest_set_irq_in(test_data->s,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
- flash_reset();
+ flash_reset(test_data);
}
-static void test_write_block_protect(void)
+static void test_write_block_protect(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
- spi_conf(CONF_ENABLE_W0);
+ spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
+ spi_conf(test_data, 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();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = n_sectors - num_protected_sectors;
@@ -551,27 +597,28 @@ static void test_write_block_protect(void)
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));
+ assert_page_mem(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
- assert_page_mem(addr, expected_value);
+ assert_page_mem(test_data, addr, expected_value);
}
}
- flash_reset();
+ flash_reset(test_data);
}
-static void test_write_block_protect_bottom_bit(void)
+static void test_write_block_protect_bottom_bit(const void *data)
{
+ const TestData *test_data = (const TestData *)data;
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
- spi_ce_ctrl(1 << CRTL_EXTENDED0);
- spi_conf(CONF_ENABLE_W0);
+ spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
+ spi_conf(test_data, CONF_ENABLE_W0);
/* top bottom bit is enabled */
uint32_t bp_bits = 0b00100 << 3;
@@ -579,15 +626,15 @@ static void test_write_block_protect_bottom_bit(void)
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();
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = 0;
@@ -596,64 +643,69 @@ static void test_write_block_protect_bottom_bit(void)
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));
+ assert_page_mem(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
- assert_page_mem(addr, expected_value);
+ assert_page_mem(test_data, addr, expected_value);
}
}
- flash_reset();
+ flash_reset(test_data);
}
-static int test_palmetto_bmc(void)
+static void test_palmetto_bmc(TestData *data)
{
- g_autofree char *tmp_path = NULL;
int ret;
int fd;
- fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL);
+ fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL);
g_assert(fd >= 0);
- ret = ftruncate(fd, FLASH_SIZE);
+ ret = ftruncate(fd, 32 * 1024 * 1024);
g_assert(ret == 0);
close(fd);
- global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
- "-drive file=%s,format=raw,if=mtd",
- tmp_path);
-
- qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
- qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
- qtest_add_func("/ast2400/smc/erase_all", test_erase_all);
- qtest_add_func("/ast2400/smc/write_page", test_write_page);
- qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
- qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
- 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();
- qtest_quit(global_qtest);
- unlink(tmp_path);
-
- return ret;
+ data->s = qtest_initf("-m 256 -machine palmetto-bmc "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with n25q256a flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0x20ba19;
+
+ qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec);
+ qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector);
+ qtest_add_data_func("/ast2400/smc/erase_all", data, test_erase_all);
+ qtest_add_data_func("/ast2400/smc/write_page", data, test_write_page);
+ qtest_add_data_func("/ast2400/smc/read_page_mem",
+ data, test_read_page_mem);
+ qtest_add_data_func("/ast2400/smc/write_page_mem",
+ data, test_write_page_mem);
+ qtest_add_data_func("/ast2400/smc/read_status_reg",
+ data, test_read_status_reg);
+ qtest_add_data_func("/ast2400/smc/status_reg_write_protection",
+ data, test_status_reg_write_protection);
+ qtest_add_data_func("/ast2400/smc/write_block_protect",
+ data, test_write_block_protect);
+ qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit",
+ data, test_write_block_protect_bottom_bit);
}
int main(int argc, char **argv)
{
+ TestData palmetto_data;
int ret;
g_test_init(&argc, &argv, NULL);
- ret = test_palmetto_bmc();
+ test_palmetto_bmc(&palmetto_data);
+ ret = g_test_run();
+
+ qtest_quit(palmetto_data.s);
+ unlink(palmetto_data.tmp_path);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 11/18] test/qtest/aspeed_smc-test: Support to test all CE pins
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (9 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 10/18] test/qtest/aspeed_smc-test: Introduce a new TestData to test different BMC SOCs Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field Jamin Lin via
` (7 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Currently, these test cases only support to test CE0. To test all CE pins,
introduces new ce and node members in TestData structure. The ce member is used
for saving the ce index and node member is used for saving the node path,
respectively.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 77 ++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 37 deletions(-)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 4c62009605..b8ab20b43d 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -32,11 +32,11 @@
* ASPEED SPI Controller registers
*/
#define R_CONF 0x00
-#define CONF_ENABLE_W0 (1 << 16)
+#define CONF_ENABLE_W0 16
#define R_CE_CTRL 0x04
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
#define R_CTRL0 0x10
-#define CTRL_CE_STOP_ACTIVE (1 << 2)
+#define CTRL_CE_STOP_ACTIVE BIT(2)
#define CTRL_READMODE 0x0
#define CTRL_FREADMODE 0x1
#define CTRL_WRITEMODE 0x2
@@ -70,6 +70,8 @@ typedef struct TestData {
uint64_t flash_base;
uint32_t jedec_id;
char *tmp_path;
+ uint8_t cs;
+ const char *node;
} TestData;
/*
@@ -140,34 +142,37 @@ static void spi_ce_ctrl(const TestData *data, uint32_t value)
static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
{
- uint32_t ctrl = spi_readl(data, R_CTRL0);
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl &= ~(CTRL_USERMODE | 0xff << 16);
ctrl |= mode | (cmd << 16);
- spi_writel(data, R_CTRL0, ctrl);
+ spi_writel(data, ctrl_reg, ctrl);
}
static void spi_ctrl_start_user(const TestData *data)
{
- uint32_t ctrl = spi_readl(data, R_CTRL0);
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- spi_writel(data, R_CTRL0, ctrl);
+ spi_writel(data, ctrl_reg, ctrl);
ctrl &= ~CTRL_CE_STOP_ACTIVE;
- spi_writel(data, R_CTRL0, ctrl);
+ spi_writel(data, ctrl_reg, ctrl);
}
static void spi_ctrl_stop_user(const TestData *data)
{
- uint32_t ctrl = spi_readl(data, R_CTRL0);
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- spi_writel(data, R_CTRL0, ctrl);
+ spi_writel(data, ctrl_reg, ctrl);
}
static void flash_reset(const TestData *data)
{
- spi_conf(data, CONF_ENABLE_W0);
+ spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
spi_ctrl_start_user(data);
flash_writeb(data, 0, RESET_ENABLE);
@@ -177,7 +182,7 @@ static void flash_reset(const TestData *data)
flash_writeb(data, 0, WRDI);
spi_ctrl_stop_user(data);
- spi_conf_remove(data, CONF_ENABLE_W0);
+ spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
}
static void test_read_jedec(const void *data)
@@ -185,7 +190,7 @@ static void test_read_jedec(const void *data)
const TestData *test_data = (const TestData *)data;
uint32_t jedec = 0x0;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, JEDEC_READ);
@@ -255,7 +260,7 @@ static void test_erase_sector(const void *data)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/*
* Previous page should be full of 0xffs after backend is
@@ -307,7 +312,7 @@ static void test_erase_all(const void *data)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/*
* Previous page should be full of 0xffs after backend is
@@ -358,7 +363,7 @@ static void test_write_page(const void *data)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
@@ -396,13 +401,12 @@ static void test_read_page_mem(const void *data)
int i;
/*
- * Enable 4BYTE mode for controller. This is should be strapped by
- * HW for CE0 anyhow.
+ * Enable 4BYTE mode for controller.
*/
- spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
/* Enable 4BYTE mode for flash. */
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
@@ -414,7 +418,7 @@ static void test_read_page_mem(const void *data)
flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
spi_ctrl_stop_user(test_data);
- spi_conf_remove(test_data, CONF_ENABLE_W0);
+ spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* Check what was written */
read_page_mem(test_data, my_page_addr, page);
@@ -439,13 +443,12 @@ static void test_write_page_mem(const void *data)
int i;
/*
- * Enable 4BYTE mode for controller. This is should be strapped by
- * HW for CE0 anyhow.
+ * Enable 4BYTE mode for controller.
*/
- spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
/* Enable 4BYTE mode for flash. */
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
@@ -473,7 +476,7 @@ static void test_read_status_reg(const void *data)
const TestData *test_data = (const TestData *)data;
uint8_t r;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, RDSR);
@@ -482,7 +485,7 @@ static void test_read_status_reg(const void *data)
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
- (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, test_data->node, "write-enable"));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
@@ -492,7 +495,7 @@ static void test_read_status_reg(const void *data)
g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
g_assert(qtest_qom_get_bool
- (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, test_data->node, "write-enable"));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WRDI);
@@ -502,7 +505,7 @@ static void test_read_status_reg(const void *data)
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
- (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
+ (test_data->s, test_data->node, "write-enable"));
flash_reset(test_data);
}
@@ -512,7 +515,7 @@ static void test_status_reg_write_protection(const void *data)
const TestData *test_data = (const TestData *)data;
uint8_t r;
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* default case: WP# is high and SRWD is low -> status register writable */
spi_ctrl_start_user(test_data);
@@ -537,8 +540,7 @@ static void test_status_reg_write_protection(const void *data)
g_assert_cmphex(r & SRWD, ==, 0);
/* WP# low and SRWD low -> status register writable */
- qtest_set_irq_in(test_data->s,
- "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
@@ -561,8 +563,7 @@ static void test_status_reg_write_protection(const void *data)
/* write is not successful */
g_assert_cmphex(r & SRWD, ==, SRWD);
- qtest_set_irq_in(test_data->s,
- "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
flash_reset(test_data);
}
@@ -572,8 +573,8 @@ static void test_write_block_protect(const void *data)
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
- spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
uint32_t bp_bits = 0b0;
@@ -617,8 +618,8 @@ static void test_write_block_protect_bottom_bit(const void *data)
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
- spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0);
- spi_conf(test_data, CONF_ENABLE_W0);
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* top bottom bit is enabled */
uint32_t bp_bits = 0b00100 << 3;
@@ -676,6 +677,8 @@ static void test_palmetto_bmc(TestData *data)
data->flash_base = 0x20000000;
data->spi_base = 0x1E620000;
data->jedec_id = 0x20ba19;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec);
qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (10 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 11/18] test/qtest/aspeed_smc-test: Support to test all CE pins Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 13:48 ` Cédric Le Goater
2024-10-22 9:41 ` [PATCH v2 13/18] test/qtest/aspeed_smc-test: Support to test AST2500 Jamin Lin via
` (6 subsequent siblings)
18 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
Currently, these test cases used the hardcode offset 0x1400000 (0x14000 * 256)
which was beyond the 16MB flash size for flash page read/write command testing.
However, the default fmc flash model of ast1030-a1 EVB is "w25q80bl" whose size
is 1MB. To test all flash models, introduces a new page_addr member in TestData
structure, so users can set the offset for flash parge read/write command
testing.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/qtest/aspeed_smc-test.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index b8ab20b43d..6db18451d2 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -72,6 +72,7 @@ typedef struct TestData {
char *tmp_path;
uint8_t cs;
const char *node;
+ uint32_t page_addr;
} TestData;
/*
@@ -256,7 +257,7 @@ static void assert_page_mem(const TestData *data, uint32_t addr,
static void test_erase_sector(const void *data)
{
const TestData *test_data = (const TestData *)data;
- uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
+ uint32_t some_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -308,7 +309,7 @@ static void test_erase_sector(const void *data)
static void test_erase_all(const void *data)
{
const TestData *test_data = (const TestData *)data;
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
+ uint32_t some_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -358,8 +359,8 @@ static void test_erase_all(const void *data)
static void test_write_page(const void *data)
{
const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -395,8 +396,8 @@ static void test_write_page(const void *data)
static void test_read_page_mem(const void *data)
{
const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
- uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -438,7 +439,7 @@ static void test_read_page_mem(const void *data)
static void test_write_page_mem(const void *data)
{
const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
+ uint32_t my_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
@@ -679,6 +680,8 @@ static void test_palmetto_bmc(TestData *data)
data->jedec_id = 0x20ba19;
data->cs = 0;
data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec);
qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector);
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 13/18] test/qtest/aspeed_smc-test: Support to test AST2500
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (11 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 14/18] test/qtest/aspeed_smc-test: Support to test AST2600 Jamin Lin via
` (5 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Add test_ast2500_evb function and reused testcases for AST2500 testing.
The spi base address, flash base address and ce index of fmc_cs0 are
0x1E620000, 0x20000000 and 0, respectively.
The default flash model of fmc_cs0 is "mx25l25635e" whose size is 32MB,
so set jedec_id 0xc22019.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 40 +++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 6db18451d2..0171ecf4ed 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -701,17 +701,57 @@ static void test_palmetto_bmc(TestData *data)
data, test_write_block_protect_bottom_bit);
}
+static void test_ast2500_evb(TestData *data)
+{
+ int ret;
+ int fd;
+
+ fd = g_file_open_tmp("qtest.m25p80.mx25l25635e.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 32 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
+
+ data->s = qtest_initf("-machine ast2500-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with mx25l25635e flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0xc22019;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2500/smc/read_jedec", data, test_read_jedec);
+ qtest_add_data_func("/ast2500/smc/erase_sector", data, test_erase_sector);
+ qtest_add_data_func("/ast2500/smc/erase_all", data, test_erase_all);
+ qtest_add_data_func("/ast2500/smc/write_page", data, test_write_page);
+ qtest_add_data_func("/ast2500/smc/read_page_mem",
+ data, test_read_page_mem);
+ qtest_add_data_func("/ast2500/smc/write_page_mem",
+ data, test_write_page_mem);
+ qtest_add_data_func("/ast2500/smc/read_status_reg",
+ data, test_read_status_reg);
+}
int main(int argc, char **argv)
{
TestData palmetto_data;
+ TestData ast2500_evb_data;
int ret;
g_test_init(&argc, &argv, NULL);
test_palmetto_bmc(&palmetto_data);
+ test_ast2500_evb(&ast2500_evb_data);
ret = g_test_run();
qtest_quit(palmetto_data.s);
+ qtest_quit(ast2500_evb_data.s);
unlink(palmetto_data.tmp_path);
+ unlink(ast2500_evb_data.tmp_path);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 14/18] test/qtest/aspeed_smc-test: Support to test AST2600
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (12 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 13/18] test/qtest/aspeed_smc-test: Support to test AST2500 Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 15/18] test/qtest/aspeed_smc-test: Support to test AST1030 Jamin Lin via
` (4 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Add test_ast2600_evb function and reused testcases for AST2600 testing.
The spi base address, flash base address and ce index of fmc_cs0 are
0x1E620000, 0x20000000 and 0, respectively.
The default flash model of fmc_cs0 is "mx66u51235f" whose size is 64MB,
so set jedec_id 0xc2253a.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 41 +++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 0171ecf4ed..30f997679c 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -737,21 +737,62 @@ static void test_ast2500_evb(TestData *data)
qtest_add_data_func("/ast2500/smc/read_status_reg",
data, test_read_status_reg);
}
+
+static void test_ast2600_evb(TestData *data)
+{
+ int ret;
+ int fd;
+
+ fd = g_file_open_tmp("qtest.m25p80.mx66u51235f.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 64 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
+
+ data->s = qtest_initf("-machine ast2600-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with mx66u51235f flash */
+ data->flash_base = 0x20000000;
+ data->spi_base = 0x1E620000;
+ data->jedec_id = 0xc2253a;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 16MB */
+ data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2600/smc/read_jedec", data, test_read_jedec);
+ qtest_add_data_func("/ast2600/smc/erase_sector", data, test_erase_sector);
+ qtest_add_data_func("/ast2600/smc/erase_all", data, test_erase_all);
+ qtest_add_data_func("/ast2600/smc/write_page", data, test_write_page);
+ qtest_add_data_func("/ast2600/smc/read_page_mem",
+ data, test_read_page_mem);
+ qtest_add_data_func("/ast2600/smc/write_page_mem",
+ data, test_write_page_mem);
+ qtest_add_data_func("/ast2600/smc/read_status_reg",
+ data, test_read_status_reg);
+}
int main(int argc, char **argv)
{
TestData palmetto_data;
TestData ast2500_evb_data;
+ TestData ast2600_evb_data;
int ret;
g_test_init(&argc, &argv, NULL);
test_palmetto_bmc(&palmetto_data);
test_ast2500_evb(&ast2500_evb_data);
+ test_ast2600_evb(&ast2600_evb_data);
ret = g_test_run();
qtest_quit(palmetto_data.s);
qtest_quit(ast2500_evb_data.s);
+ qtest_quit(ast2600_evb_data.s);
unlink(palmetto_data.tmp_path);
unlink(ast2500_evb_data.tmp_path);
+ unlink(ast2600_evb_data.tmp_path);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 15/18] test/qtest/aspeed_smc-test: Support to test AST1030
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (13 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 14/18] test/qtest/aspeed_smc-test: Support to test AST2600 Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 16/18] test/qtest/aspeed_smc-test: Support write page command with QPI mode Jamin Lin via
` (3 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Add test_ast1030_evb function and reused testcases for AST1030 testing.
The base address, flash base address and ce index of fmc_cs0 are
0x7E620000, 0x80000000 and 0, respectively.
The default flash model of fmc_cs0 is "w25q80bl" whose size is 1MB,
so set jedec_id 0xef4014.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 42 +++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 30f997679c..c5c38e23c5 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -774,11 +774,50 @@ static void test_ast2600_evb(TestData *data)
qtest_add_data_func("/ast2600/smc/read_status_reg",
data, test_read_status_reg);
}
+
+static void test_ast1030_evb(TestData *data)
+{
+ int ret;
+ int fd;
+
+ fd = g_file_open_tmp("qtest.m25p80.w25q80bl.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 1 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
+
+ data->s = qtest_initf("-machine ast1030-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with w25q80bl flash */
+ data->flash_base = 0x80000000;
+ data->spi_base = 0x7E620000;
+ data->jedec_id = 0xef4014;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 512KB */
+ data->page_addr = 0x800 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast1030/smc/read_jedec", data, test_read_jedec);
+ qtest_add_data_func("/ast1030/smc/erase_sector", data, test_erase_sector);
+ qtest_add_data_func("/ast1030/smc/erase_all", data, test_erase_all);
+ qtest_add_data_func("/ast1030/smc/write_page", data, test_write_page);
+ qtest_add_data_func("/ast1030/smc/read_page_mem",
+ data, test_read_page_mem);
+ qtest_add_data_func("/ast1030/smc/write_page_mem",
+ data, test_write_page_mem);
+ qtest_add_data_func("/ast1030/smc/read_status_reg",
+ data, test_read_status_reg);
+}
+
int main(int argc, char **argv)
{
TestData palmetto_data;
TestData ast2500_evb_data;
TestData ast2600_evb_data;
+ TestData ast1030_evb_data;
int ret;
g_test_init(&argc, &argv, NULL);
@@ -786,13 +825,16 @@ int main(int argc, char **argv)
test_palmetto_bmc(&palmetto_data);
test_ast2500_evb(&ast2500_evb_data);
test_ast2600_evb(&ast2600_evb_data);
+ test_ast1030_evb(&ast1030_evb_data);
ret = g_test_run();
qtest_quit(palmetto_data.s);
qtest_quit(ast2500_evb_data.s);
qtest_quit(ast2600_evb_data.s);
+ qtest_quit(ast1030_evb_data.s);
unlink(palmetto_data.tmp_path);
unlink(ast2500_evb_data.tmp_path);
unlink(ast2600_evb_data.tmp_path);
+ unlink(ast1030_evb_data.tmp_path);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 16/18] test/qtest/aspeed_smc-test: Support write page command with QPI mode
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (14 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 15/18] test/qtest/aspeed_smc-test: Support to test AST1030 Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases Jamin Lin via
` (2 subsequent siblings)
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang, Cédric Le Goater
Add a new testcase for write page command with QPI mode testing.
Currently, only run this testcase for AST2500, AST2600 and AST1030.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
tests/qtest/aspeed_smc-test.c | 74 +++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index c5c38e23c5..59f3876cdc 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -36,6 +36,7 @@
#define R_CE_CTRL 0x04
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
#define R_CTRL0 0x10
+#define CTRL_IO_QUAD_IO BIT(31)
#define CTRL_CE_STOP_ACTIVE BIT(2)
#define CTRL_READMODE 0x0
#define CTRL_FREADMODE 0x1
@@ -62,6 +63,7 @@ enum {
ERASE_SECTOR = 0xd8,
};
+#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
#define FLASH_PAGE_SIZE 256
typedef struct TestData {
@@ -171,6 +173,18 @@ static void spi_ctrl_stop_user(const TestData *data)
spi_writel(data, ctrl_reg, ctrl);
}
+static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+ uint32_t mode;
+
+ mode = value & CTRL_IO_MODE_MASK;
+ ctrl &= ~CTRL_IO_MODE_MASK;
+ ctrl |= mode;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
static void flash_reset(const TestData *data)
{
spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
@@ -659,6 +673,60 @@ static void test_write_block_protect_bottom_bit(const void *data)
flash_reset(test_data);
}
+static void test_write_page_qpi(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ uint32_t page_pattern[] = {
+ 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
+ };
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Set QPI mode */
+ spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
+
+ /* Fill the page pattern */
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ flash_writel(test_data, 0, make_be32(page_pattern[i]));
+ }
+
+ /* Fill the page with its own addresses */
+ for (; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+
+ /* Restore io mode */
+ spi_ctrl_set_io_mode(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ /* Check what was written */
+ read_page(test_data, my_page_addr, page);
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ g_assert_cmphex(page[i], ==, page_pattern[i]);
+ }
+ for (; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ /* Check some other page. It should be full of 0xff */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
static void test_palmetto_bmc(TestData *data)
{
int ret;
@@ -736,6 +804,8 @@ static void test_ast2500_evb(TestData *data)
data, test_write_page_mem);
qtest_add_data_func("/ast2500/smc/read_status_reg",
data, test_read_status_reg);
+ qtest_add_data_func("/ast2500/smc/write_page_qpi",
+ data, test_write_page_qpi);
}
static void test_ast2600_evb(TestData *data)
@@ -773,6 +843,8 @@ static void test_ast2600_evb(TestData *data)
data, test_write_page_mem);
qtest_add_data_func("/ast2600/smc/read_status_reg",
data, test_read_status_reg);
+ qtest_add_data_func("/ast2600/smc/write_page_qpi",
+ data, test_write_page_qpi);
}
static void test_ast1030_evb(TestData *data)
@@ -810,6 +882,8 @@ static void test_ast1030_evb(TestData *data)
data, test_write_page_mem);
qtest_add_data_func("/ast1030/smc/read_status_reg",
data, test_read_status_reg);
+ qtest_add_data_func("/ast1030/smc/write_page_qpi",
+ data, test_write_page_qpi);
}
int main(int argc, char **argv)
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (15 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 16/18] test/qtest/aspeed_smc-test: Support write page command with QPI mode Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-11-25 13:43 ` Cédric Le Goater
2024-10-22 9:41 ` [PATCH v2 18/18] test/qtest/ast2700-smc-test: Support to test AST2700 Jamin Lin via
2024-10-24 6:11 ` [PATCH v2 00/18] Fix write incorrect data into flash in user mode Cédric Le Goater
18 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
The testcases for ASPEED SMC model were placed in aspeed_smc-test.c.
However, this test file only supports for ARM32. To support all ASPEED SOCs
such as AST2700 whose CPU architecture is aarch64, introduces a new
aspeed-smc-utils source file and move all common APIs and testcases
from aspeed_smc-test.c to aspeed-smc-utils.c.
Finally, users are able to re-used these testcase for AST2700 and future
ASPEED SOCs testing.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/qtest/aspeed-smc-utils.c | 681 ++++++++++++++++++++++++++++++++
tests/qtest/aspeed-smc-utils.h | 95 +++++
tests/qtest/aspeed_smc-test.c | 700 +--------------------------------
tests/qtest/meson.build | 1 +
4 files changed, 778 insertions(+), 699 deletions(-)
create mode 100644 tests/qtest/aspeed-smc-utils.c
create mode 100644 tests/qtest/aspeed-smc-utils.h
diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c
new file mode 100644
index 0000000000..37da5d1f3b
--- /dev/null
+++ b/tests/qtest/aspeed-smc-utils.c
@@ -0,0 +1,681 @@
+/*
+ * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
+ * Controller)
+ *
+ * Copyright (C) 2016 IBM Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest-single.h"
+#include "qemu/bitops.h"
+#include "aspeed-smc-utils.h"
+
+/*
+ * Use an explicit bswap for the values read/wrote to the flash region
+ * as they are BE and the Aspeed CPU is LE.
+ */
+static inline uint32_t make_be32(uint32_t data)
+{
+ return bswap32(data);
+}
+
+static inline void spi_writel(const TestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->spi_base + offset, value);
+}
+
+static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
+{
+ return qtest_readl(data->s, data->spi_base + offset);
+}
+
+static inline void flash_writeb(const TestData *data, uint64_t offset,
+ uint8_t value)
+{
+ qtest_writeb(data->s, data->flash_base + offset, value);
+}
+
+static inline void flash_writel(const TestData *data, uint64_t offset,
+ uint32_t value)
+{
+ qtest_writel(data->s, data->flash_base + offset, value);
+}
+
+static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
+{
+ return qtest_readb(data->s, data->flash_base + offset);
+}
+
+static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
+{
+ return qtest_readl(data->s, data->flash_base + offset);
+}
+
+static void spi_conf(const TestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CONF);
+
+ conf |= value;
+ spi_writel(data, R_CONF, conf);
+}
+
+static void spi_conf_remove(const TestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CONF);
+
+ conf &= ~value;
+ spi_writel(data, R_CONF, conf);
+}
+
+static void spi_ce_ctrl(const TestData *data, uint32_t value)
+{
+ uint32_t conf = spi_readl(data, R_CE_CTRL);
+
+ conf |= value;
+ spi_writel(data, R_CE_CTRL, conf);
+}
+
+static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+ ctrl &= ~(CTRL_USERMODE | 0xff << 16);
+ ctrl |= mode | (cmd << 16);
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_start_user(const TestData *data)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+
+ ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+
+ ctrl &= ~CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_stop_user(const TestData *data)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+
+ ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
+{
+ uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
+ uint32_t ctrl = spi_readl(data, ctrl_reg);
+ uint32_t mode;
+
+ mode = value & CTRL_IO_MODE_MASK;
+ ctrl &= ~CTRL_IO_MODE_MASK;
+ ctrl |= mode;
+ spi_writel(data, ctrl_reg, ctrl);
+}
+
+static void flash_reset(const TestData *data)
+{
+ spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
+
+ spi_ctrl_start_user(data);
+ flash_writeb(data, 0, RESET_ENABLE);
+ flash_writeb(data, 0, RESET_MEMORY);
+ flash_writeb(data, 0, WREN);
+ flash_writeb(data, 0, BULK_ERASE);
+ flash_writeb(data, 0, WRDI);
+ spi_ctrl_stop_user(data);
+
+ spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
+}
+
+static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
+{
+ int i;
+
+ spi_ctrl_start_user(data);
+
+ flash_writeb(data, 0, EN_4BYTE_ADDR);
+ flash_writeb(data, 0, READ);
+ flash_writel(data, 0, make_be32(addr));
+
+ /* Continuous read are supported */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ page[i] = make_be32(flash_readl(data, 0));
+ }
+ spi_ctrl_stop_user(data);
+}
+
+static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
+{
+ int i;
+
+ /* move out USER mode to use direct reads from the AHB bus */
+ spi_ctrl_setmode(data, CTRL_READMODE, READ);
+
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ page[i] = make_be32(flash_readl(data, addr + i * 4));
+ }
+}
+
+static void write_page_mem(const TestData *data, uint32_t addr,
+ uint32_t write_value)
+{
+ spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
+
+ for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(data, addr + i * 4, write_value);
+ }
+}
+
+static void assert_page_mem(const TestData *data, uint32_t addr,
+ uint32_t expected_value)
+{
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ read_page_mem(data, addr, page);
+ for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, expected_value);
+ }
+}
+
+void test_read_jedec(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t jedec = 0x0;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, JEDEC_READ);
+ jedec |= flash_readb(test_data, 0) << 16;
+ jedec |= flash_readb(test_data, 0) << 8;
+ jedec |= flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ flash_reset(test_data);
+
+ g_assert_cmphex(jedec, ==, test_data->jedec_id);
+}
+
+void test_erase_sector(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t some_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /*
+ * Previous page should be full of 0xffs after backend is
+ * initialized
+ */
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is correctly written */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, ERASE_SECTOR);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is erased */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void test_erase_all(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t some_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /*
+ * Previous page should be full of 0xffs after backend is
+ * initialized
+ */
+ read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(some_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is correctly written */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
+ }
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ spi_ctrl_stop_user(test_data);
+
+ /* Check the page is erased */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void test_write_page(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+
+ /* Check what was written */
+ read_page(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ /* Check some other page. It should be full of 0xff */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void test_read_page_mem(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ /*
+ * Enable 4BYTE mode for controller.
+ */
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+
+ /* Enable 4BYTE mode for flash. */
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Fill the page with its own addresses */
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+ spi_ctrl_stop_user(test_data);
+ spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* Check what was written */
+ read_page_mem(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ /* Check some other page. It should be full of 0xff */
+ read_page_mem(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
+void test_write_page_mem(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ int i;
+
+ /*
+ * Enable 4BYTE mode for controller.
+ */
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+
+ /* Enable 4BYTE mode for flash. */
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ /* move out USER mode to use direct writes to the AHB bus */
+ spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
+
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, my_page_addr + i * 4,
+ make_be32(my_page_addr + i * 4));
+ }
+
+ /* Check what was written */
+ read_page_mem(test_data, my_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ flash_reset(test_data);
+}
+
+void test_read_status_reg(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint8_t r;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, 0);
+ g_assert(!qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
+ g_assert(qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WRDI);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ g_assert_cmphex(r & SR_WEL, ==, 0);
+ g_assert(!qtest_qom_get_bool
+ (test_data->s, test_data->node, "write-enable"));
+
+ flash_reset(test_data);
+}
+
+void test_status_reg_write_protection(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint8_t r;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* default case: WP# is high and SRWD is low -> status register writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ /* WP# high and SRWD high -> status register writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, 0);
+
+ /* WP# low and SRWD low -> status register writable */
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, SRWD);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ /* WP# low and SRWD high -> status register NOT writable */
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0 , WREN);
+ /* test ability to write SRWD */
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, 0);
+ flash_writeb(test_data, 0, RDSR);
+ r = flash_readb(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+ /* write is not successful */
+ g_assert_cmphex(r & SRWD, ==, SRWD);
+
+ qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
+ flash_reset(test_data);
+}
+
+void test_write_block_protect(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t sector_size = 65536;
+ uint32_t n_sectors = 512;
+
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ uint32_t bp_bits = 0b0;
+
+ for (int i = 0; i < 16; i++) {
+ bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ 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(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
+
+ uint32_t expected_value = protection_start <= sector
+ && sector < protection_end
+ ? 0xffffffff : 0xabcdef12;
+
+ assert_page_mem(test_data, addr, expected_value);
+ }
+ }
+
+ flash_reset(test_data);
+}
+
+void test_write_block_protect_bottom_bit(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t sector_size = 65536;
+ uint32_t n_sectors = 512;
+
+ spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ /* 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(test_data);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, BULK_ERASE);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, WRSR);
+ flash_writeb(test_data, 0, bp_bits);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ spi_ctrl_stop_user(test_data);
+
+ 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(test_data, addr, 0xffffffff);
+ write_page_mem(test_data, addr, make_be32(0xabcdef12));
+
+ uint32_t expected_value = protection_start <= sector
+ && sector < protection_end
+ ? 0xffffffff : 0xabcdef12;
+
+ assert_page_mem(test_data, addr, expected_value);
+ }
+ }
+
+ flash_reset(test_data);
+}
+
+void test_write_page_qpi(const void *data)
+{
+ const TestData *test_data = (const TestData *)data;
+ uint32_t my_page_addr = test_data->page_addr;
+ uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
+ uint32_t page[FLASH_PAGE_SIZE / 4];
+ uint32_t page_pattern[] = {
+ 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
+ };
+ int i;
+
+ spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
+
+ spi_ctrl_start_user(test_data);
+ flash_writeb(test_data, 0, EN_4BYTE_ADDR);
+ flash_writeb(test_data, 0, WREN);
+ flash_writeb(test_data, 0, PP);
+ flash_writel(test_data, 0, make_be32(my_page_addr));
+
+ /* Set QPI mode */
+ spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
+
+ /* Fill the page pattern */
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ flash_writel(test_data, 0, make_be32(page_pattern[i]));
+ }
+
+ /* Fill the page with its own addresses */
+ for (; i < FLASH_PAGE_SIZE / 4; i++) {
+ flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
+ }
+
+ /* Restore io mode */
+ spi_ctrl_set_io_mode(test_data, 0);
+ spi_ctrl_stop_user(test_data);
+
+ /* Check what was written */
+ read_page(test_data, my_page_addr, page);
+ for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
+ g_assert_cmphex(page[i], ==, page_pattern[i]);
+ }
+ for (; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
+ }
+
+ /* Check some other page. It should be full of 0xff */
+ read_page(test_data, some_page_addr, page);
+ for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
+ g_assert_cmphex(page[i], ==, 0xffffffff);
+ }
+
+ flash_reset(test_data);
+}
+
diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h
new file mode 100644
index 0000000000..0f298085c2
--- /dev/null
+++ b/tests/qtest/aspeed-smc-utils.h
@@ -0,0 +1,95 @@
+/*
+ * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
+ * Controller)
+ *
+ * Copyright (C) 2016 IBM Corp.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TESTS_ASPEED_SMC_UTILS_H
+#define TESTS_ASPEED_SMC_UTILS_H
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest-single.h"
+#include "qemu/bitops.h"
+
+/*
+ * ASPEED SPI Controller registers
+ */
+#define R_CONF 0x00
+#define CONF_ENABLE_W0 16
+#define R_CE_CTRL 0x04
+#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
+#define R_CTRL0 0x10
+#define CTRL_IO_QUAD_IO BIT(31)
+#define CTRL_CE_STOP_ACTIVE BIT(2)
+#define CTRL_READMODE 0x0
+#define CTRL_FREADMODE 0x1
+#define CTRL_WRITEMODE 0x2
+#define CTRL_USERMODE 0x3
+#define SR_WEL BIT(1)
+
+/*
+ * Flash commands
+ */
+enum {
+ JEDEC_READ = 0x9f,
+ RDSR = 0x5,
+ WRDI = 0x4,
+ BULK_ERASE = 0xc7,
+ READ = 0x03,
+ PP = 0x02,
+ WRSR = 0x1,
+ WREN = 0x6,
+ SRWD = 0x80,
+ RESET_ENABLE = 0x66,
+ RESET_MEMORY = 0x99,
+ EN_4BYTE_ADDR = 0xB7,
+ ERASE_SECTOR = 0xd8,
+};
+
+#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
+#define FLASH_PAGE_SIZE 256
+
+typedef struct TestData {
+ QTestState *s;
+ uint64_t spi_base;
+ uint64_t flash_base;
+ uint32_t jedec_id;
+ char *tmp_path;
+ uint8_t cs;
+ const char *node;
+ uint32_t page_addr;
+} TestData;
+
+void test_read_jedec(const void *data);
+void test_erase_sector(const void *data);
+void test_erase_all(const void *data);
+void test_write_page(const void *data);
+void test_read_page_mem(const void *data);
+void test_write_page_mem(const void *data);
+void test_read_status_reg(const void *data);
+void test_status_reg_write_protection(const void *data);
+void test_write_block_protect(const void *data);
+void test_write_block_protect_bottom_bit(const void *data);
+void test_write_page_qpi(const void *data);
+
+#endif /* TESTS_ASPEED_SMC_UTILS_H */
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index 59f3876cdc..ef3fdc516e 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -27,705 +27,7 @@
#include "qemu/bswap.h"
#include "libqtest-single.h"
#include "qemu/bitops.h"
-
-/*
- * ASPEED SPI Controller registers
- */
-#define R_CONF 0x00
-#define CONF_ENABLE_W0 16
-#define R_CE_CTRL 0x04
-#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
-#define R_CTRL0 0x10
-#define CTRL_IO_QUAD_IO BIT(31)
-#define CTRL_CE_STOP_ACTIVE BIT(2)
-#define CTRL_READMODE 0x0
-#define CTRL_FREADMODE 0x1
-#define CTRL_WRITEMODE 0x2
-#define CTRL_USERMODE 0x3
-#define SR_WEL BIT(1)
-
-/*
- * Flash commands
- */
-enum {
- JEDEC_READ = 0x9f,
- RDSR = 0x5,
- WRDI = 0x4,
- BULK_ERASE = 0xc7,
- READ = 0x03,
- PP = 0x02,
- WRSR = 0x1,
- WREN = 0x6,
- SRWD = 0x80,
- RESET_ENABLE = 0x66,
- RESET_MEMORY = 0x99,
- EN_4BYTE_ADDR = 0xB7,
- ERASE_SECTOR = 0xd8,
-};
-
-#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
-#define FLASH_PAGE_SIZE 256
-
-typedef struct TestData {
- QTestState *s;
- uint64_t spi_base;
- uint64_t flash_base;
- uint32_t jedec_id;
- char *tmp_path;
- uint8_t cs;
- const char *node;
- uint32_t page_addr;
-} TestData;
-
-/*
- * Use an explicit bswap for the values read/wrote to the flash region
- * as they are BE and the Aspeed CPU is LE.
- */
-static inline uint32_t make_be32(uint32_t data)
-{
- return bswap32(data);
-}
-
-static inline void spi_writel(const TestData *data, uint64_t offset,
- uint32_t value)
-{
- qtest_writel(data->s, data->spi_base + offset, value);
-}
-
-static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
-{
- return qtest_readl(data->s, data->spi_base + offset);
-}
-
-static inline void flash_writeb(const TestData *data, uint64_t offset,
- uint8_t value)
-{
- qtest_writeb(data->s, data->flash_base + offset, value);
-}
-
-static inline void flash_writel(const TestData *data, uint64_t offset,
- uint32_t value)
-{
- qtest_writel(data->s, data->flash_base + offset, value);
-}
-
-static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
-{
- return qtest_readb(data->s, data->flash_base + offset);
-}
-
-static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
-{
- return qtest_readl(data->s, data->flash_base + offset);
-}
-
-static void spi_conf(const TestData *data, uint32_t value)
-{
- uint32_t conf = spi_readl(data, R_CONF);
-
- conf |= value;
- spi_writel(data, R_CONF, conf);
-}
-
-static void spi_conf_remove(const TestData *data, uint32_t value)
-{
- uint32_t conf = spi_readl(data, R_CONF);
-
- conf &= ~value;
- spi_writel(data, R_CONF, conf);
-}
-
-static void spi_ce_ctrl(const TestData *data, uint32_t value)
-{
- uint32_t conf = spi_readl(data, R_CE_CTRL);
-
- conf |= value;
- spi_writel(data, R_CE_CTRL, conf);
-}
-
-static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
-{
- uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
- uint32_t ctrl = spi_readl(data, ctrl_reg);
- ctrl &= ~(CTRL_USERMODE | 0xff << 16);
- ctrl |= mode | (cmd << 16);
- spi_writel(data, ctrl_reg, ctrl);
-}
-
-static void spi_ctrl_start_user(const TestData *data)
-{
- uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
- uint32_t ctrl = spi_readl(data, ctrl_reg);
-
- ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- spi_writel(data, ctrl_reg, ctrl);
-
- ctrl &= ~CTRL_CE_STOP_ACTIVE;
- spi_writel(data, ctrl_reg, ctrl);
-}
-
-static void spi_ctrl_stop_user(const TestData *data)
-{
- uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
- uint32_t ctrl = spi_readl(data, ctrl_reg);
-
- ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
- spi_writel(data, ctrl_reg, ctrl);
-}
-
-static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
-{
- uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
- uint32_t ctrl = spi_readl(data, ctrl_reg);
- uint32_t mode;
-
- mode = value & CTRL_IO_MODE_MASK;
- ctrl &= ~CTRL_IO_MODE_MASK;
- ctrl |= mode;
- spi_writel(data, ctrl_reg, ctrl);
-}
-
-static void flash_reset(const TestData *data)
-{
- spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
-
- spi_ctrl_start_user(data);
- flash_writeb(data, 0, RESET_ENABLE);
- flash_writeb(data, 0, RESET_MEMORY);
- flash_writeb(data, 0, WREN);
- flash_writeb(data, 0, BULK_ERASE);
- flash_writeb(data, 0, WRDI);
- spi_ctrl_stop_user(data);
-
- spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
-}
-
-static void test_read_jedec(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t jedec = 0x0;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, JEDEC_READ);
- jedec |= flash_readb(test_data, 0) << 16;
- jedec |= flash_readb(test_data, 0) << 8;
- jedec |= flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
-
- flash_reset(test_data);
-
- g_assert_cmphex(jedec, ==, test_data->jedec_id);
-}
-
-static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
-{
- int i;
-
- spi_ctrl_start_user(data);
-
- flash_writeb(data, 0, EN_4BYTE_ADDR);
- flash_writeb(data, 0, READ);
- flash_writel(data, 0, make_be32(addr));
-
- /* Continuous read are supported */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- page[i] = make_be32(flash_readl(data, 0));
- }
- spi_ctrl_stop_user(data);
-}
-
-static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
-{
- int i;
-
- /* move out USER mode to use direct reads from the AHB bus */
- spi_ctrl_setmode(data, CTRL_READMODE, READ);
-
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- page[i] = make_be32(flash_readl(data, addr + i * 4));
- }
-}
-
-static void write_page_mem(const TestData *data, uint32_t addr,
- uint32_t write_value)
-{
- spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
-
- for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(data, addr + i * 4, write_value);
- }
-}
-
-static void assert_page_mem(const TestData *data, uint32_t addr,
- uint32_t expected_value)
-{
- uint32_t page[FLASH_PAGE_SIZE / 4];
- read_page_mem(data, addr, page);
- for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, expected_value);
- }
-}
-
-static void test_erase_sector(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t some_page_addr = test_data->page_addr;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- /*
- * Previous page should be full of 0xffs after backend is
- * initialized
- */
- read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, PP);
- flash_writel(test_data, 0, make_be32(some_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
- }
- spi_ctrl_stop_user(test_data);
-
- /* Check the page is correctly written */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
- }
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, ERASE_SECTOR);
- flash_writel(test_data, 0, make_be32(some_page_addr));
- spi_ctrl_stop_user(test_data);
-
- /* Check the page is erased */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset(test_data);
-}
-
-static void test_erase_all(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t some_page_addr = test_data->page_addr;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- /*
- * Previous page should be full of 0xffs after backend is
- * initialized
- */
- read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, PP);
- flash_writel(test_data, 0, make_be32(some_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
- }
- spi_ctrl_stop_user(test_data);
-
- /* Check the page is correctly written */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
- }
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, BULK_ERASE);
- spi_ctrl_stop_user(test_data);
-
- /* Check the page is erased */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset(test_data);
-}
-
-static void test_write_page(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = test_data->page_addr;
- uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, PP);
- flash_writel(test_data, 0, make_be32(my_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
- }
- spi_ctrl_stop_user(test_data);
-
- /* Check what was written */
- read_page(test_data, my_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
- }
-
- /* Check some other page. It should be full of 0xff */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset(test_data);
-}
-
-static void test_read_page_mem(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = test_data->page_addr;
- uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- /*
- * Enable 4BYTE mode for controller.
- */
- spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
-
- /* Enable 4BYTE mode for flash. */
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, PP);
- flash_writel(test_data, 0, make_be32(my_page_addr));
-
- /* Fill the page with its own addresses */
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
- }
- spi_ctrl_stop_user(test_data);
- spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- /* Check what was written */
- read_page_mem(test_data, my_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
- }
-
- /* Check some other page. It should be full of 0xff */
- read_page_mem(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset(test_data);
-}
-
-static void test_write_page_mem(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = test_data->page_addr;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- int i;
-
- /*
- * Enable 4BYTE mode for controller.
- */
- spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
-
- /* Enable 4BYTE mode for flash. */
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- spi_ctrl_stop_user(test_data);
-
- /* move out USER mode to use direct writes to the AHB bus */
- spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
-
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, my_page_addr + i * 4,
- make_be32(my_page_addr + i * 4));
- }
-
- /* Check what was written */
- read_page_mem(test_data, my_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
- }
-
- flash_reset(test_data);
-}
-
-static void test_read_status_reg(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint8_t r;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
-
- g_assert_cmphex(r & SR_WEL, ==, 0);
- g_assert(!qtest_qom_get_bool
- (test_data->s, test_data->node, "write-enable"));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
-
- g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
- g_assert(qtest_qom_get_bool
- (test_data->s, test_data->node, "write-enable"));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WRDI);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
-
- g_assert_cmphex(r & SR_WEL, ==, 0);
- g_assert(!qtest_qom_get_bool
- (test_data->s, test_data->node, "write-enable"));
-
- flash_reset(test_data);
-}
-
-static void test_status_reg_write_protection(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint8_t r;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- /* default case: WP# is high and SRWD is low -> status register writable */
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- /* test ability to write SRWD */
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, SRWD);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
- g_assert_cmphex(r & SRWD, ==, SRWD);
-
- /* WP# high and SRWD high -> status register writable */
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- /* test ability to write SRWD */
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, 0);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
- g_assert_cmphex(r & SRWD, ==, 0);
-
- /* WP# low and SRWD low -> status register writable */
- qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- /* test ability to write SRWD */
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, SRWD);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
- g_assert_cmphex(r & SRWD, ==, SRWD);
-
- /* WP# low and SRWD high -> status register NOT writable */
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0 , WREN);
- /* test ability to write SRWD */
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, 0);
- flash_writeb(test_data, 0, RDSR);
- r = flash_readb(test_data, 0);
- spi_ctrl_stop_user(test_data);
- /* write is not successful */
- g_assert_cmphex(r & SRWD, ==, SRWD);
-
- qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
- flash_reset(test_data);
-}
-
-static void test_write_block_protect(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t sector_size = 65536;
- uint32_t n_sectors = 512;
-
- spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- uint32_t bp_bits = 0b0;
-
- for (int i = 0; i < 16; i++) {
- bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, BULK_ERASE);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, bp_bits);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- spi_ctrl_stop_user(test_data);
-
- 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(test_data, addr, 0xffffffff);
- write_page_mem(test_data, addr, make_be32(0xabcdef12));
-
- uint32_t expected_value = protection_start <= sector
- && sector < protection_end
- ? 0xffffffff : 0xabcdef12;
-
- assert_page_mem(test_data, addr, expected_value);
- }
- }
-
- flash_reset(test_data);
-}
-
-static void test_write_block_protect_bottom_bit(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t sector_size = 65536;
- uint32_t n_sectors = 512;
-
- spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- /* 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(test_data);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, BULK_ERASE);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, WRSR);
- flash_writeb(test_data, 0, bp_bits);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- spi_ctrl_stop_user(test_data);
-
- 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(test_data, addr, 0xffffffff);
- write_page_mem(test_data, addr, make_be32(0xabcdef12));
-
- uint32_t expected_value = protection_start <= sector
- && sector < protection_end
- ? 0xffffffff : 0xabcdef12;
-
- assert_page_mem(test_data, addr, expected_value);
- }
- }
-
- flash_reset(test_data);
-}
-
-static void test_write_page_qpi(const void *data)
-{
- const TestData *test_data = (const TestData *)data;
- uint32_t my_page_addr = test_data->page_addr;
- uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
- uint32_t page[FLASH_PAGE_SIZE / 4];
- uint32_t page_pattern[] = {
- 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
- };
- int i;
-
- spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
-
- spi_ctrl_start_user(test_data);
- flash_writeb(test_data, 0, EN_4BYTE_ADDR);
- flash_writeb(test_data, 0, WREN);
- flash_writeb(test_data, 0, PP);
- flash_writel(test_data, 0, make_be32(my_page_addr));
-
- /* Set QPI mode */
- spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
-
- /* Fill the page pattern */
- for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
- flash_writel(test_data, 0, make_be32(page_pattern[i]));
- }
-
- /* Fill the page with its own addresses */
- for (; i < FLASH_PAGE_SIZE / 4; i++) {
- flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
- }
-
- /* Restore io mode */
- spi_ctrl_set_io_mode(test_data, 0);
- spi_ctrl_stop_user(test_data);
-
- /* Check what was written */
- read_page(test_data, my_page_addr, page);
- for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
- g_assert_cmphex(page[i], ==, page_pattern[i]);
- }
- for (; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
- }
-
- /* Check some other page. It should be full of 0xff */
- read_page(test_data, some_page_addr, page);
- for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
- g_assert_cmphex(page[i], ==, 0xffffffff);
- }
-
- flash_reset(test_data);
-}
+#include "aspeed-smc-utils.h"
static void test_palmetto_bmc(TestData *data)
{
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 41f3678cee..fde4de902b 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -353,6 +353,7 @@ qtests = {
'virtio-net-failover': files('migration-helpers.c'),
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
+ 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
}
if vnc.found()
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 18/18] test/qtest/ast2700-smc-test: Support to test AST2700
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (16 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases Jamin Lin via
@ 2024-10-22 9:41 ` Jamin Lin via
2024-10-24 6:11 ` [PATCH v2 00/18] Fix write incorrect data into flash in user mode Cédric Le Goater
18 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin via @ 2024-10-22 9:41 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: jamin_lin, troy_lee, yunlin.tang
Add test_ast2700_evb function and reused testcases which are from
aspeed_smc-test.c for AST2700 testing. The base address, flash base address
and ce index of fmc_cs0 are 0x14000000, 0x100000000 and 0, respectively.
The default flash model of fmc_cs0 is "w25q01jvq" whose size is 128MB,
so set jedec_id 0xef4021.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/qtest/ast2700-smc-test.c | 67 ++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 4 +-
2 files changed, 70 insertions(+), 1 deletion(-)
create mode 100644 tests/qtest/ast2700-smc-test.c
diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c
new file mode 100644
index 0000000000..e06e10f3e8
--- /dev/null
+++ b/tests/qtest/ast2700-smc-test.c
@@ -0,0 +1,67 @@
+/*
+ * QTest testcase for the M25P80 Flash using the ASPEED SPI Controller since
+ * AST2700.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest-single.h"
+#include "qemu/bitops.h"
+#include "aspeed-smc-utils.h"
+
+static void test_ast2700_evb(TestData *data)
+{
+ int ret;
+ int fd;
+
+ fd = g_file_open_tmp("qtest.m25p80.w25q01jvq.XXXXXX",
+ &data->tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, 128 * 1024 * 1024);
+ g_assert(ret == 0);
+ close(fd);
+
+ data->s = qtest_initf("-machine ast2700-evb "
+ "-drive file=%s,format=raw,if=mtd",
+ data->tmp_path);
+
+ /* fmc cs0 with w25q01jvq flash */
+ data->flash_base = 0x100000000;
+ data->spi_base = 0x14000000;
+ data->jedec_id = 0xef4021;
+ data->cs = 0;
+ data->node = "/machine/soc/fmc/ssi.0/child[0]";
+ /* beyond 64MB */
+ data->page_addr = 0x40000 * FLASH_PAGE_SIZE;
+
+ qtest_add_data_func("/ast2700/smc/read_jedec", data, test_read_jedec);
+ qtest_add_data_func("/ast2700/smc/erase_sector", data, test_erase_sector);
+ qtest_add_data_func("/ast2700/smc/erase_all", data, test_erase_all);
+ qtest_add_data_func("/ast2700/smc/write_page", data, test_write_page);
+ qtest_add_data_func("/ast2700/smc/read_page_mem",
+ data, test_read_page_mem);
+ qtest_add_data_func("/ast2700/smc/write_page_mem",
+ data, test_write_page_mem);
+ qtest_add_data_func("/ast2700/smc/read_status_reg",
+ data, test_read_status_reg);
+ qtest_add_data_func("/ast2700/smc/write_page_qpi",
+ data, test_write_page_qpi);
+}
+
+int main(int argc, char **argv)
+{
+ TestData ast2700_evb_data;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ test_ast2700_evb(&ast2700_evb_data);
+ ret = g_test_run();
+
+ qtest_quit(ast2700_evb_data.s);
+ unlink(ast2700_evb_data.tmp_path);
+ return ret;
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index fde4de902b..a0707d5bd2 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -210,7 +210,8 @@ qtests_aspeed = \
'aspeed_smc-test',
'aspeed_gpio-test']
qtests_aspeed64 = \
- ['ast2700-gpio-test']
+ ['ast2700-gpio-test',
+ 'ast2700-smc-test']
qtests_stm32l4x5 = \
['stm32l4x5_exti-test',
@@ -354,6 +355,7 @@ qtests = {
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
+ 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'),
}
if vnc.found()
--
2.34.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-10-22 9:40 ` [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers Jamin Lin via
@ 2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 14:10 ` Cédric Le Goater
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-22 10:48 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
On 10/22/24 11:40, Jamin Lin wrote:
> It only attached flash model of fmc and spi[0] in aspeed_machine_init function.
> However, AST2500 and AST2600 have one fmc and two spi(spi1 and spi2)
> controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2) controllers.
>
> Besides, it used hardcode to attach flash model of fmc, spi[0] and spi[1] in
> aspeed_minibmc_machine_init for AST1030.
>
> To make both functions more flexible and support all ASPEED SOCs spi
> controllers, adds a for loop with sc->spis_num to attach flash model of
> all supported spi controllers. The sc->spis_num is from AspeedSoCClass.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/arm/aspeed.c | 21 ++++++++++++---------
> 1 file changed, 12 insertions(+), 9 deletions(-)
>
> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
> index b4b1ce9efb..7ac01a3562 100644
> --- a/hw/arm/aspeed.c
> +++ b/hw/arm/aspeed.c
> @@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState *machine)
> aspeed_board_init_flashes(&bmc->soc->fmc,
> bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
> amc->num_cs, 0);
> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> - bmc->spi_model ? bmc->spi_model : amc->spi_model,
> - 1, amc->num_cs);
> + for (i = 0; i < sc->spis_num; i++) {
> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> + bmc->spi_model ? bmc->spi_model : amc->spi_model,
> + amc->num_cs, amc->num_cs + (amc->num_cs * i));
> + }
> }
>
> if (machine->kernel_filename && sc->num_cpus > 1) {
> @@ -1579,7 +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
> {
> AspeedMachineState *bmc = ASPEED_MACHINE(machine);
> AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
> + AspeedSoCClass *sc;
> Clock *sysclk;
> + int i;
>
> sysclk = clock_new(OBJECT(machine), "SYSCLK");
> clock_set_hz(sysclk, SYSCLK_FRQ);
> @@ -1587,6 +1591,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
> bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
> object_property_add_child(OBJECT(machine), "soc", OBJECT(bmc->soc));
> object_unref(OBJECT(bmc->soc));
> + sc = ASPEED_SOC_GET_CLASS(bmc->soc);
> qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
>
> object_property_set_link(OBJECT(bmc->soc), "memory",
> @@ -1599,13 +1604,11 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
> amc->num_cs,
> 0);
>
> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> - bmc->spi_model ? bmc->spi_model : amc->spi_model,
> - amc->num_cs, amc->num_cs);
> -
> - aspeed_board_init_flashes(&bmc->soc->spi[1],
> + for (i = 0; i < sc->spis_num; i++) {
> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> bmc->spi_model ? bmc->spi_model : amc->spi_model,
> - amc->num_cs, (amc->num_cs * 2));
> + amc->num_cs, amc->num_cs + (amc->num_cs * i));
> + }
>
> if (amc->i2c_init) {
> amc->i2c_init(bmc);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
@ 2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 10:49 ` Kevin Wolf
1 sibling, 0 replies; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-22 10:48 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
On 10/22/24 11:40, Jamin Lin wrote:
> According to the design of ASPEED SPI controllers user mode, users write the
> data to flash, the SPI drivers set the Control Register(0x10) bit 0 and 1
> enter user mode. Then, SPI drivers send flash commands for writing data.
> Finally, SPI drivers set the Control Register (0x10) bit 2 to stop
> active control and restore bit 0 and 1.
>
> According to the design of ASPEED SMC model, firmware writes the
> Control Register and the "aspeed_smc_flash_update_ctrl" function is called.
> Then, this function verify Control Register(0x10) bit 0 and 1. If it set user
> mode, the value of s->snoop_index is SNOOP_START else SNOOP_OFF.
> If s->snoop_index is SNOOP_START, the "aspeed_smc_do_snoop" function verify
> the first incomming data is a new flash command and writes the corresponding
> dummy bytes if need.
>
> However, it did not check the current unselect status. If current unselect
> status is "false" and firmware set the IO MODE by Control Register bit 31:28,
> the value of s->snoop_index will be changed to SNOOP_START again and
> "aspeed_smc_do_snoop" misunderstand that the incomming data is the new flash
> command and it causes writing unexpected data into flash.
>
> Example:
> 1. Firmware set user mode by Control Register bit 0 and 1(0x03)
> 2. SMC model set s->snoop SNOOP_START
> 3. Firmware set Quad Page Program with 4-Byte Address command (0x34)
> 4. SMC model verify this flash command and it needs 4 dummy bytes.
> 5. Firmware send 4 bytes address.
> 6. SMC model receives 4 bytes address
> 7. Firmware set QPI IO MODE by Control Register bit 31. (0x80000003)
> 8. SMC model verify new user mode by Control Register bit 0 and 1.
> Then, set s->snoop SNOOP_START again. (It is the wrong behavior.)
> 9. Firmware send 0xebd8c134 data and it should be written into flash.
> However, SMC model misunderstand that the first incoming data, 0x34,
> is the new command because the value of s->snoop is changed to SNOOP_START.
> Finally, SMC sned the incorrect data to flash model.
>
> Introduce a new unselect attribute in AspeedSMCState to save the current
> unselect status for user mode and set it "true" by default.
> Update "aspeed_smc_flash_update_ctrl" function to check the previous unselect
> status. If both new unselect status and previous unselect status is different,
> update s->snoop_index value and call "aspeed_smc_flash_do_select".
>
> Increase VMStateDescription version.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/ssi/aspeed_smc.c | 40 ++++++++++++++++++++++++++-----------
> include/hw/ssi/aspeed_smc.h | 1 +
> 2 files changed, 29 insertions(+), 12 deletions(-)
>
> diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
> index e3fdc66cb2..7b0f6599f9 100644
> --- a/hw/ssi/aspeed_smc.c
> +++ b/hw/ssi/aspeed_smc.c
> @@ -417,7 +417,7 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect)
> AspeedSMCState *s = fl->controller;
>
> trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : "");
> -
> + s->unselect = unselect;
> qemu_set_irq(s->cs_lines[fl->cs], unselect);
> }
>
> @@ -677,22 +677,35 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
> static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value)
> {
> AspeedSMCState *s = fl->controller;
> - bool unselect;
> + bool unselect = false;
> + uint32_t old_mode;
> + uint32_t new_mode;
> +
> + old_mode = s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK;
> + new_mode = value & CTRL_CMD_MODE_MASK;
>
> - /* User mode selects the CS, other modes unselect */
> - unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE;
> + if (old_mode == CTRL_USERMODE) {
> + if (new_mode != CTRL_USERMODE) {
> + unselect = true;
> + }
>
> - /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
> - if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
> - value & CTRL_CE_STOP_ACTIVE) {
> - unselect = true;
> + /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
> + if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
> + value & CTRL_CE_STOP_ACTIVE) {
> + unselect = true;
> + }
> + } else {
> + if (new_mode != CTRL_USERMODE) {
> + unselect = true;
> + }
> }
>
> s->regs[s->r_ctrl0 + fl->cs] = value;
>
> - s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
> -
> - aspeed_smc_flash_do_select(fl, unselect);
> + if (unselect != s->unselect) {
> + s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
> + aspeed_smc_flash_do_select(fl, unselect);
> + }
> }
>
> static void aspeed_smc_reset(DeviceState *d)
> @@ -729,6 +742,8 @@ static void aspeed_smc_reset(DeviceState *d)
> qemu_set_irq(s->cs_lines[i], true);
> }
>
> + s->unselect = true;
> +
> /* setup the default segment register values and regions for all */
> for (i = 0; i < asc->cs_num_max; ++i) {
> aspeed_smc_flash_set_segment_region(s, i,
> @@ -1261,12 +1276,13 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
>
> static const VMStateDescription vmstate_aspeed_smc = {
> .name = "aspeed.smc",
> - .version_id = 2,
> + .version_id = 3,
> .minimum_version_id = 2,
> .fields = (const VMStateField[]) {
> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
> VMSTATE_UINT8(snoop_index, AspeedSMCState),
> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
> + VMSTATE_BOOL(unselect, AspeedSMCState),
> VMSTATE_END_OF_LIST()
> }
> };
> diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
> index 234dca32b0..25b95e7406 100644
> --- a/include/hw/ssi/aspeed_smc.h
> +++ b/include/hw/ssi/aspeed_smc.h
> @@ -82,6 +82,7 @@ struct AspeedSMCState {
>
> uint8_t snoop_index;
> uint8_t snoop_dummies;
> + bool unselect;
> };
>
> typedef struct AspeedSegments {
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
2024-10-22 10:48 ` Cédric Le Goater
@ 2024-10-22 10:49 ` Kevin Wolf
2024-10-22 13:40 ` Cédric Le Goater
1 sibling, 1 reply; 41+ messages in thread
From: Kevin Wolf @ 2024-10-22 10:49 UTC (permalink / raw)
To: Jamin Lin
Cc: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
troy_lee, yunlin.tang
Am 22.10.2024 um 11:40 hat Jamin Lin geschrieben:
> According to the design of ASPEED SPI controllers user mode, users write the
> data to flash, the SPI drivers set the Control Register(0x10) bit 0 and 1
> enter user mode. Then, SPI drivers send flash commands for writing data.
> Finally, SPI drivers set the Control Register (0x10) bit 2 to stop
> active control and restore bit 0 and 1.
>
> According to the design of ASPEED SMC model, firmware writes the
> Control Register and the "aspeed_smc_flash_update_ctrl" function is called.
> Then, this function verify Control Register(0x10) bit 0 and 1. If it set user
> mode, the value of s->snoop_index is SNOOP_START else SNOOP_OFF.
> If s->snoop_index is SNOOP_START, the "aspeed_smc_do_snoop" function verify
> the first incomming data is a new flash command and writes the corresponding
> dummy bytes if need.
>
> However, it did not check the current unselect status. If current unselect
> status is "false" and firmware set the IO MODE by Control Register bit 31:28,
> the value of s->snoop_index will be changed to SNOOP_START again and
> "aspeed_smc_do_snoop" misunderstand that the incomming data is the new flash
> command and it causes writing unexpected data into flash.
>
> Example:
> 1. Firmware set user mode by Control Register bit 0 and 1(0x03)
> 2. SMC model set s->snoop SNOOP_START
> 3. Firmware set Quad Page Program with 4-Byte Address command (0x34)
> 4. SMC model verify this flash command and it needs 4 dummy bytes.
> 5. Firmware send 4 bytes address.
> 6. SMC model receives 4 bytes address
> 7. Firmware set QPI IO MODE by Control Register bit 31. (0x80000003)
> 8. SMC model verify new user mode by Control Register bit 0 and 1.
> Then, set s->snoop SNOOP_START again. (It is the wrong behavior.)
> 9. Firmware send 0xebd8c134 data and it should be written into flash.
> However, SMC model misunderstand that the first incoming data, 0x34,
> is the new command because the value of s->snoop is changed to SNOOP_START.
> Finally, SMC sned the incorrect data to flash model.
>
> Introduce a new unselect attribute in AspeedSMCState to save the current
> unselect status for user mode and set it "true" by default.
> Update "aspeed_smc_flash_update_ctrl" function to check the previous unselect
> status. If both new unselect status and previous unselect status is different,
> update s->snoop_index value and call "aspeed_smc_flash_do_select".
>
> Increase VMStateDescription version.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> @@ -1261,12 +1276,13 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
>
> static const VMStateDescription vmstate_aspeed_smc = {
> .name = "aspeed.smc",
> - .version_id = 2,
> + .version_id = 3,
> .minimum_version_id = 2,
> .fields = (const VMStateField[]) {
> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
> VMSTATE_UINT8(snoop_index, AspeedSMCState),
> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
> + VMSTATE_BOOL(unselect, AspeedSMCState),
> VMSTATE_END_OF_LIST()
> }
> };
I think this will break migration compatibility. In order to enable
at least forward migration, it should be:
VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
For allowing backwards migration, too, we should consider making it a
subsection instead that allows migration in the default case of an idle
device.
Kevin
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 10:49 ` Kevin Wolf
@ 2024-10-22 13:40 ` Cédric Le Goater
2024-10-22 15:23 ` Kevin Wolf
2024-10-23 1:41 ` Jamin Lin
0 siblings, 2 replies; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-22 13:40 UTC (permalink / raw)
To: Kevin Wolf, Jamin Lin
Cc: Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery, Joel Stanley,
Alistair Francis, Hanna Reitz, Thomas Huth, Laurent Vivier,
Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
troy_lee, yunlin.tang
>>
>> static const VMStateDescription vmstate_aspeed_smc = {
>> .name = "aspeed.smc",
>> - .version_id = 2,
>> + .version_id = 3,
>> .minimum_version_id = 2,
>> .fields = (const VMStateField[]) {
>> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
>> VMSTATE_UINT8(snoop_index, AspeedSMCState),
>> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
>> + VMSTATE_BOOL(unselect, AspeedSMCState),
>> VMSTATE_END_OF_LIST()
>> }
>> };
>
> I think this will break migration compatibility. In order to enable
> at least forward migration, it should be:
>
> VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
This is correct. I will fix the patch.
Some background,
The aspeed machines are fully emulated and the Aspeed SoC models are not
part of any virt* machines (yet). So migration support is a bit of a
theory. We have done our best to maintain some support, compatibility
not being a priority. IOW, it's not perfectly tuned as on virt machines.
Also, on ARM, migration of the CPU secure mode (I think this is the reason,
Peter please correct me !) is not supported and if migration is initiated
after Linux has started, the machine will hang.
However, if one day, an aspeed model becomes part of a virt machine, we
should be more careful. I would start by resetting all vmstate versions
to 1!
Thanks,
C.
>
> For allowing backwards migration, too, we should consider making it a
> subsection instead that allows migration in the default case of an idle
> device.
>
> Kevin
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field
2024-10-22 9:41 ` [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field Jamin Lin via
@ 2024-10-22 13:48 ` Cédric Le Goater
2024-10-23 1:40 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-22 13:48 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
On 10/22/24 11:41, Jamin Lin wrote:
> Currently, these test cases used the hardcode offset 0x1400000 (0x14000 * 256)
> which was beyond the 16MB flash size for flash page read/write command testing.
> However, the default fmc flash model of ast1030-a1 EVB is "w25q80bl" whose size
> is 1MB. To test all flash models, introduces a new page_addr member in TestData
I will change : s/all/SoC/
> structure, so users can set the offset for flash parge read/write command
> testing.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
with that,
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> tests/qtest/aspeed_smc-test.c | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
> index b8ab20b43d..6db18451d2 100644
> --- a/tests/qtest/aspeed_smc-test.c
> +++ b/tests/qtest/aspeed_smc-test.c
> @@ -72,6 +72,7 @@ typedef struct TestData {
> char *tmp_path;
> uint8_t cs;
> const char *node;
> + uint32_t page_addr;
> } TestData;
>
> /*
> @@ -256,7 +257,7 @@ static void assert_page_mem(const TestData *data, uint32_t addr,
> static void test_erase_sector(const void *data)
> {
> const TestData *test_data = (const TestData *)data;
> - uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
> + uint32_t some_page_addr = test_data->page_addr;
> uint32_t page[FLASH_PAGE_SIZE / 4];
> int i;
>
> @@ -308,7 +309,7 @@ static void test_erase_sector(const void *data)
> static void test_erase_all(const void *data)
> {
> const TestData *test_data = (const TestData *)data;
> - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> + uint32_t some_page_addr = test_data->page_addr;
> uint32_t page[FLASH_PAGE_SIZE / 4];
> int i;
>
> @@ -358,8 +359,8 @@ static void test_erase_all(const void *data)
> static void test_write_page(const void *data)
> {
> const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
> - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> uint32_t page[FLASH_PAGE_SIZE / 4];
> int i;
>
> @@ -395,8 +396,8 @@ static void test_write_page(const void *data)
> static void test_read_page_mem(const void *data)
> {
> const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
> - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> uint32_t page[FLASH_PAGE_SIZE / 4];
> int i;
>
> @@ -438,7 +439,7 @@ static void test_read_page_mem(const void *data)
> static void test_write_page_mem(const void *data)
> {
> const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> + uint32_t my_page_addr = test_data->page_addr;
> uint32_t page[FLASH_PAGE_SIZE / 4];
> int i;
>
> @@ -679,6 +680,8 @@ static void test_palmetto_bmc(TestData *data)
> data->jedec_id = 0x20ba19;
> data->cs = 0;
> data->node = "/machine/soc/fmc/ssi.0/child[0]";
> + /* beyond 16MB */
> + data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
>
> qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec);
> qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-10-22 10:48 ` Cédric Le Goater
@ 2024-10-22 14:10 ` Cédric Le Goater
2024-10-23 2:46 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-22 14:10 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
oops. R-b sent on the wrong patch.
On 10/22/24 12:48, Cédric Le Goater wrote:
> On 10/22/24 11:40, Jamin Lin wrote:
>> It only attached flash model of fmc and spi[0] in aspeed_machine_init function.
>> However, AST2500 and AST2600 have one fmc and two spi(spi1 and spi2)
>> controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2) controllers.
>>
>> Besides, it used hardcode to attach flash model of fmc, spi[0] and spi[1] in
>> aspeed_minibmc_machine_init for AST1030.
>>
>> To make both functions more flexible and support all ASPEED SOCs spi
>> controllers, adds a for loop with sc->spis_num to attach flash model of
>> all supported spi controllers. The sc->spis_num is from AspeedSoCClass.
To be honest, I am not a big fan of the aspeed_board_init_flashes()
routine. See commit 27a2c66c92ec for the reason.
I prefer the more flexible approach :
$ qemu-system-arm -M ast2600-evb \
-blockdev node-name=fmc0,driver=file,filename=/path/to/fmc0.img \
-device mx66u51235f,bus=ssi.0,cs=0x0,drive=fmc0 \
-blockdev node-name=fmc1,driver=file,filename=/path/to/fmc1.img \
-device mx66u51235f,bus=ssi.0,cs=0x1,drive=fmc1 \
-blockdev node-name=spi1,driver=file,filename=/path/to/spi1.img \
-device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
-nographic -nodefaults
which doesn't use the drive_get() interface and so, doesn't make
assumption on the order of the drives defined on the QEMU command
line.
Also, the number of availabe flash devices is a machine definition,
not a SoC definition. Not all CS are wired.
I will drop that patch for now.
Thanks,
C.
>> ---
>> hw/arm/aspeed.c | 21 ++++++++++++---------
>> 1 file changed, 12 insertions(+), 9 deletions(-)
>>
>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
>> index b4b1ce9efb..7ac01a3562 100644
>> --- a/hw/arm/aspeed.c
>> +++ b/hw/arm/aspeed.c
>> @@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState *machine)
>> aspeed_board_init_flashes(&bmc->soc->fmc,
>> bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
>> amc->num_cs, 0);
>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
>> - bmc->spi_model ? bmc->spi_model : amc->spi_model,
>> - 1, amc->num_cs);
>> + for (i = 0; i < sc->spis_num; i++) {
>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
>> + bmc->spi_model ? bmc->spi_model : amc->spi_model,
>> + amc->num_cs, amc->num_cs + (amc->num_cs * i));
>> + }
>> }
>> if (machine->kernel_filename && sc->num_cpus > 1) {
>> @@ -1579,7 +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
>> {
>> AspeedMachineState *bmc = ASPEED_MACHINE(machine);
>> AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
>> + AspeedSoCClass *sc;
>> Clock *sysclk;
>> + int i;
>> sysclk = clock_new(OBJECT(machine), "SYSCLK");
>> clock_set_hz(sysclk, SYSCLK_FRQ);
>> @@ -1587,6 +1591,7 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
>> bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
>> object_property_add_child(OBJECT(machine), "soc", OBJECT(bmc->soc));
>> object_unref(OBJECT(bmc->soc));
>> + sc = ASPEED_SOC_GET_CLASS(bmc->soc);
>> qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
>> object_property_set_link(OBJECT(bmc->soc), "memory",
>> @@ -1599,13 +1604,11 @@ static void aspeed_minibmc_machine_init(MachineState *machine)
>> amc->num_cs,
>> 0);
>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
>> - bmc->spi_model ? bmc->spi_model : amc->spi_model,
>> - amc->num_cs, amc->num_cs);
>> -
>> - aspeed_board_init_flashes(&bmc->soc->spi[1],
>> + for (i = 0; i < sc->spis_num; i++) {
>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
>> bmc->spi_model ? bmc->spi_model : amc->spi_model,
>> - amc->num_cs, (amc->num_cs * 2));
>> + amc->num_cs, amc->num_cs + (amc->num_cs * i));
>> + }
>> if (amc->i2c_init) {
>> amc->i2c_init(bmc);
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 13:40 ` Cédric Le Goater
@ 2024-10-22 15:23 ` Kevin Wolf
2024-10-24 6:06 ` Cédric Le Goater
2024-10-23 1:41 ` Jamin Lin
1 sibling, 1 reply; 41+ messages in thread
From: Kevin Wolf @ 2024-10-22 15:23 UTC (permalink / raw)
To: Cédric Le Goater
Cc: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Hanna Reitz, Thomas Huth,
Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
troy_lee, yunlin.tang
Am 22.10.2024 um 15:40 hat Cédric Le Goater geschrieben:
> > > static const VMStateDescription vmstate_aspeed_smc = {
> > > .name = "aspeed.smc",
> > > - .version_id = 2,
> > > + .version_id = 3,
> > > .minimum_version_id = 2,
> > > .fields = (const VMStateField[]) {
> > > VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
> > > VMSTATE_UINT8(snoop_index, AspeedSMCState),
> > > VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
> > > + VMSTATE_BOOL(unselect, AspeedSMCState),
> > > VMSTATE_END_OF_LIST()
> > > }
> > > };
> >
> > I think this will break migration compatibility. In order to enable
> > at least forward migration, it should be:
> >
> > VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
>
> This is correct. I will fix the patch.
>
> Some background,
>
> The aspeed machines are fully emulated and the Aspeed SoC models are not
> part of any virt* machines (yet). So migration support is a bit of a
> theory. We have done our best to maintain some support, compatibility
> not being a priority. IOW, it's not perfectly tuned as on virt machines.
>
> Also, on ARM, migration of the CPU secure mode (I think this is the reason,
> Peter please correct me !) is not supported and if migration is initiated
> after Linux has started, the machine will hang.
That's a good reason not to implement backwards migration for now, it
would only complicate things. But as long as we claim to be migratable
by having VMStateDescriptions and even increasing version_id, we should
at least try to keep that part correct.
> However, if one day, an aspeed model becomes part of a virt machine, we
> should be more careful. I would start by resetting all vmstate versions
> to 1!
Why would you reset it? Keeping 3 (or whatever it will be by then) as
the first serious supported version shouldn't hurt and probably avoids
some confusion.
Kevin
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field
2024-10-22 13:48 ` Cédric Le Goater
@ 2024-10-23 1:40 ` Jamin Lin
0 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin @ 2024-10-23 1:40 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a
> "page_addr" data field
>
> On 10/22/24 11:41, Jamin Lin wrote:
> > Currently, these test cases used the hardcode offset 0x1400000
> > (0x14000 * 256) which was beyond the 16MB flash size for flash page
> read/write command testing.
> > However, the default fmc flash model of ast1030-a1 EVB is "w25q80bl"
> > whose size is 1MB. To test all flash models, introduces a new
> > page_addr member in TestData
>
> I will change : s/all/SoC/
>
Thanks for help.
If I need to re-send v3 patch, I will fix it.
Thanks-Jamin
> > structure, so users can set the offset for flash parge read/write
> > command testing.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>
> with that,
>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
>
> Thanks,
>
> C.
>
>
> > ---
> > tests/qtest/aspeed_smc-test.c | 17 ++++++++++-------
> > 1 file changed, 10 insertions(+), 7 deletions(-)
> >
> > diff --git a/tests/qtest/aspeed_smc-test.c
> > b/tests/qtest/aspeed_smc-test.c index b8ab20b43d..6db18451d2 100644
> > --- a/tests/qtest/aspeed_smc-test.c
> > +++ b/tests/qtest/aspeed_smc-test.c
> > @@ -72,6 +72,7 @@ typedef struct TestData {
> > char *tmp_path;
> > uint8_t cs;
> > const char *node;
> > + uint32_t page_addr;
> > } TestData;
> >
> > /*
> > @@ -256,7 +257,7 @@ static void assert_page_mem(const TestData *data,
> uint32_t addr,
> > static void test_erase_sector(const void *data)
> > {
> > const TestData *test_data = (const TestData *)data;
> > - uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
> > + uint32_t some_page_addr = test_data->page_addr;
> > uint32_t page[FLASH_PAGE_SIZE / 4];
> > int i;
> >
> > @@ -308,7 +309,7 @@ static void test_erase_sector(const void *data)
> > static void test_erase_all(const void *data)
> > {
> > const TestData *test_data = (const TestData *)data;
> > - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> > + uint32_t some_page_addr = test_data->page_addr;
> > uint32_t page[FLASH_PAGE_SIZE / 4];
> > int i;
> >
> > @@ -358,8 +359,8 @@ static void test_erase_all(const void *data)
> > static void test_write_page(const void *data)
> > {
> > const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond
> 16MB */
> > - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> > + uint32_t my_page_addr = test_data->page_addr;
> > + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> > uint32_t page[FLASH_PAGE_SIZE / 4];
> > int i;
> >
> > @@ -395,8 +396,8 @@ static void test_write_page(const void *data)
> > static void test_read_page_mem(const void *data)
> > {
> > const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond
> 16MB */
> > - uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> > + uint32_t my_page_addr = test_data->page_addr;
> > + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> > uint32_t page[FLASH_PAGE_SIZE / 4];
> > int i;
> >
> > @@ -438,7 +439,7 @@ static void test_read_page_mem(const void *data)
> > static void test_write_page_mem(const void *data)
> > {
> > const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
> > + uint32_t my_page_addr = test_data->page_addr;
> > uint32_t page[FLASH_PAGE_SIZE / 4];
> > int i;
> >
> > @@ -679,6 +680,8 @@ static void test_palmetto_bmc(TestData *data)
> > data->jedec_id = 0x20ba19;
> > data->cs = 0;
> > data->node = "/machine/soc/fmc/ssi.0/child[0]";
> > + /* beyond 16MB */
> > + data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
> >
> > qtest_add_data_func("/ast2400/smc/read_jedec", data,
> test_read_jedec);
> > qtest_add_data_func("/ast2400/smc/erase_sector", data,
> > test_erase_sector);
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 13:40 ` Cédric Le Goater
2024-10-22 15:23 ` Kevin Wolf
@ 2024-10-23 1:41 ` Jamin Lin
2024-10-24 6:13 ` Cédric Le Goater
1 sibling, 1 reply; 41+ messages in thread
From: Jamin Lin @ 2024-10-23 1:41 UTC (permalink / raw)
To: Cédric Le Goater, Kevin Wolf
Cc: Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery, Joel Stanley,
Alistair Francis, Hanna Reitz, Thomas Huth, Laurent Vivier,
Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in
> user mode
>
> >>
> >> static const VMStateDescription vmstate_aspeed_smc = {
> >> .name = "aspeed.smc",
> >> - .version_id = 2,
> >> + .version_id = 3,
> >> .minimum_version_id = 2,
> >> .fields = (const VMStateField[]) {
> >> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState,
> ASPEED_SMC_R_MAX),
> >> VMSTATE_UINT8(snoop_index, AspeedSMCState),
> >> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
> >> + VMSTATE_BOOL(unselect, AspeedSMCState),
> >> VMSTATE_END_OF_LIST()
> >> }
> >> };
> >
> > I think this will break migration compatibility. In order to enable at
> > least forward migration, it should be:
> >
> > VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
>
> This is correct. I will fix the patch.
>
If I need to re-send v3 patch, I will fix it.
Thanks for help.
Jamin
> Some background,
>
> The aspeed machines are fully emulated and the Aspeed SoC models are not
> part of any virt* machines (yet). So migration support is a bit of a theory. We
> have done our best to maintain some support, compatibility not being a
> priority. IOW, it's not perfectly tuned as on virt machines.
>
> Also, on ARM, migration of the CPU secure mode (I think this is the reason,
> Peter please correct me !) is not supported and if migration is initiated after
> Linux has started, the machine will hang.
>
> However, if one day, an aspeed model becomes part of a virt machine, we
> should be more careful. I would start by resetting all vmstate versions to 1!
>
> Thanks,
>
> C.
>
>
>
> >
> > For allowing backwards migration, too, we should consider making it a
> > subsection instead that allows migration in the default case of an
> > idle device.
> >
> > Kevin
> >
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-10-22 14:10 ` Cédric Le Goater
@ 2024-10-23 2:46 ` Jamin Lin
2024-11-26 16:39 ` Cédric Le Goater
0 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin @ 2024-10-23 2:46 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi
> controllers
>
> oops. R-b sent on the wrong patch.
>
> On 10/22/24 12:48, Cédric Le Goater wrote:
> > On 10/22/24 11:40, Jamin Lin wrote:
> >> It only attached flash model of fmc and spi[0] in aspeed_machine_init
> function.
> >> However, AST2500 and AST2600 have one fmc and two spi(spi1 and spi2)
> >> controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2) controllers.
> >>
> >> Besides, it used hardcode to attach flash model of fmc, spi[0] and
> >> spi[1] in aspeed_minibmc_machine_init for AST1030.
> >>
> >> To make both functions more flexible and support all ASPEED SOCs spi
> >> controllers, adds a for loop with sc->spis_num to attach flash model
> >> of all supported spi controllers. The sc->spis_num is from AspeedSoCClass.
>
> To be honest, I am not a big fan of the aspeed_board_init_flashes() routine.
> See commit 27a2c66c92ec for the reason.
>
> I prefer the more flexible approach :
>
> $ qemu-system-arm -M ast2600-evb \
> -blockdev node-name=fmc0,driver=file,filename=/path/to/fmc0.img \
> -device mx66u51235f,bus=ssi.0,cs=0x0,drive=fmc0 \
> -blockdev node-name=fmc1,driver=file,filename=/path/to/fmc1.img \
> -device mx66u51235f,bus=ssi.0,cs=0x1,drive=fmc1 \
> -blockdev node-name=spi1,driver=file,filename=/path/to/spi1.img \
> -device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
> -nographic -nodefaults
>
Thanks for notify me this solution.
I can successfully attach the default image to supported SPI controllers with different flash model.
It seems we need to add "defaults_enabled()" if-statement in aspeed_minibmc_machine_init
to support this solution for AST1030. Otherwise, I will get this error.
qemu-system-arm: -device w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0: CS index '0x0' in use by a w25q80bl device
https://github.com/qemu/qemu/blob/master/hw/arm/aspeed.c
if (defaults_enabled()) {
aspeed_board_init_flashes(&bmc->soc->fmc,
bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
amc->num_cs,
0);
aspeed_board_init_flashes(&bmc->soc->spi[0],
bmc->spi_model ? bmc->spi_model : amc->spi_model,
amc->num_cs, amc->num_cs);
aspeed_board_init_flashes(&bmc->soc->spi[1],
bmc->spi_model ? bmc->spi_model : amc->spi_model,
amc->num_cs, (amc->num_cs * 2));
}
Do I need to send this patch in v3 patch series?
Or individually send this patch in the new patch series?
AST1030:
-blockdev node-name=fmc0,driver=file,filename=./fmc_cs0_img \
-device w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0 \
-blockdev node-name=fmc1,driver=file,filename=./fmc_cs1_img \
-device w25q80bl,bus=ssi.0,cs=0x1,drive=fmc1 \
-blockdev node-name=spi1c0,driver=file,filename=./spi1_cs0_img \
-device w25q256,bus=ssi.1,cs=0x0,drive=spi1c0 \
-blockdev node-name=spi1c1,driver=file,filename=./spi1_cs1_img \
-device w25q256,bus=ssi.1,cs=0x1,drive=spi1c1 \
-blockdev node-name=spi2c0,driver=file,filename=./spi2_cs0_img \
-device w25q256,bus=ssi.2,cs=0x0,drive=spi2c0 \
-blockdev node-name=spi2c1,driver=file,filename=./spi2_cs1_img \
-device w25q256,bus=ssi.2,cs=0x1,drive=spi2c1 \
-nodefaults
AST2600:
-blockdev node-name=fmc0,driver=file,filename=$1 \
-device mx66u51235f,cs=0x0,bus=ssi.0,drive=fmc0 \
-blockdev node-name=fmc1,driver=file,filename=./fmc_cs1_img \
-device mx66u51235f,cs=0x1,bus=ssi.0,drive=fmc1 \
-blockdev node-name=spi1,driver=file,filename=./spi1_cs0_img \
-device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
-blockdev node-name=spi2,driver=file,filename=./spi2_cs0_img \
-device mx66u51235f,cs=0x0,bus=ssi.2,drive=spi2 \
-nodefaults
> which doesn't use the drive_get() interface and so, doesn't make assumption
> on the order of the drives defined on the QEMU command line.
>
> Also, the number of availabe flash devices is a machine definition, not a SoC
> definition. Not all CS are wired.
>
> I will drop that patch for now.
>
Understand and thanks for suggestion.
Jamin
>
> Thanks,
>
> C.
>
>
>
> >> ---
> >> hw/arm/aspeed.c | 21 ++++++++++++---------
> >> 1 file changed, 12 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index
> >> b4b1ce9efb..7ac01a3562 100644
> >> --- a/hw/arm/aspeed.c
> >> +++ b/hw/arm/aspeed.c
> >> @@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState
> >> *machine)
> >> aspeed_board_init_flashes(&bmc->soc->fmc,
> >> bmc->fmc_model ?
> bmc->fmc_model :
> >> amc->fmc_model,
> >> amc->num_cs, 0);
> >> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> >> - bmc->spi_model ?
> bmc->spi_model :
> >> amc->spi_model,
> >> - 1, amc->num_cs);
> >> + for (i = 0; i < sc->spis_num; i++) {
> >> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> >> + bmc->spi_model ?
> bmc->spi_model :
> >> +amc->spi_model,
> >> + amc->num_cs, amc->num_cs +
> (amc->num_cs
> >> +* i));
> >> + }
> >> }
> >> if (machine->kernel_filename && sc->num_cpus > 1) { @@
> -1579,7
> >> +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState
> >> *machine)
> >> {
> >> AspeedMachineState *bmc = ASPEED_MACHINE(machine);
> >> AspeedMachineClass *amc =
> ASPEED_MACHINE_GET_CLASS(machine);
> >> + AspeedSoCClass *sc;
> >> Clock *sysclk;
> >> + int i;
> >> sysclk = clock_new(OBJECT(machine), "SYSCLK");
> >> clock_set_hz(sysclk, SYSCLK_FRQ); @@ -1587,6 +1591,7 @@
> static
> >> void aspeed_minibmc_machine_init(MachineState *machine)
> >> bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
> >> object_property_add_child(OBJECT(machine), "soc",
> >> OBJECT(bmc->soc));
> >> object_unref(OBJECT(bmc->soc));
> >> + sc = ASPEED_SOC_GET_CLASS(bmc->soc);
> >> qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
> >> object_property_set_link(OBJECT(bmc->soc), "memory", @@
> >> -1599,13 +1604,11 @@ static void
> >> aspeed_minibmc_machine_init(MachineState *machine)
> >> amc->num_cs,
> >> 0);
> >> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> >> - bmc->spi_model ?
> bmc->spi_model :
> >> amc->spi_model,
> >> - amc->num_cs,
> amc->num_cs);
> >> -
> >> - aspeed_board_init_flashes(&bmc->soc->spi[1],
> >> + for (i = 0; i < sc->spis_num; i++) {
> >> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> >> bmc->spi_model ?
> bmc->spi_model :
> >> amc->spi_model,
> >> - amc->num_cs,
> (amc->num_cs * 2));
> >> + amc->num_cs,
> amc->num_cs +
> >> +(amc->num_cs * i));
> >> + }
> >> if (amc->i2c_init) {
> >> amc->i2c_init(bmc);
> >
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-22 15:23 ` Kevin Wolf
@ 2024-10-24 6:06 ` Cédric Le Goater
0 siblings, 0 replies; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-24 6:06 UTC (permalink / raw)
To: Kevin Wolf
Cc: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Hanna Reitz, Thomas Huth,
Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
troy_lee, yunlin.tang
On 10/22/24 17:23, Kevin Wolf wrote:
> Am 22.10.2024 um 15:40 hat Cédric Le Goater geschrieben:
>>>> static const VMStateDescription vmstate_aspeed_smc = {
>>>> .name = "aspeed.smc",
>>>> - .version_id = 2,
>>>> + .version_id = 3,
>>>> .minimum_version_id = 2,
>>>> .fields = (const VMStateField[]) {
>>>> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
>>>> VMSTATE_UINT8(snoop_index, AspeedSMCState),
>>>> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
>>>> + VMSTATE_BOOL(unselect, AspeedSMCState),
>>>> VMSTATE_END_OF_LIST()
>>>> }
>>>> };
>>>
>>> I think this will break migration compatibility. In order to enable
>>> at least forward migration, it should be:
>>>
>>> VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
>>
>> This is correct. I will fix the patch.
>>
>> Some background,
>>
>> The aspeed machines are fully emulated and the Aspeed SoC models are not
>> part of any virt* machines (yet). So migration support is a bit of a
>> theory. We have done our best to maintain some support, compatibility
>> not being a priority. IOW, it's not perfectly tuned as on virt machines.
>>
>> Also, on ARM, migration of the CPU secure mode (I think this is the reason,
>> Peter please correct me !) is not supported and if migration is initiated
>> after Linux has started, the machine will hang.
>
> That's a good reason not to implement backwards migration for now, it
> would only complicate things. But as long as we claim to be migratable
> by having VMStateDescriptions and even increasing version_id, we should
> at least try to keep that part correct.
Sure. Thanks for pointing that out.
>> However, if one day, an aspeed model becomes part of a virt machine, we
>> should be more careful. I would start by resetting all vmstate versions
>> to 1!
>
> Why would you reset it? Keeping 3 (or whatever it will be by then) as
> the first serious supported version shouldn't hurt and probably avoids
> some confusion.
OK . We'll see when we get to that point. Who knows. The Aspeed machines
have gotten much bigger than we expected !
C.
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
` (17 preceding siblings ...)
2024-10-22 9:41 ` [PATCH v2 18/18] test/qtest/ast2700-smc-test: Support to test AST2700 Jamin Lin via
@ 2024-10-24 6:11 ` Cédric Le Goater
2024-10-24 6:14 ` Jamin Lin
18 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-24 6:11 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
Hello Jamin,
On 10/22/24 11:40, Jamin Lin wrote:
> change from v1:
> 1. Fix write incorrect data into flash in user mode.
> 2. Refactor aspeed smc qtest testcases to support AST2600, AST2500 and
> AST1030.
> 3. Add ast2700 smc qtest testcase to support AST2700.
>
> change from v2:
> 1. Introduce a new aspeed-smc-utils.c to place common testcases.
> 2. Fix hardcode attach flash model of spi controllers
> 3. Add reviewers suggestion and fix review issue.
I have applied 1-6,8 to aspeed-next and should send a PR with them. I kept
the test extensions for later, to take a closer a look and also because
I will be on PTO next week. Tests can be merged in the next PR if we have
time in this cycle or in QEMU 10.0.
Thanks,
C.
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in user mode
2024-10-23 1:41 ` Jamin Lin
@ 2024-10-24 6:13 ` Cédric Le Goater
0 siblings, 0 replies; 41+ messages in thread
From: Cédric Le Goater @ 2024-10-24 6:13 UTC (permalink / raw)
To: Jamin Lin, Kevin Wolf
Cc: Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery, Joel Stanley,
Alistair Francis, Hanna Reitz, Thomas Huth, Laurent Vivier,
Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core,
Troy Lee, Yunlin Tang
On 10/23/24 03:41, Jamin Lin wrote:
> Hi Cedric,
>
>> Subject: Re: [PATCH v2 01/18] aspeed/smc: Fix write incorrect data into flash in
>> user mode
>>
>>>>
>>>> static const VMStateDescription vmstate_aspeed_smc = {
>>>> .name = "aspeed.smc",
>>>> - .version_id = 2,
>>>> + .version_id = 3,
>>>> .minimum_version_id = 2,
>>>> .fields = (const VMStateField[]) {
>>>> VMSTATE_UINT32_ARRAY(regs, AspeedSMCState,
>> ASPEED_SMC_R_MAX),
>>>> VMSTATE_UINT8(snoop_index, AspeedSMCState),
>>>> VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
>>>> + VMSTATE_BOOL(unselect, AspeedSMCState),
>>>> VMSTATE_END_OF_LIST()
>>>> }
>>>> };
>>>
>>> I think this will break migration compatibility. In order to enable at
>>> least forward migration, it should be:
>>>
>>> VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
>>
>> This is correct. I will fix the patch.
>>
> If I need to re-send v3 patch, I will fix it.
I took care of it. No need to resend.
Thanks
C.
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
2024-10-24 6:11 ` [PATCH v2 00/18] Fix write incorrect data into flash in user mode Cédric Le Goater
@ 2024-10-24 6:14 ` Jamin Lin
2024-11-14 5:30 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin @ 2024-10-24 6:14 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
>
> Hello Jamin,
>
> On 10/22/24 11:40, Jamin Lin wrote:
> > change from v1:
> > 1. Fix write incorrect data into flash in user mode.
> > 2. Refactor aspeed smc qtest testcases to support AST2600, AST2500
> > and AST1030.
> > 3. Add ast2700 smc qtest testcase to support AST2700.
> >
> > change from v2:
> > 1. Introduce a new aspeed-smc-utils.c to place common testcases.
> > 2. Fix hardcode attach flash model of spi controllers 3. Add reviewers
> > suggestion and fix review issue.
> I have applied 1-6,8 to aspeed-next and should send a PR with them. I kept the
> test extensions for later, to take a closer a look and also because I will be on
> PTO next week. Tests can be merged in the next PR if we have time in this cycle
> or in QEMU 10.0.
>
Got it and thanks for help.
Jamin
> Thanks,
>
> C.
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
2024-10-24 6:14 ` Jamin Lin
@ 2024-11-14 5:30 ` Jamin Lin
2024-11-14 7:38 ` Cédric Le Goater
0 siblings, 1 reply; 41+ messages in thread
From: Jamin Lin @ 2024-11-14 5:30 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: RE: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
>
> Hi Cedric,
>
> > Subject: Re: [PATCH v2 00/18] Fix write incorrect data into flash in
> > user mode
> >
> > Hello Jamin,
> >
> > On 10/22/24 11:40, Jamin Lin wrote:
> > > change from v1:
> > > 1. Fix write incorrect data into flash in user mode.
> > > 2. Refactor aspeed smc qtest testcases to support AST2600, AST2500
> > > and AST1030.
> > > 3. Add ast2700 smc qtest testcase to support AST2700.
> > >
> > > change from v2:
> > > 1. Introduce a new aspeed-smc-utils.c to place common testcases.
> > > 2. Fix hardcode attach flash model of spi controllers 3. Add
> > > reviewers suggestion and fix review issue.
> > I have applied 1-6,8 to aspeed-next and should send a PR with them. I
> > kept the test extensions for later, to take a closer a look and also
> > because I will be on PTO next week. Tests can be merged in the next PR
> > if we have time in this cycle or in QEMU 10.0.
> >
> Got it and thanks for help.
> Jamin
> > Thanks,
Could you please help to review patch 17 and 18 ?
Do I need to re-send patch from 9 to 18 of this patch series?
Thanks-Jamin
> >
> > C.
> >
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
2024-11-14 5:30 ` Jamin Lin
@ 2024-11-14 7:38 ` Cédric Le Goater
2024-11-14 8:50 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-11-14 7:38 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hello Jamin,
On 11/14/24 06:30, Jamin Lin wrote:
> Hi Cedric,
>
>> Subject: RE: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
>>
>> Hi Cedric,
>>
>>> Subject: Re: [PATCH v2 00/18] Fix write incorrect data into flash in
>>> user mode
>>>
>>> Hello Jamin,
>>>
>>> On 10/22/24 11:40, Jamin Lin wrote:
>>>> change from v1:
>>>> 1. Fix write incorrect data into flash in user mode.
>>>> 2. Refactor aspeed smc qtest testcases to support AST2600, AST2500
>>>> and AST1030.
>>>> 3. Add ast2700 smc qtest testcase to support AST2700.
>>>>
>>>> change from v2:
>>>> 1. Introduce a new aspeed-smc-utils.c to place common testcases.
>>>> 2. Fix hardcode attach flash model of spi controllers 3. Add
>>>> reviewers suggestion and fix review issue.
>>> I have applied 1-6,8 to aspeed-next and should send a PR with them. I
>>> kept the test extensions for later, to take a closer a look and also
>>> because I will be on PTO next week. Tests can be merged in the next PR
>>> if we have time in this cycle or in QEMU 10.0.
>>>
>> Got it and thanks for help.
>> Jamin
>>> Thanks,
>
> Could you please help to review patch 17 and 18 ?
> Do I need to re-send patch from 9 to 18 of this patch series?
Not yet. I have some comments to send but I am busy on another topic.
We have some time before QEMU 10.0. They are in my aspeed-9.2 branch,
so that I don't forget about them.
Thanks,
C.
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
2024-11-14 7:38 ` Cédric Le Goater
@ 2024-11-14 8:50 ` Jamin Lin
0 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin @ 2024-11-14 8:50 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 00/18] Fix write incorrect data into flash in user mode
>
> Hello Jamin,
>
> On 11/14/24 06:30, Jamin Lin wrote:
> > Hi Cedric,
> >
> >> Subject: RE: [PATCH v2 00/18] Fix write incorrect data into flash in
> >> user mode
> >>
> >> Hi Cedric,
> >>
> >>> Subject: Re: [PATCH v2 00/18] Fix write incorrect data into flash in
> >>> user mode
> >>>
> >>> Hello Jamin,
> >>>
> >>> On 10/22/24 11:40, Jamin Lin wrote:
> >>>> change from v1:
> >>>> 1. Fix write incorrect data into flash in user mode.
> >>>> 2. Refactor aspeed smc qtest testcases to support AST2600,
> >>>> AST2500 and AST1030.
> >>>> 3. Add ast2700 smc qtest testcase to support AST2700.
> >>>>
> >>>> change from v2:
> >>>> 1. Introduce a new aspeed-smc-utils.c to place common testcases.
> >>>> 2. Fix hardcode attach flash model of spi controllers 3. Add
> >>>> reviewers suggestion and fix review issue.
> >>> I have applied 1-6,8 to aspeed-next and should send a PR with them.
> >>> I kept the test extensions for later, to take a closer a look and
> >>> also because I will be on PTO next week. Tests can be merged in the
> >>> next PR if we have time in this cycle or in QEMU 10.0.
> >>>
> >> Got it and thanks for help.
> >> Jamin
> >>> Thanks,
> >
> > Could you please help to review patch 17 and 18 ?
> > Do I need to re-send patch from 9 to 18 of this patch series?
>
> Not yet. I have some comments to send but I am busy on another topic.
>
Got it.
Thanks for your kindly support.
Jamin
> We have some time before QEMU 10.0. They are in my aspeed-9.2 branch, so
> that I don't forget about them.
>
> Thanks,
>
> C.
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 02/18] hw/block:m25p80: Fix coding style
2024-10-22 9:40 ` [PATCH v2 02/18] hw/block:m25p80: Fix coding style Jamin Lin via
@ 2024-11-15 16:44 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-11-15 16:44 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Andrew Jeffery, Joel Stanley, Alistair Francis,
Kevin Wolf, Hanna Reitz, Thomas Huth, Laurent Vivier,
Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang, Cédric Le Goater
On 22/10/24 10:40, Jamin Lin via wrote:
> Fix coding style issues from checkpatch.pl
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
> ---
> hw/block/m25p80.c | 22 ++++++++++++++--------
> 1 file changed, 14 insertions(+), 8 deletions(-)
> @@ -1843,7 +1849,7 @@ static void m25p80_register_types(void)
>
> type_register_static(&m25p80_info);
> for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
> - TypeInfo ti = {
> + const TypeInfo ti = {
This is a bit more than style change.
> .name = known_devices[i].part_name,
> .parent = TYPE_M25P80,
> .class_init = m25p80_class_init,
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases
2024-10-22 9:41 ` [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases Jamin Lin via
@ 2024-11-25 13:43 ` Cédric Le Goater
2024-11-26 3:07 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-11-25 13:43 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: troy_lee, yunlin.tang
On 10/22/24 11:41, Jamin Lin wrote:
> The testcases for ASPEED SMC model were placed in aspeed_smc-test.c.
> However, this test file only supports for ARM32. To support all ASPEED SOCs
> such as AST2700 whose CPU architecture is aarch64, introduces a new
> aspeed-smc-utils source file and move all common APIs and testcases
> from aspeed_smc-test.c to aspeed-smc-utils.c.
>
> Finally, users are able to re-used these testcase for AST2700 and future
> ASPEED SOCs testing.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> tests/qtest/aspeed-smc-utils.c | 681 ++++++++++++++++++++++++++++++++
> tests/qtest/aspeed-smc-utils.h | 95 +++++
> tests/qtest/aspeed_smc-test.c | 700 +--------------------------------
> tests/qtest/meson.build | 1 +
> 4 files changed, 778 insertions(+), 699 deletions(-)
> create mode 100644 tests/qtest/aspeed-smc-utils.c
> create mode 100644 tests/qtest/aspeed-smc-utils.h
>
> diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c
> new file mode 100644
> index 0000000000..37da5d1f3b
> --- /dev/null
> +++ b/tests/qtest/aspeed-smc-utils.c
> @@ -0,0 +1,681 @@
> +/*
> + * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
> + * Controller)
> + *
> + * Copyright (C) 2016 IBM Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/bswap.h"
> +#include "libqtest-single.h"
> +#include "qemu/bitops.h"
> +#include "aspeed-smc-utils.h"
> +
> +/*
> + * Use an explicit bswap for the values read/wrote to the flash region
> + * as they are BE and the Aspeed CPU is LE.
> + */
> +static inline uint32_t make_be32(uint32_t data)
> +{
> + return bswap32(data);
> +}
> +
> +static inline void spi_writel(const TestData *data, uint64_t offset,
> + uint32_t value)
> +{
> + qtest_writel(data->s, data->spi_base + offset, value);
> +}
> +
> +static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
> +{
> + return qtest_readl(data->s, data->spi_base + offset);
> +}
> +
> +static inline void flash_writeb(const TestData *data, uint64_t offset,
> + uint8_t value)
> +{
> + qtest_writeb(data->s, data->flash_base + offset, value);
> +}
> +
> +static inline void flash_writel(const TestData *data, uint64_t offset,
> + uint32_t value)
> +{
> + qtest_writel(data->s, data->flash_base + offset, value);
> +}
> +
> +static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
> +{
> + return qtest_readb(data->s, data->flash_base + offset);
> +}
> +
> +static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
> +{
> + return qtest_readl(data->s, data->flash_base + offset);
> +}
> +
> +static void spi_conf(const TestData *data, uint32_t value)
> +{
> + uint32_t conf = spi_readl(data, R_CONF);
> +
> + conf |= value;
> + spi_writel(data, R_CONF, conf);
> +}
> +
> +static void spi_conf_remove(const TestData *data, uint32_t value)
> +{
> + uint32_t conf = spi_readl(data, R_CONF);
> +
> + conf &= ~value;
> + spi_writel(data, R_CONF, conf);
> +}
> +
> +static void spi_ce_ctrl(const TestData *data, uint32_t value)
> +{
> + uint32_t conf = spi_readl(data, R_CE_CTRL);
> +
> + conf |= value;
> + spi_writel(data, R_CE_CTRL, conf);
> +}
> +
> +static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
> +{
> + uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> + uint32_t ctrl = spi_readl(data, ctrl_reg);
> + ctrl &= ~(CTRL_USERMODE | 0xff << 16);
> + ctrl |= mode | (cmd << 16);
> + spi_writel(data, ctrl_reg, ctrl);
> +}
> +
> +static void spi_ctrl_start_user(const TestData *data)
> +{
> + uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> + uint32_t ctrl = spi_readl(data, ctrl_reg);
> +
> + ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> + spi_writel(data, ctrl_reg, ctrl);
> +
> + ctrl &= ~CTRL_CE_STOP_ACTIVE;
> + spi_writel(data, ctrl_reg, ctrl);
> +}
> +
> +static void spi_ctrl_stop_user(const TestData *data)
> +{
> + uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> + uint32_t ctrl = spi_readl(data, ctrl_reg);
> +
> + ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> + spi_writel(data, ctrl_reg, ctrl);
> +}
> +
> +static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
> +{
> + uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> + uint32_t ctrl = spi_readl(data, ctrl_reg);
> + uint32_t mode;
> +
> + mode = value & CTRL_IO_MODE_MASK;
> + ctrl &= ~CTRL_IO_MODE_MASK;
> + ctrl |= mode;
> + spi_writel(data, ctrl_reg, ctrl);
> +}
> +
> +static void flash_reset(const TestData *data)
> +{
> + spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
> +
> + spi_ctrl_start_user(data);
> + flash_writeb(data, 0, RESET_ENABLE);
> + flash_writeb(data, 0, RESET_MEMORY);
> + flash_writeb(data, 0, WREN);
> + flash_writeb(data, 0, BULK_ERASE);
> + flash_writeb(data, 0, WRDI);
> + spi_ctrl_stop_user(data);
> +
> + spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
> +}
> +
> +static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
> +{
> + int i;
> +
> + spi_ctrl_start_user(data);
> +
> + flash_writeb(data, 0, EN_4BYTE_ADDR);
> + flash_writeb(data, 0, READ);
> + flash_writel(data, 0, make_be32(addr));
> +
> + /* Continuous read are supported */
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + page[i] = make_be32(flash_readl(data, 0));
> + }
> + spi_ctrl_stop_user(data);
> +}
> +
> +static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
> +{
> + int i;
> +
> + /* move out USER mode to use direct reads from the AHB bus */
> + spi_ctrl_setmode(data, CTRL_READMODE, READ);
> +
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + page[i] = make_be32(flash_readl(data, addr + i * 4));
> + }
> +}
> +
> +static void write_page_mem(const TestData *data, uint32_t addr,
> + uint32_t write_value)
> +{
> + spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
> +
> + for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(data, addr + i * 4, write_value);
> + }
> +}
> +
> +static void assert_page_mem(const TestData *data, uint32_t addr,
> + uint32_t expected_value)
> +{
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + read_page_mem(data, addr, page);
> + for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, expected_value);
> + }
> +}
> +
> +void test_read_jedec(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t jedec = 0x0;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, JEDEC_READ);
> + jedec |= flash_readb(test_data, 0) << 16;
> + jedec |= flash_readb(test_data, 0) << 8;
> + jedec |= flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> +
> + flash_reset(test_data);
> +
> + g_assert_cmphex(jedec, ==, test_data->jedec_id);
> +}
> +
> +void test_erase_sector(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t some_page_addr = test_data->page_addr;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + int i;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + /*
> + * Previous page should be full of 0xffs after backend is
> + * initialized
> + */
> + read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, PP);
> + flash_writel(test_data, 0, make_be32(some_page_addr));
> +
> + /* Fill the page with its own addresses */
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> + }
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check the page is correctly written */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> + }
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, ERASE_SECTOR);
> + flash_writel(test_data, 0, make_be32(some_page_addr));
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check the page is erased */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_erase_all(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t some_page_addr = test_data->page_addr;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + int i;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + /*
> + * Previous page should be full of 0xffs after backend is
> + * initialized
> + */
> + read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, PP);
> + flash_writel(test_data, 0, make_be32(some_page_addr));
> +
> + /* Fill the page with its own addresses */
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> + }
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check the page is correctly written */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> + }
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, BULK_ERASE);
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check the page is erased */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_write_page(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + int i;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, PP);
> + flash_writel(test_data, 0, make_be32(my_page_addr));
> +
> + /* Fill the page with its own addresses */
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> + }
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check what was written */
> + read_page(test_data, my_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> + }
> +
> + /* Check some other page. It should be full of 0xff */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_read_page_mem(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + int i;
> +
> + /*
> + * Enable 4BYTE mode for controller.
> + */
> + spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> +
> + /* Enable 4BYTE mode for flash. */
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, PP);
> + flash_writel(test_data, 0, make_be32(my_page_addr));
> +
> + /* Fill the page with its own addresses */
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> + }
> + spi_ctrl_stop_user(test_data);
> + spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + /* Check what was written */
> + read_page_mem(test_data, my_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> + }
> +
> + /* Check some other page. It should be full of 0xff */
> + read_page_mem(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_write_page_mem(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + int i;
> +
> + /*
> + * Enable 4BYTE mode for controller.
> + */
> + spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> +
> + /* Enable 4BYTE mode for flash. */
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + spi_ctrl_stop_user(test_data);
> +
> + /* move out USER mode to use direct writes to the AHB bus */
> + spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
> +
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, my_page_addr + i * 4,
> + make_be32(my_page_addr + i * 4));
> + }
> +
> + /* Check what was written */
> + read_page_mem(test_data, my_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_read_status_reg(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint8_t r;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> +
> + g_assert_cmphex(r & SR_WEL, ==, 0);
> + g_assert(!qtest_qom_get_bool
> + (test_data->s, test_data->node, "write-enable"));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> +
> + g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
> + g_assert(qtest_qom_get_bool
> + (test_data->s, test_data->node, "write-enable"));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WRDI);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> +
> + g_assert_cmphex(r & SR_WEL, ==, 0);
> + g_assert(!qtest_qom_get_bool
> + (test_data->s, test_data->node, "write-enable"));
> +
> + flash_reset(test_data);
> +}
> +
> +void test_status_reg_write_protection(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint8_t r;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + /* default case: WP# is high and SRWD is low -> status register writable */
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + /* test ability to write SRWD */
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, SRWD);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> + g_assert_cmphex(r & SRWD, ==, SRWD);
> +
> + /* WP# high and SRWD high -> status register writable */
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + /* test ability to write SRWD */
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, 0);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> + g_assert_cmphex(r & SRWD, ==, 0);
> +
> + /* WP# low and SRWD low -> status register writable */
> + qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + /* test ability to write SRWD */
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, SRWD);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> + g_assert_cmphex(r & SRWD, ==, SRWD);
> +
> + /* WP# low and SRWD high -> status register NOT writable */
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0 , WREN);
> + /* test ability to write SRWD */
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, 0);
> + flash_writeb(test_data, 0, RDSR);
> + r = flash_readb(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> + /* write is not successful */
> + g_assert_cmphex(r & SRWD, ==, SRWD);
> +
> + qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
> + flash_reset(test_data);
> +}
> +
> +void test_write_block_protect(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t sector_size = 65536;
> + uint32_t n_sectors = 512;
> +
> + spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + uint32_t bp_bits = 0b0;
> +
> + for (int i = 0; i < 16; i++) {
> + bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, BULK_ERASE);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, bp_bits);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + spi_ctrl_stop_user(test_data);
> +
> + 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(test_data, addr, 0xffffffff);
> + write_page_mem(test_data, addr, make_be32(0xabcdef12));
> +
> + uint32_t expected_value = protection_start <= sector
> + && sector < protection_end
> + ? 0xffffffff : 0xabcdef12;
> +
> + assert_page_mem(test_data, addr, expected_value);
> + }
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_write_block_protect_bottom_bit(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t sector_size = 65536;
> + uint32_t n_sectors = 512;
> +
> + spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + /* 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(test_data);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, BULK_ERASE);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, WRSR);
> + flash_writeb(test_data, 0, bp_bits);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + spi_ctrl_stop_user(test_data);
> +
> + 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(test_data, addr, 0xffffffff);
> + write_page_mem(test_data, addr, make_be32(0xabcdef12));
> +
> + uint32_t expected_value = protection_start <= sector
> + && sector < protection_end
> + ? 0xffffffff : 0xabcdef12;
> +
> + assert_page_mem(test_data, addr, expected_value);
> + }
> + }
> +
> + flash_reset(test_data);
> +}
> +
> +void test_write_page_qpi(const void *data)
> +{
> + const TestData *test_data = (const TestData *)data;
> + uint32_t my_page_addr = test_data->page_addr;
> + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> + uint32_t page[FLASH_PAGE_SIZE / 4];
> + uint32_t page_pattern[] = {
> + 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
> + };
> + int i;
> +
> + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> +
> + spi_ctrl_start_user(test_data);
> + flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> + flash_writeb(test_data, 0, WREN);
> + flash_writeb(test_data, 0, PP);
> + flash_writel(test_data, 0, make_be32(my_page_addr));
> +
> + /* Set QPI mode */
> + spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
> +
> + /* Fill the page pattern */
> + for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> + flash_writel(test_data, 0, make_be32(page_pattern[i]));
> + }
> +
> + /* Fill the page with its own addresses */
> + for (; i < FLASH_PAGE_SIZE / 4; i++) {
> + flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> + }
> +
> + /* Restore io mode */
> + spi_ctrl_set_io_mode(test_data, 0);
> + spi_ctrl_stop_user(test_data);
> +
> + /* Check what was written */
> + read_page(test_data, my_page_addr, page);
> + for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> + g_assert_cmphex(page[i], ==, page_pattern[i]);
> + }
> + for (; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> + }
> +
> + /* Check some other page. It should be full of 0xff */
> + read_page(test_data, some_page_addr, page);
> + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> + g_assert_cmphex(page[i], ==, 0xffffffff);
> + }
> +
> + flash_reset(test_data);
> +}
> +
> diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h
> new file mode 100644
> index 0000000000..0f298085c2
> --- /dev/null
> +++ b/tests/qtest/aspeed-smc-utils.h
> @@ -0,0 +1,95 @@
> +/*
> + * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
> + * Controller)
> + *
> + * Copyright (C) 2016 IBM Corp.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef TESTS_ASPEED_SMC_UTILS_H
> +#define TESTS_ASPEED_SMC_UTILS_H
> +
> +#include "qemu/osdep.h"
> +#include "qemu/bswap.h"
> +#include "libqtest-single.h"
> +#include "qemu/bitops.h"
> +
> +/*
> + * ASPEED SPI Controller registers
> + */
> +#define R_CONF 0x00
> +#define CONF_ENABLE_W0 16
> +#define R_CE_CTRL 0x04
> +#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
> +#define R_CTRL0 0x10
> +#define CTRL_IO_QUAD_IO BIT(31)
> +#define CTRL_CE_STOP_ACTIVE BIT(2)
> +#define CTRL_READMODE 0x0
> +#define CTRL_FREADMODE 0x1
> +#define CTRL_WRITEMODE 0x2
> +#define CTRL_USERMODE 0x3
> +#define SR_WEL BIT(1)
> +
> +/*
> + * Flash commands
> + */
> +enum {
> + JEDEC_READ = 0x9f,
> + RDSR = 0x5,
> + WRDI = 0x4,
> + BULK_ERASE = 0xc7,
> + READ = 0x03,
> + PP = 0x02,
> + WRSR = 0x1,
> + WREN = 0x6,
> + SRWD = 0x80,
> + RESET_ENABLE = 0x66,
> + RESET_MEMORY = 0x99,
> + EN_4BYTE_ADDR = 0xB7,
> + ERASE_SECTOR = 0xd8,
> +};
> +
> +#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
> +#define FLASH_PAGE_SIZE 256
> +
> +typedef struct TestData {
> + QTestState *s;
> + uint64_t spi_base;> + uint64_t flash_base;
> + uint32_t jedec_id;
> + char *tmp_path;
> + uint8_t cs;
> + const char *node;
> + uint32_t page_addr;
> +} TestData;
Please replace the type name with AspeedSMCTestData.
> +
> +void test_read_jedec(const void *data);
The above routine needs an 'aspeed_smc' prefix. I think
aspeed_smc_test_read_jedec
should be fine.
> +void test_erase_sector(const void *data);
> +void test_erase_all(const void *data);
> +void test_write_page(const void *data);
> +void test_read_page_mem(const void *data);
> +void test_write_page_mem(const void *data);
> +void test_read_status_reg(const void *data);
> +void test_status_reg_write_protection(const void *data);
> +void test_write_block_protect(const void *data);
> +void test_write_block_protect_bottom_bit(const void *data);
> +void test_write_page_qpi(const void *data);
same for these above.
Thanks,
C.
> +#endif /* TESTS_ASPEED_SMC_UTILS_H */
> diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
> index 59f3876cdc..ef3fdc516e 100644
> --- a/tests/qtest/aspeed_smc-test.c
> +++ b/tests/qtest/aspeed_smc-test.c
> @@ -27,705 +27,7 @@
> #include "qemu/bswap.h"
> #include "libqtest-single.h"
> #include "qemu/bitops.h"
> -
> -/*
> - * ASPEED SPI Controller registers
> - */
> -#define R_CONF 0x00
> -#define CONF_ENABLE_W0 16
> -#define R_CE_CTRL 0x04
> -#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
> -#define R_CTRL0 0x10
> -#define CTRL_IO_QUAD_IO BIT(31)
> -#define CTRL_CE_STOP_ACTIVE BIT(2)
> -#define CTRL_READMODE 0x0
> -#define CTRL_FREADMODE 0x1
> -#define CTRL_WRITEMODE 0x2
> -#define CTRL_USERMODE 0x3
> -#define SR_WEL BIT(1)
> -
> -/*
> - * Flash commands
> - */
> -enum {
> - JEDEC_READ = 0x9f,
> - RDSR = 0x5,
> - WRDI = 0x4,
> - BULK_ERASE = 0xc7,
> - READ = 0x03,
> - PP = 0x02,
> - WRSR = 0x1,
> - WREN = 0x6,
> - SRWD = 0x80,
> - RESET_ENABLE = 0x66,
> - RESET_MEMORY = 0x99,
> - EN_4BYTE_ADDR = 0xB7,
> - ERASE_SECTOR = 0xd8,
> -};
> -
> -#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
> -#define FLASH_PAGE_SIZE 256
> -
> -typedef struct TestData {
> - QTestState *s;
> - uint64_t spi_base;
> - uint64_t flash_base;
> - uint32_t jedec_id;
> - char *tmp_path;
> - uint8_t cs;
> - const char *node;
> - uint32_t page_addr;
> -} TestData;
> -
> -/*
> - * Use an explicit bswap for the values read/wrote to the flash region
> - * as they are BE and the Aspeed CPU is LE.
> - */
> -static inline uint32_t make_be32(uint32_t data)
> -{
> - return bswap32(data);
> -}
> -
> -static inline void spi_writel(const TestData *data, uint64_t offset,
> - uint32_t value)
> -{
> - qtest_writel(data->s, data->spi_base + offset, value);
> -}
> -
> -static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
> -{
> - return qtest_readl(data->s, data->spi_base + offset);
> -}
> -
> -static inline void flash_writeb(const TestData *data, uint64_t offset,
> - uint8_t value)
> -{
> - qtest_writeb(data->s, data->flash_base + offset, value);
> -}
> -
> -static inline void flash_writel(const TestData *data, uint64_t offset,
> - uint32_t value)
> -{
> - qtest_writel(data->s, data->flash_base + offset, value);
> -}
> -
> -static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
> -{
> - return qtest_readb(data->s, data->flash_base + offset);
> -}
> -
> -static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
> -{
> - return qtest_readl(data->s, data->flash_base + offset);
> -}
> -
> -static void spi_conf(const TestData *data, uint32_t value)
> -{
> - uint32_t conf = spi_readl(data, R_CONF);
> -
> - conf |= value;
> - spi_writel(data, R_CONF, conf);
> -}
> -
> -static void spi_conf_remove(const TestData *data, uint32_t value)
> -{
> - uint32_t conf = spi_readl(data, R_CONF);
> -
> - conf &= ~value;
> - spi_writel(data, R_CONF, conf);
> -}
> -
> -static void spi_ce_ctrl(const TestData *data, uint32_t value)
> -{
> - uint32_t conf = spi_readl(data, R_CE_CTRL);
> -
> - conf |= value;
> - spi_writel(data, R_CE_CTRL, conf);
> -}
> -
> -static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
> -{
> - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> - uint32_t ctrl = spi_readl(data, ctrl_reg);
> - ctrl &= ~(CTRL_USERMODE | 0xff << 16);
> - ctrl |= mode | (cmd << 16);
> - spi_writel(data, ctrl_reg, ctrl);
> -}
> -
> -static void spi_ctrl_start_user(const TestData *data)
> -{
> - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> - uint32_t ctrl = spi_readl(data, ctrl_reg);
> -
> - ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> - spi_writel(data, ctrl_reg, ctrl);
> -
> - ctrl &= ~CTRL_CE_STOP_ACTIVE;
> - spi_writel(data, ctrl_reg, ctrl);
> -}
> -
> -static void spi_ctrl_stop_user(const TestData *data)
> -{
> - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> - uint32_t ctrl = spi_readl(data, ctrl_reg);
> -
> - ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> - spi_writel(data, ctrl_reg, ctrl);
> -}
> -
> -static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
> -{
> - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> - uint32_t ctrl = spi_readl(data, ctrl_reg);
> - uint32_t mode;
> -
> - mode = value & CTRL_IO_MODE_MASK;
> - ctrl &= ~CTRL_IO_MODE_MASK;
> - ctrl |= mode;
> - spi_writel(data, ctrl_reg, ctrl);
> -}
> -
> -static void flash_reset(const TestData *data)
> -{
> - spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
> -
> - spi_ctrl_start_user(data);
> - flash_writeb(data, 0, RESET_ENABLE);
> - flash_writeb(data, 0, RESET_MEMORY);
> - flash_writeb(data, 0, WREN);
> - flash_writeb(data, 0, BULK_ERASE);
> - flash_writeb(data, 0, WRDI);
> - spi_ctrl_stop_user(data);
> -
> - spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
> -}
> -
> -static void test_read_jedec(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t jedec = 0x0;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, JEDEC_READ);
> - jedec |= flash_readb(test_data, 0) << 16;
> - jedec |= flash_readb(test_data, 0) << 8;
> - jedec |= flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> -
> - flash_reset(test_data);
> -
> - g_assert_cmphex(jedec, ==, test_data->jedec_id);
> -}
> -
> -static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
> -{
> - int i;
> -
> - spi_ctrl_start_user(data);
> -
> - flash_writeb(data, 0, EN_4BYTE_ADDR);
> - flash_writeb(data, 0, READ);
> - flash_writel(data, 0, make_be32(addr));
> -
> - /* Continuous read are supported */
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - page[i] = make_be32(flash_readl(data, 0));
> - }
> - spi_ctrl_stop_user(data);
> -}
> -
> -static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
> -{
> - int i;
> -
> - /* move out USER mode to use direct reads from the AHB bus */
> - spi_ctrl_setmode(data, CTRL_READMODE, READ);
> -
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - page[i] = make_be32(flash_readl(data, addr + i * 4));
> - }
> -}
> -
> -static void write_page_mem(const TestData *data, uint32_t addr,
> - uint32_t write_value)
> -{
> - spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
> -
> - for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(data, addr + i * 4, write_value);
> - }
> -}
> -
> -static void assert_page_mem(const TestData *data, uint32_t addr,
> - uint32_t expected_value)
> -{
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - read_page_mem(data, addr, page);
> - for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, expected_value);
> - }
> -}
> -
> -static void test_erase_sector(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t some_page_addr = test_data->page_addr;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - int i;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - /*
> - * Previous page should be full of 0xffs after backend is
> - * initialized
> - */
> - read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, PP);
> - flash_writel(test_data, 0, make_be32(some_page_addr));
> -
> - /* Fill the page with its own addresses */
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> - }
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check the page is correctly written */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> - }
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, ERASE_SECTOR);
> - flash_writel(test_data, 0, make_be32(some_page_addr));
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check the page is erased */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_erase_all(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t some_page_addr = test_data->page_addr;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - int i;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - /*
> - * Previous page should be full of 0xffs after backend is
> - * initialized
> - */
> - read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, PP);
> - flash_writel(test_data, 0, make_be32(some_page_addr));
> -
> - /* Fill the page with its own addresses */
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> - }
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check the page is correctly written */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> - }
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, BULK_ERASE);
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check the page is erased */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_write_page(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = test_data->page_addr;
> - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - int i;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, PP);
> - flash_writel(test_data, 0, make_be32(my_page_addr));
> -
> - /* Fill the page with its own addresses */
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> - }
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check what was written */
> - read_page(test_data, my_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> - }
> -
> - /* Check some other page. It should be full of 0xff */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_read_page_mem(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = test_data->page_addr;
> - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - int i;
> -
> - /*
> - * Enable 4BYTE mode for controller.
> - */
> - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> -
> - /* Enable 4BYTE mode for flash. */
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, PP);
> - flash_writel(test_data, 0, make_be32(my_page_addr));
> -
> - /* Fill the page with its own addresses */
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> - }
> - spi_ctrl_stop_user(test_data);
> - spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - /* Check what was written */
> - read_page_mem(test_data, my_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> - }
> -
> - /* Check some other page. It should be full of 0xff */
> - read_page_mem(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_write_page_mem(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = test_data->page_addr;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - int i;
> -
> - /*
> - * Enable 4BYTE mode for controller.
> - */
> - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> -
> - /* Enable 4BYTE mode for flash. */
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - spi_ctrl_stop_user(test_data);
> -
> - /* move out USER mode to use direct writes to the AHB bus */
> - spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
> -
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, my_page_addr + i * 4,
> - make_be32(my_page_addr + i * 4));
> - }
> -
> - /* Check what was written */
> - read_page_mem(test_data, my_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_read_status_reg(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint8_t r;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> -
> - g_assert_cmphex(r & SR_WEL, ==, 0);
> - g_assert(!qtest_qom_get_bool
> - (test_data->s, test_data->node, "write-enable"));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> -
> - g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
> - g_assert(qtest_qom_get_bool
> - (test_data->s, test_data->node, "write-enable"));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WRDI);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> -
> - g_assert_cmphex(r & SR_WEL, ==, 0);
> - g_assert(!qtest_qom_get_bool
> - (test_data->s, test_data->node, "write-enable"));
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_status_reg_write_protection(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint8_t r;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - /* default case: WP# is high and SRWD is low -> status register writable */
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - /* test ability to write SRWD */
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, SRWD);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> - g_assert_cmphex(r & SRWD, ==, SRWD);
> -
> - /* WP# high and SRWD high -> status register writable */
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - /* test ability to write SRWD */
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, 0);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> - g_assert_cmphex(r & SRWD, ==, 0);
> -
> - /* WP# low and SRWD low -> status register writable */
> - qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - /* test ability to write SRWD */
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, SRWD);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> - g_assert_cmphex(r & SRWD, ==, SRWD);
> -
> - /* WP# low and SRWD high -> status register NOT writable */
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0 , WREN);
> - /* test ability to write SRWD */
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, 0);
> - flash_writeb(test_data, 0, RDSR);
> - r = flash_readb(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> - /* write is not successful */
> - g_assert_cmphex(r & SRWD, ==, SRWD);
> -
> - qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
> - flash_reset(test_data);
> -}
> -
> -static void test_write_block_protect(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t sector_size = 65536;
> - uint32_t n_sectors = 512;
> -
> - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - uint32_t bp_bits = 0b0;
> -
> - for (int i = 0; i < 16; i++) {
> - bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, BULK_ERASE);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, bp_bits);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - spi_ctrl_stop_user(test_data);
> -
> - 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(test_data, addr, 0xffffffff);
> - write_page_mem(test_data, addr, make_be32(0xabcdef12));
> -
> - uint32_t expected_value = protection_start <= sector
> - && sector < protection_end
> - ? 0xffffffff : 0xabcdef12;
> -
> - assert_page_mem(test_data, addr, expected_value);
> - }
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_write_block_protect_bottom_bit(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t sector_size = 65536;
> - uint32_t n_sectors = 512;
> -
> - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - /* 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(test_data);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, BULK_ERASE);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, WRSR);
> - flash_writeb(test_data, 0, bp_bits);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - spi_ctrl_stop_user(test_data);
> -
> - 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(test_data, addr, 0xffffffff);
> - write_page_mem(test_data, addr, make_be32(0xabcdef12));
> -
> - uint32_t expected_value = protection_start <= sector
> - && sector < protection_end
> - ? 0xffffffff : 0xabcdef12;
> -
> - assert_page_mem(test_data, addr, expected_value);
> - }
> - }
> -
> - flash_reset(test_data);
> -}
> -
> -static void test_write_page_qpi(const void *data)
> -{
> - const TestData *test_data = (const TestData *)data;
> - uint32_t my_page_addr = test_data->page_addr;
> - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> - uint32_t page[FLASH_PAGE_SIZE / 4];
> - uint32_t page_pattern[] = {
> - 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
> - };
> - int i;
> -
> - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> -
> - spi_ctrl_start_user(test_data);
> - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> - flash_writeb(test_data, 0, WREN);
> - flash_writeb(test_data, 0, PP);
> - flash_writel(test_data, 0, make_be32(my_page_addr));
> -
> - /* Set QPI mode */
> - spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
> -
> - /* Fill the page pattern */
> - for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> - flash_writel(test_data, 0, make_be32(page_pattern[i]));
> - }
> -
> - /* Fill the page with its own addresses */
> - for (; i < FLASH_PAGE_SIZE / 4; i++) {
> - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> - }
> -
> - /* Restore io mode */
> - spi_ctrl_set_io_mode(test_data, 0);
> - spi_ctrl_stop_user(test_data);
> -
> - /* Check what was written */
> - read_page(test_data, my_page_addr, page);
> - for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> - g_assert_cmphex(page[i], ==, page_pattern[i]);
> - }
> - for (; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> - }
> -
> - /* Check some other page. It should be full of 0xff */
> - read_page(test_data, some_page_addr, page);
> - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> - g_assert_cmphex(page[i], ==, 0xffffffff);
> - }
> -
> - flash_reset(test_data);
> -}
> +#include "aspeed-smc-utils.h"
>
> static void test_palmetto_bmc(TestData *data)
> {
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 41f3678cee..fde4de902b 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -353,6 +353,7 @@ qtests = {
> 'virtio-net-failover': files('migration-helpers.c'),
> 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
> 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
> + 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
> }
>
> if vnc.found()
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases
2024-11-25 13:43 ` Cédric Le Goater
@ 2024-11-26 3:07 ` Jamin Lin
0 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin @ 2024-11-26 3:07 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to
> > +
> > +typedef struct TestData {
> > + QTestState *s;
> > + uint64_t spi_base;> + uint64_t flash_base;
> > + uint32_t jedec_id;
> > + char *tmp_path;
> > + uint8_t cs;
> > + const char *node;
> > + uint32_t page_addr;
> > +} TestData;
>
> Please replace the type name with AspeedSMCTestData.
>
> > +
> > +void test_read_jedec(const void *data);
>
> The above routine needs an 'aspeed_smc' prefix. I think
>
> aspeed_smc_test_read_jedec
>
> should be fine.
>
> > +void test_erase_sector(const void *data);
> > +void test_erase_all(const void *data);
> > +void test_write_page(const void *data);
> > +void test_read_page_mem(const void *data);
> > +void test_write_page_mem(const void *data);
> > +void test_read_status_reg(const void *data);
> > +void test_status_reg_write_protection(const void *data);
> > +void test_write_block_protect(const void *data);
> > +void test_write_block_protect_bottom_bit(const void *data);
> > +void test_write_page_qpi(const void *data);
>
> same for these above.
>
Thanks for review.
Will fix them
Jamin
> Thanks,
>
> C.
>
>
> > +#endif /* TESTS_ASPEED_SMC_UTILS_H */
> > diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
> > index 59f3876cdc..ef3fdc516e 100644
> > --- a/tests/qtest/aspeed_smc-test.c
> > +++ b/tests/qtest/aspeed_smc-test.c
> > @@ -27,705 +27,7 @@
> > #include "qemu/bswap.h"
> > #include "libqtest-single.h"
> > #include "qemu/bitops.h"
> > -
> > -/*
> > - * ASPEED SPI Controller registers
> > - */
> > -#define R_CONF 0x00
> > -#define CONF_ENABLE_W0 16
> > -#define R_CE_CTRL 0x04
> > -#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
> > -#define R_CTRL0 0x10
> > -#define CTRL_IO_QUAD_IO BIT(31)
> > -#define CTRL_CE_STOP_ACTIVE BIT(2)
> > -#define CTRL_READMODE 0x0
> > -#define CTRL_FREADMODE 0x1
> > -#define CTRL_WRITEMODE 0x2
> > -#define CTRL_USERMODE 0x3
> > -#define SR_WEL BIT(1)
> > -
> > -/*
> > - * Flash commands
> > - */
> > -enum {
> > - JEDEC_READ = 0x9f,
> > - RDSR = 0x5,
> > - WRDI = 0x4,
> > - BULK_ERASE = 0xc7,
> > - READ = 0x03,
> > - PP = 0x02,
> > - WRSR = 0x1,
> > - WREN = 0x6,
> > - SRWD = 0x80,
> > - RESET_ENABLE = 0x66,
> > - RESET_MEMORY = 0x99,
> > - EN_4BYTE_ADDR = 0xB7,
> > - ERASE_SECTOR = 0xd8,
> > -};
> > -
> > -#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
> > -#define FLASH_PAGE_SIZE 256
> > -
> > -typedef struct TestData {
> > - QTestState *s;
> > - uint64_t spi_base;
> > - uint64_t flash_base;
> > - uint32_t jedec_id;
> > - char *tmp_path;
> > - uint8_t cs;
> > - const char *node;
> > - uint32_t page_addr;
> > -} TestData;
> > -
> > -/*
> > - * Use an explicit bswap for the values read/wrote to the flash region
> > - * as they are BE and the Aspeed CPU is LE.
> > - */
> > -static inline uint32_t make_be32(uint32_t data)
> > -{
> > - return bswap32(data);
> > -}
> > -
> > -static inline void spi_writel(const TestData *data, uint64_t offset,
> > - uint32_t value)
> > -{
> > - qtest_writel(data->s, data->spi_base + offset, value);
> > -}
> > -
> > -static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
> > -{
> > - return qtest_readl(data->s, data->spi_base + offset);
> > -}
> > -
> > -static inline void flash_writeb(const TestData *data, uint64_t offset,
> > - uint8_t value)
> > -{
> > - qtest_writeb(data->s, data->flash_base + offset, value);
> > -}
> > -
> > -static inline void flash_writel(const TestData *data, uint64_t offset,
> > - uint32_t value)
> > -{
> > - qtest_writel(data->s, data->flash_base + offset, value);
> > -}
> > -
> > -static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
> > -{
> > - return qtest_readb(data->s, data->flash_base + offset);
> > -}
> > -
> > -static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
> > -{
> > - return qtest_readl(data->s, data->flash_base + offset);
> > -}
> > -
> > -static void spi_conf(const TestData *data, uint32_t value)
> > -{
> > - uint32_t conf = spi_readl(data, R_CONF);
> > -
> > - conf |= value;
> > - spi_writel(data, R_CONF, conf);
> > -}
> > -
> > -static void spi_conf_remove(const TestData *data, uint32_t value)
> > -{
> > - uint32_t conf = spi_readl(data, R_CONF);
> > -
> > - conf &= ~value;
> > - spi_writel(data, R_CONF, conf);
> > -}
> > -
> > -static void spi_ce_ctrl(const TestData *data, uint32_t value)
> > -{
> > - uint32_t conf = spi_readl(data, R_CE_CTRL);
> > -
> > - conf |= value;
> > - spi_writel(data, R_CE_CTRL, conf);
> > -}
> > -
> > -static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t
> cmd)
> > -{
> > - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> > - uint32_t ctrl = spi_readl(data, ctrl_reg);
> > - ctrl &= ~(CTRL_USERMODE | 0xff << 16);
> > - ctrl |= mode | (cmd << 16);
> > - spi_writel(data, ctrl_reg, ctrl);
> > -}
> > -
> > -static void spi_ctrl_start_user(const TestData *data)
> > -{
> > - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> > - uint32_t ctrl = spi_readl(data, ctrl_reg);
> > -
> > - ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> > - spi_writel(data, ctrl_reg, ctrl);
> > -
> > - ctrl &= ~CTRL_CE_STOP_ACTIVE;
> > - spi_writel(data, ctrl_reg, ctrl);
> > -}
> > -
> > -static void spi_ctrl_stop_user(const TestData *data)
> > -{
> > - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> > - uint32_t ctrl = spi_readl(data, ctrl_reg);
> > -
> > - ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
> > - spi_writel(data, ctrl_reg, ctrl);
> > -}
> > -
> > -static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value)
> > -{
> > - uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
> > - uint32_t ctrl = spi_readl(data, ctrl_reg);
> > - uint32_t mode;
> > -
> > - mode = value & CTRL_IO_MODE_MASK;
> > - ctrl &= ~CTRL_IO_MODE_MASK;
> > - ctrl |= mode;
> > - spi_writel(data, ctrl_reg, ctrl);
> > -}
> > -
> > -static void flash_reset(const TestData *data)
> > -{
> > - spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
> > -
> > - spi_ctrl_start_user(data);
> > - flash_writeb(data, 0, RESET_ENABLE);
> > - flash_writeb(data, 0, RESET_MEMORY);
> > - flash_writeb(data, 0, WREN);
> > - flash_writeb(data, 0, BULK_ERASE);
> > - flash_writeb(data, 0, WRDI);
> > - spi_ctrl_stop_user(data);
> > -
> > - spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
> > -}
> > -
> > -static void test_read_jedec(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t jedec = 0x0;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, JEDEC_READ);
> > - jedec |= flash_readb(test_data, 0) << 16;
> > - jedec |= flash_readb(test_data, 0) << 8;
> > - jedec |= flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - flash_reset(test_data);
> > -
> > - g_assert_cmphex(jedec, ==, test_data->jedec_id);
> > -}
> > -
> > -static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
> > -{
> > - int i;
> > -
> > - spi_ctrl_start_user(data);
> > -
> > - flash_writeb(data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(data, 0, READ);
> > - flash_writel(data, 0, make_be32(addr));
> > -
> > - /* Continuous read are supported */
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - page[i] = make_be32(flash_readl(data, 0));
> > - }
> > - spi_ctrl_stop_user(data);
> > -}
> > -
> > -static void read_page_mem(const TestData *data, uint32_t addr, uint32_t
> *page)
> > -{
> > - int i;
> > -
> > - /* move out USER mode to use direct reads from the AHB bus */
> > - spi_ctrl_setmode(data, CTRL_READMODE, READ);
> > -
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - page[i] = make_be32(flash_readl(data, addr + i * 4));
> > - }
> > -}
> > -
> > -static void write_page_mem(const TestData *data, uint32_t addr,
> > - uint32_t write_value)
> > -{
> > - spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
> > -
> > - for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(data, addr + i * 4, write_value);
> > - }
> > -}
> > -
> > -static void assert_page_mem(const TestData *data, uint32_t addr,
> > - uint32_t expected_value)
> > -{
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - read_page_mem(data, addr, page);
> > - for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, expected_value);
> > - }
> > -}
> > -
> > -static void test_erase_sector(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t some_page_addr = test_data->page_addr;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - int i;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - /*
> > - * Previous page should be full of 0xffs after backend is
> > - * initialized
> > - */
> > - read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, PP);
> > - flash_writel(test_data, 0, make_be32(some_page_addr));
> > -
> > - /* Fill the page with its own addresses */
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> > - }
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check the page is correctly written */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> > - }
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, ERASE_SECTOR);
> > - flash_writel(test_data, 0, make_be32(some_page_addr));
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check the page is erased */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_erase_all(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t some_page_addr = test_data->page_addr;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - int i;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - /*
> > - * Previous page should be full of 0xffs after backend is
> > - * initialized
> > - */
> > - read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, PP);
> > - flash_writel(test_data, 0, make_be32(some_page_addr));
> > -
> > - /* Fill the page with its own addresses */
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
> > - }
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check the page is correctly written */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
> > - }
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, BULK_ERASE);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check the page is erased */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_write_page(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = test_data->page_addr;
> > - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - int i;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, PP);
> > - flash_writel(test_data, 0, make_be32(my_page_addr));
> > -
> > - /* Fill the page with its own addresses */
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> > - }
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check what was written */
> > - read_page(test_data, my_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> > - }
> > -
> > - /* Check some other page. It should be full of 0xff */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_read_page_mem(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = test_data->page_addr;
> > - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - int i;
> > -
> > - /*
> > - * Enable 4BYTE mode for controller.
> > - */
> > - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> > -
> > - /* Enable 4BYTE mode for flash. */
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, PP);
> > - flash_writel(test_data, 0, make_be32(my_page_addr));
> > -
> > - /* Fill the page with its own addresses */
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> > - }
> > - spi_ctrl_stop_user(test_data);
> > - spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - /* Check what was written */
> > - read_page_mem(test_data, my_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> > - }
> > -
> > - /* Check some other page. It should be full of 0xff */
> > - read_page_mem(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_write_page_mem(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = test_data->page_addr;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - int i;
> > -
> > - /*
> > - * Enable 4BYTE mode for controller.
> > - */
> > - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> > -
> > - /* Enable 4BYTE mode for flash. */
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* move out USER mode to use direct writes to the AHB bus */
> > - spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
> > -
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, my_page_addr + i * 4,
> > - make_be32(my_page_addr + i * 4));
> > - }
> > -
> > - /* Check what was written */
> > - read_page_mem(test_data, my_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_read_status_reg(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint8_t r;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - g_assert_cmphex(r & SR_WEL, ==, 0);
> > - g_assert(!qtest_qom_get_bool
> > - (test_data->s, test_data->node, "write-enable"));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
> > - g_assert(qtest_qom_get_bool
> > - (test_data->s, test_data->node, "write-enable"));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WRDI);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - g_assert_cmphex(r & SR_WEL, ==, 0);
> > - g_assert(!qtest_qom_get_bool
> > - (test_data->s, test_data->node, "write-enable"));
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_status_reg_write_protection(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint8_t r;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - /* default case: WP# is high and SRWD is low -> status register
> writable */
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - /* test ability to write SRWD */
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, SRWD);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > - g_assert_cmphex(r & SRWD, ==, SRWD);
> > -
> > - /* WP# high and SRWD high -> status register writable */
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - /* test ability to write SRWD */
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, 0);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > - g_assert_cmphex(r & SRWD, ==, 0);
> > -
> > - /* WP# low and SRWD low -> status register writable */
> > - qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - /* test ability to write SRWD */
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, SRWD);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > - g_assert_cmphex(r & SRWD, ==, SRWD);
> > -
> > - /* WP# low and SRWD high -> status register NOT writable */
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0 , WREN);
> > - /* test ability to write SRWD */
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, 0);
> > - flash_writeb(test_data, 0, RDSR);
> > - r = flash_readb(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > - /* write is not successful */
> > - g_assert_cmphex(r & SRWD, ==, SRWD);
> > -
> > - qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_write_block_protect(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t sector_size = 65536;
> > - uint32_t n_sectors = 512;
> > -
> > - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - uint32_t bp_bits = 0b0;
> > -
> > - for (int i = 0; i < 16; i++) {
> > - bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, BULK_ERASE);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, bp_bits);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - 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(test_data, addr, 0xffffffff);
> > - write_page_mem(test_data, addr, make_be32(0xabcdef12));
> > -
> > - uint32_t expected_value = protection_start <= sector
> > - && sector < protection_end
> > - ? 0xffffffff : 0xabcdef12;
> > -
> > - assert_page_mem(test_data, addr, expected_value);
> > - }
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_write_block_protect_bottom_bit(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t sector_size = 65536;
> > - uint32_t n_sectors = 512;
> > -
> > - spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - /* 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(test_data);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, BULK_ERASE);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, WRSR);
> > - flash_writeb(test_data, 0, bp_bits);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - 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(test_data, addr, 0xffffffff);
> > - write_page_mem(test_data, addr, make_be32(0xabcdef12));
> > -
> > - uint32_t expected_value = protection_start <= sector
> > - && sector < protection_end
> > - ? 0xffffffff : 0xabcdef12;
> > -
> > - assert_page_mem(test_data, addr, expected_value);
> > - }
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > -
> > -static void test_write_page_qpi(const void *data)
> > -{
> > - const TestData *test_data = (const TestData *)data;
> > - uint32_t my_page_addr = test_data->page_addr;
> > - uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
> > - uint32_t page[FLASH_PAGE_SIZE / 4];
> > - uint32_t page_pattern[] = {
> > - 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
> > - };
> > - int i;
> > -
> > - spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
> > -
> > - spi_ctrl_start_user(test_data);
> > - flash_writeb(test_data, 0, EN_4BYTE_ADDR);
> > - flash_writeb(test_data, 0, WREN);
> > - flash_writeb(test_data, 0, PP);
> > - flash_writel(test_data, 0, make_be32(my_page_addr));
> > -
> > - /* Set QPI mode */
> > - spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
> > -
> > - /* Fill the page pattern */
> > - for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> > - flash_writel(test_data, 0, make_be32(page_pattern[i]));
> > - }
> > -
> > - /* Fill the page with its own addresses */
> > - for (; i < FLASH_PAGE_SIZE / 4; i++) {
> > - flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
> > - }
> > -
> > - /* Restore io mode */
> > - spi_ctrl_set_io_mode(test_data, 0);
> > - spi_ctrl_stop_user(test_data);
> > -
> > - /* Check what was written */
> > - read_page(test_data, my_page_addr, page);
> > - for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
> > - g_assert_cmphex(page[i], ==, page_pattern[i]);
> > - }
> > - for (; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
> > - }
> > -
> > - /* Check some other page. It should be full of 0xff */
> > - read_page(test_data, some_page_addr, page);
> > - for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
> > - g_assert_cmphex(page[i], ==, 0xffffffff);
> > - }
> > -
> > - flash_reset(test_data);
> > -}
> > +#include "aspeed-smc-utils.h"
> >
> > static void test_palmetto_bmc(TestData *data)
> > {
> > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> > index 41f3678cee..fde4de902b 100644
> > --- a/tests/qtest/meson.build
> > +++ b/tests/qtest/meson.build
> > @@ -353,6 +353,7 @@ qtests = {
> > 'virtio-net-failover': files('migration-helpers.c'),
> > 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
> > 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
> > + 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
> > }
> >
> > if vnc.found()
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-10-23 2:46 ` Jamin Lin
@ 2024-11-26 16:39 ` Cédric Le Goater
2024-11-27 1:13 ` Jamin Lin
0 siblings, 1 reply; 41+ messages in thread
From: Cédric Le Goater @ 2024-11-26 16:39 UTC (permalink / raw)
To: Jamin Lin, Peter Maydell, Steven Lee, Troy Lee, Andrew Jeffery,
Joel Stanley, Alistair Francis, Kevin Wolf, Hanna Reitz,
Thomas Huth, Laurent Vivier, Paolo Bonzini, open list:ASPEED BMCs,
open list:All patches CC here, open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hello Jamin,
Sorry for the later answer. I think I missed the question below.
On 10/23/24 04:46, Jamin Lin wrote:
> Hi Cedric,
>
>> Subject: Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi
>> controllers
>>
>> oops. R-b sent on the wrong patch.
>>
>> On 10/22/24 12:48, Cédric Le Goater wrote:
>>> On 10/22/24 11:40, Jamin Lin wrote:
>>>> It only attached flash model of fmc and spi[0] in aspeed_machine_init
>> function.
>>>> However, AST2500 and AST2600 have one fmc and two spi(spi1 and spi2)
>>>> controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2) controllers.
>>>>
>>>> Besides, it used hardcode to attach flash model of fmc, spi[0] and
>>>> spi[1] in aspeed_minibmc_machine_init for AST1030.
>>>>
>>>> To make both functions more flexible and support all ASPEED SOCs spi
>>>> controllers, adds a for loop with sc->spis_num to attach flash model
>>>> of all supported spi controllers. The sc->spis_num is from AspeedSoCClass.
>>
>> To be honest, I am not a big fan of the aspeed_board_init_flashes() routine.
>> See commit 27a2c66c92ec for the reason.
>>
>> I prefer the more flexible approach :
>>
>> $ qemu-system-arm -M ast2600-evb \
>> -blockdev node-name=fmc0,driver=file,filename=/path/to/fmc0.img \
>> -device mx66u51235f,bus=ssi.0,cs=0x0,drive=fmc0 \
>> -blockdev node-name=fmc1,driver=file,filename=/path/to/fmc1.img \
>> -device mx66u51235f,bus=ssi.0,cs=0x1,drive=fmc1 \
>> -blockdev node-name=spi1,driver=file,filename=/path/to/spi1.img \
>> -device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
>> -nographic -nodefaults
>>
> Thanks for notify me this solution.
> I can successfully attach the default image to supported SPI controllers with different flash model.
> It seems we need to add "defaults_enabled()" if-statement in aspeed_minibmc_machine_init
> to support this solution for AST1030. Otherwise, I will get this error.
>
> qemu-system-arm: -device w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0: CS index '0x0' in use by a w25q80bl device
>
> https://github.com/qemu/qemu/blob/master/hw/arm/aspeed.c
> if (defaults_enabled()) {
> aspeed_board_init_flashes(&bmc->soc->fmc,
> bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
> amc->num_cs,
> 0);
>
> aspeed_board_init_flashes(&bmc->soc->spi[0],
> bmc->spi_model ? bmc->spi_model : amc->spi_model,
> amc->num_cs, amc->num_cs);
>
> aspeed_board_init_flashes(&bmc->soc->spi[1],
> bmc->spi_model ? bmc->spi_model : amc->spi_model,
> amc->num_cs, (amc->num_cs * 2));
> }
>
> Do I need to send this patch in v3 patch series?
> Or individually send this patch in the new patch series?
defaults_enabled() should be used to avoid creating the devices indeed.
Please send a patch for it. Or did you already ?
Thanks,
C.
>
> AST1030:
> -blockdev node-name=fmc0,driver=file,filename=./fmc_cs0_img \
> -device w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0 \
> -blockdev node-name=fmc1,driver=file,filename=./fmc_cs1_img \
> -device w25q80bl,bus=ssi.0,cs=0x1,drive=fmc1 \
> -blockdev node-name=spi1c0,driver=file,filename=./spi1_cs0_img \
> -device w25q256,bus=ssi.1,cs=0x0,drive=spi1c0 \
> -blockdev node-name=spi1c1,driver=file,filename=./spi1_cs1_img \
> -device w25q256,bus=ssi.1,cs=0x1,drive=spi1c1 \
> -blockdev node-name=spi2c0,driver=file,filename=./spi2_cs0_img \
> -device w25q256,bus=ssi.2,cs=0x0,drive=spi2c0 \
> -blockdev node-name=spi2c1,driver=file,filename=./spi2_cs1_img \
> -device w25q256,bus=ssi.2,cs=0x1,drive=spi2c1 \
> -nodefaults
>
> AST2600:
> -blockdev node-name=fmc0,driver=file,filename=$1 \
> -device mx66u51235f,cs=0x0,bus=ssi.0,drive=fmc0 \
> -blockdev node-name=fmc1,driver=file,filename=./fmc_cs1_img \
> -device mx66u51235f,cs=0x1,bus=ssi.0,drive=fmc1 \
> -blockdev node-name=spi1,driver=file,filename=./spi1_cs0_img \
> -device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
> -blockdev node-name=spi2,driver=file,filename=./spi2_cs0_img \
> -device mx66u51235f,cs=0x0,bus=ssi.2,drive=spi2 \
> -nodefaults
>
>> which doesn't use the drive_get() interface and so, doesn't make assumption
>> on the order of the drives defined on the QEMU command line.
>>
>> Also, the number of availabe flash devices is a machine definition, not a SoC
>> definition. Not all CS are wired.
>>
>> I will drop that patch for now.
>>
> Understand and thanks for suggestion.
> Jamin
>>
>> Thanks,
>>
>> C.
>>
>>
>>
>>>> ---
>>>> hw/arm/aspeed.c | 21 ++++++++++++---------
>>>> 1 file changed, 12 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index
>>>> b4b1ce9efb..7ac01a3562 100644
>>>> --- a/hw/arm/aspeed.c
>>>> +++ b/hw/arm/aspeed.c
>>>> @@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState
>>>> *machine)
>>>> aspeed_board_init_flashes(&bmc->soc->fmc,
>>>> bmc->fmc_model ?
>> bmc->fmc_model :
>>>> amc->fmc_model,
>>>> amc->num_cs, 0);
>>>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
>>>> - bmc->spi_model ?
>> bmc->spi_model :
>>>> amc->spi_model,
>>>> - 1, amc->num_cs);
>>>> + for (i = 0; i < sc->spis_num; i++) {
>>>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
>>>> + bmc->spi_model ?
>> bmc->spi_model :
>>>> +amc->spi_model,
>>>> + amc->num_cs, amc->num_cs +
>> (amc->num_cs
>>>> +* i));
>>>> + }
>>>> }
>>>> if (machine->kernel_filename && sc->num_cpus > 1) { @@
>> -1579,7
>>>> +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState
>>>> *machine)
>>>> {
>>>> AspeedMachineState *bmc = ASPEED_MACHINE(machine);
>>>> AspeedMachineClass *amc =
>> ASPEED_MACHINE_GET_CLASS(machine);
>>>> + AspeedSoCClass *sc;
>>>> Clock *sysclk;
>>>> + int i;
>>>> sysclk = clock_new(OBJECT(machine), "SYSCLK");
>>>> clock_set_hz(sysclk, SYSCLK_FRQ); @@ -1587,6 +1591,7 @@
>> static
>>>> void aspeed_minibmc_machine_init(MachineState *machine)
>>>> bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
>>>> object_property_add_child(OBJECT(machine), "soc",
>>>> OBJECT(bmc->soc));
>>>> object_unref(OBJECT(bmc->soc));
>>>> + sc = ASPEED_SOC_GET_CLASS(bmc->soc);
>>>> qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
>>>> object_property_set_link(OBJECT(bmc->soc), "memory", @@
>>>> -1599,13 +1604,11 @@ static void
>>>> aspeed_minibmc_machine_init(MachineState *machine)
>>>> amc->num_cs,
>>>> 0);
>>>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
>>>> - bmc->spi_model ?
>> bmc->spi_model :
>>>> amc->spi_model,
>>>> - amc->num_cs,
>> amc->num_cs);
>>>> -
>>>> - aspeed_board_init_flashes(&bmc->soc->spi[1],
>>>> + for (i = 0; i < sc->spis_num; i++) {
>>>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
>>>> bmc->spi_model ?
>> bmc->spi_model :
>>>> amc->spi_model,
>>>> - amc->num_cs,
>> (amc->num_cs * 2));
>>>> + amc->num_cs,
>> amc->num_cs +
>>>> +(amc->num_cs * i));
>>>> + }
>>>> if (amc->i2c_init) {
>>>> amc->i2c_init(bmc);
>>>
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers
2024-11-26 16:39 ` Cédric Le Goater
@ 2024-11-27 1:13 ` Jamin Lin
0 siblings, 0 replies; 41+ messages in thread
From: Jamin Lin @ 2024-11-27 1:13 UTC (permalink / raw)
To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
Andrew Jeffery, Joel Stanley, Alistair Francis, Kevin Wolf,
Hanna Reitz, Thomas Huth, Laurent Vivier, Paolo Bonzini,
open list:ASPEED BMCs, open list:All patches CC here,
open list:Block layer core
Cc: Troy Lee, Yunlin Tang
Hi Cedric,
> Subject: Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi
> controllers
>
> Hello Jamin,
>
> Sorry for the later answer. I think I missed the question below.
>
> On 10/23/24 04:46, Jamin Lin wrote:
> > Hi Cedric,
> >
> >> Subject: Re: [PATCH v2 07/18] aspeed: Fix hardcode attach flash model
> >> of spi controllers
> >>
> >> oops. R-b sent on the wrong patch.
> >>
> >> On 10/22/24 12:48, Cédric Le Goater wrote:
> >>> On 10/22/24 11:40, Jamin Lin wrote:
> >>>> It only attached flash model of fmc and spi[0] in
> >>>> aspeed_machine_init
> >> function.
> >>>> However, AST2500 and AST2600 have one fmc and two spi(spi1 and
> >>>> spi2) controllers; AST2700 have one fmc and 3 spi(spi0, spi1 and spi2)
> controllers.
> >>>>
> >>>> Besides, it used hardcode to attach flash model of fmc, spi[0] and
> >>>> spi[1] in aspeed_minibmc_machine_init for AST1030.
> >>>>
> >>>> To make both functions more flexible and support all ASPEED SOCs
> >>>> spi controllers, adds a for loop with sc->spis_num to attach flash
> >>>> model of all supported spi controllers. The sc->spis_num is from
> AspeedSoCClass.
> >>
> >> To be honest, I am not a big fan of the aspeed_board_init_flashes() routine.
> >> See commit 27a2c66c92ec for the reason.
> >>
> >> I prefer the more flexible approach :
> >>
> >> $ qemu-system-arm -M ast2600-evb \
> >> -blockdev
> node-name=fmc0,driver=file,filename=/path/to/fmc0.img \
> >> -device mx66u51235f,bus=ssi.0,cs=0x0,drive=fmc0 \
> >> -blockdev
> node-name=fmc1,driver=file,filename=/path/to/fmc1.img \
> >> -device mx66u51235f,bus=ssi.0,cs=0x1,drive=fmc1 \
> >> -blockdev
> node-name=spi1,driver=file,filename=/path/to/spi1.img \
> >> -device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
> >> -nographic -nodefaults
> >>
> > Thanks for notify me this solution.
> > I can successfully attach the default image to supported SPI controllers with
> different flash model.
> > It seems we need to add "defaults_enabled()" if-statement in
> > aspeed_minibmc_machine_init to support this solution for AST1030.
> Otherwise, I will get this error.
> >
> > qemu-system-arm: -device w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0: CS
> > index '0x0' in use by a w25q80bl device
> >
> > https://github.com/qemu/qemu/blob/master/hw/arm/aspeed.c
> > if (defaults_enabled()) {
> > aspeed_board_init_flashes(&bmc->soc->fmc,
> > bmc->fmc_model ? bmc->fmc_model :
> amc->fmc_model,
> > amc->num_cs,
> > 0);
> >
> > aspeed_board_init_flashes(&bmc->soc->spi[0],
> > bmc->spi_model ? bmc->spi_model :
> amc->spi_model,
> > amc->num_cs, amc->num_cs);
> >
> > aspeed_board_init_flashes(&bmc->soc->spi[1],
> > bmc->spi_model ? bmc->spi_model :
> amc->spi_model,
> > amc->num_cs, (amc->num_cs * 2));
> > }
> >
> > Do I need to send this patch in v3 patch series?
> > Or individually send this patch in the new patch series?
>
>
> defaults_enabled() should be used to avoid creating the devices indeed.
> Please send a patch for it. Or did you already ?
>
This patch had been applied,
https://github.com/qemu/qemu/commit/22b3c557ffd4fb9c6c034a839b3e5b82d131123a
Thanks-Jamin
> Thanks,
>
> C.
>
>
>
> >
> > AST1030:
> > -blockdev node-name=fmc0,driver=file,filename=./fmc_cs0_img \ -device
> > w25q80bl,bus=ssi.0,cs=0x0,drive=fmc0 \ -blockdev
> > node-name=fmc1,driver=file,filename=./fmc_cs1_img \ -device
> > w25q80bl,bus=ssi.0,cs=0x1,drive=fmc1 \ -blockdev
> > node-name=spi1c0,driver=file,filename=./spi1_cs0_img \ -device
> > w25q256,bus=ssi.1,cs=0x0,drive=spi1c0 \ -blockdev
> > node-name=spi1c1,driver=file,filename=./spi1_cs1_img \ -device
> > w25q256,bus=ssi.1,cs=0x1,drive=spi1c1 \ -blockdev
> > node-name=spi2c0,driver=file,filename=./spi2_cs0_img \ -device
> > w25q256,bus=ssi.2,cs=0x0,drive=spi2c0 \ -blockdev
> > node-name=spi2c1,driver=file,filename=./spi2_cs1_img \ -device
> > w25q256,bus=ssi.2,cs=0x1,drive=spi2c1 \ -nodefaults
> >
> > AST2600:
> > -blockdev node-name=fmc0,driver=file,filename=$1 \ -device
> > mx66u51235f,cs=0x0,bus=ssi.0,drive=fmc0 \ -blockdev
> > node-name=fmc1,driver=file,filename=./fmc_cs1_img \ -device
> > mx66u51235f,cs=0x1,bus=ssi.0,drive=fmc1 \ -blockdev
> > node-name=spi1,driver=file,filename=./spi1_cs0_img \ -device
> > mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \ -blockdev
> > node-name=spi2,driver=file,filename=./spi2_cs0_img \ -device
> > mx66u51235f,cs=0x0,bus=ssi.2,drive=spi2 \ -nodefaults
> >
> >> which doesn't use the drive_get() interface and so, doesn't make
> >> assumption on the order of the drives defined on the QEMU command line.
> >>
> >> Also, the number of availabe flash devices is a machine definition,
> >> not a SoC definition. Not all CS are wired.
> >>
> >> I will drop that patch for now.
> >>
> > Understand and thanks for suggestion.
> > Jamin
> >>
> >> Thanks,
> >>
> >> C.
> >>
> >>
> >>
> >>>> ---
> >>>> hw/arm/aspeed.c | 21 ++++++++++++---------
> >>>> 1 file changed, 12 insertions(+), 9 deletions(-)
> >>>>
> >>>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index
> >>>> b4b1ce9efb..7ac01a3562 100644
> >>>> --- a/hw/arm/aspeed.c
> >>>> +++ b/hw/arm/aspeed.c
> >>>> @@ -419,9 +419,11 @@ static void aspeed_machine_init(MachineState
> >>>> *machine)
> >>>> aspeed_board_init_flashes(&bmc->soc->fmc,
> >>>> bmc->fmc_model ?
> >> bmc->fmc_model :
> >>>> amc->fmc_model,
> >>>> amc->num_cs, 0);
> >>>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> >>>> - bmc->spi_model ?
> >> bmc->spi_model :
> >>>> amc->spi_model,
> >>>> - 1, amc->num_cs);
> >>>> + for (i = 0; i < sc->spis_num; i++) {
> >>>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> >>>> + bmc->spi_model ?
> >> bmc->spi_model :
> >>>> +amc->spi_model,
> >>>> + amc->num_cs, amc->num_cs
> +
> >> (amc->num_cs
> >>>> +* i));
> >>>> + }
> >>>> }
> >>>> if (machine->kernel_filename && sc->num_cpus > 1) { @@
> >> -1579,7
> >>>> +1581,9 @@ static void aspeed_minibmc_machine_init(MachineState
> >>>> *machine)
> >>>> {
> >>>> AspeedMachineState *bmc = ASPEED_MACHINE(machine);
> >>>> AspeedMachineClass *amc =
> >> ASPEED_MACHINE_GET_CLASS(machine);
> >>>> + AspeedSoCClass *sc;
> >>>> Clock *sysclk;
> >>>> + int i;
> >>>> sysclk = clock_new(OBJECT(machine), "SYSCLK");
> >>>> clock_set_hz(sysclk, SYSCLK_FRQ); @@ -1587,6 +1591,7 @@
> >> static
> >>>> void aspeed_minibmc_machine_init(MachineState *machine)
> >>>> bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
> >>>> object_property_add_child(OBJECT(machine), "soc",
> >>>> OBJECT(bmc->soc));
> >>>> object_unref(OBJECT(bmc->soc));
> >>>> + sc = ASPEED_SOC_GET_CLASS(bmc->soc);
> >>>> qdev_connect_clock_in(DEVICE(bmc->soc), "sysclk", sysclk);
> >>>> object_property_set_link(OBJECT(bmc->soc), "memory", @@
> >>>> -1599,13 +1604,11 @@ static void
> >>>> aspeed_minibmc_machine_init(MachineState *machine)
> >>>> amc->num_cs,
> >>>> 0);
> >>>> - aspeed_board_init_flashes(&bmc->soc->spi[0],
> >>>> - bmc->spi_model ?
> >> bmc->spi_model :
> >>>> amc->spi_model,
> >>>> - amc->num_cs,
> >> amc->num_cs);
> >>>> -
> >>>> - aspeed_board_init_flashes(&bmc->soc->spi[1],
> >>>> + for (i = 0; i < sc->spis_num; i++) {
> >>>> + aspeed_board_init_flashes(&bmc->soc->spi[i],
> >>>> bmc->spi_model ?
> >> bmc->spi_model :
> >>>> amc->spi_model,
> >>>> - amc->num_cs,
> >> (amc->num_cs * 2));
> >>>> + amc->num_cs,
> >> amc->num_cs +
> >>>> +(amc->num_cs * i));
> >>>> + }
> >>>> if (amc->i2c_init) {
> >>>> amc->i2c_init(bmc);
> >>>
> >
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2024-11-27 1:15 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-22 9:40 [PATCH v2 00/18] Fix write incorrect data into flash in user mode Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 01/18] aspeed/smc: " Jamin Lin via
2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 10:49 ` Kevin Wolf
2024-10-22 13:40 ` Cédric Le Goater
2024-10-22 15:23 ` Kevin Wolf
2024-10-24 6:06 ` Cédric Le Goater
2024-10-23 1:41 ` Jamin Lin
2024-10-24 6:13 ` Cédric Le Goater
2024-10-22 9:40 ` [PATCH v2 02/18] hw/block:m25p80: Fix coding style Jamin Lin via
2024-11-15 16:44 ` Philippe Mathieu-Daudé
2024-10-22 9:40 ` [PATCH v2 03/18] hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 04/18] hw/block/m25p80: Add SFDP table for w25q80bl flash Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 05/18] hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 06/18] hw/arm/aspeed: Correct fmc_model w25q80bl " Jamin Lin via
2024-10-22 9:40 ` [PATCH v2 07/18] aspeed: Fix hardcode attach flash model of spi controllers Jamin Lin via
2024-10-22 10:48 ` Cédric Le Goater
2024-10-22 14:10 ` Cédric Le Goater
2024-10-23 2:46 ` Jamin Lin
2024-11-26 16:39 ` Cédric Le Goater
2024-11-27 1:13 ` Jamin Lin
2024-10-22 9:41 ` [PATCH v2 08/18] test/qtest/aspeed_smc-test: Fix coding style Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 09/18] test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc function Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 10/18] test/qtest/aspeed_smc-test: Introduce a new TestData to test different BMC SOCs Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 11/18] test/qtest/aspeed_smc-test: Support to test all CE pins Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 12/18] test/qtest/aspeed_smc-test: Introducing a "page_addr" data field Jamin Lin via
2024-10-22 13:48 ` Cédric Le Goater
2024-10-23 1:40 ` Jamin Lin
2024-10-22 9:41 ` [PATCH v2 13/18] test/qtest/aspeed_smc-test: Support to test AST2500 Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 14/18] test/qtest/aspeed_smc-test: Support to test AST2600 Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 15/18] test/qtest/aspeed_smc-test: Support to test AST1030 Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 16/18] test/qtest/aspeed_smc-test: Support write page command with QPI mode Jamin Lin via
2024-10-22 9:41 ` [PATCH v2 17/18] test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases Jamin Lin via
2024-11-25 13:43 ` Cédric Le Goater
2024-11-26 3:07 ` Jamin Lin
2024-10-22 9:41 ` [PATCH v2 18/18] test/qtest/ast2700-smc-test: Support to test AST2700 Jamin Lin via
2024-10-24 6:11 ` [PATCH v2 00/18] Fix write incorrect data into flash in user mode Cédric Le Goater
2024-10-24 6:14 ` Jamin Lin
2024-11-14 5:30 ` Jamin Lin
2024-11-14 7:38 ` Cédric Le Goater
2024-11-14 8:50 ` Jamin Lin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).