diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-01-29 12:00:19 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-01-29 12:00:19 +0000 |
commit | b4fbe1f65a4769c09e6bf2d79fc84360f840f40e (patch) | |
tree | 2565dfb0a8d719063e9682b7887747748eba230a /hw/ssi/aspeed_smc.c | |
parent | 3a183e330dbd7dbcac3841737ac874979552cca2 (diff) | |
parent | 46f5abc0a2566ac3dc954eeb62fd625f0eaca120 (diff) | |
download | qemu-b4fbe1f65a4769c09e6bf2d79fc84360f840f40e.zip qemu-b4fbe1f65a4769c09e6bf2d79fc84360f840f40e.tar.gz qemu-b4fbe1f65a4769c09e6bf2d79fc84360f840f40e.tar.bz2 |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190129' into staging
target-arm queue:
* Fix validation of 32-bit address spaces for aa32 (fixes an assert introduced in ba97be9f4a4)
* v8m: Ensure IDAU is respected if SAU is disabled
* gdbstub: fix gdb_get_cpu(s, pid, tid) when pid and/or tid are 0
* exec.c: Use correct attrs in cpu_memory_rw_debug()
* accel/tcg/user-exec: Don't parse aarch64 insns to test for read vs write
* target/arm: Don't clear supported PMU events when initializing PMCEID1
* memory: add memory_region_flush_rom_device()
* microbit: Add stub NRF51 TWI magnetometer/accelerometer detection
* tests/microbit-test: extend testing of microbit devices
* checkpatch: Don't emit spurious warnings about block comments
* aspeed/smc: misc bug fixes
* xlnx-zynqmp: Don't create rpu-cluster if there are no RPUs
* xlnx-zynqmp: Realize cluster after putting RPUs in it
* accel/tcg: Add cluster number to TCG TB hash so differently configured
CPUs don't pick up cached TBs for the wrong kind of CPU
# gpg: Signature made Tue 29 Jan 2019 11:59:10 GMT
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190129: (23 commits)
gdbstub: Simplify gdb_get_cpu_pid() to use cpu->cluster_index
accel/tcg: Add cluster number to TCG TB hash
qom/cpu: Add cluster_index to CPUState
hw/arm/xlnx-zynqmp: Realize cluster after putting RPUs in it
aspeed/smc: snoop SPI transfers to fake dummy cycles
aspeed/smc: Add dummy data register
aspeed/smc: define registers for all possible CS
aspeed/smc: fix default read value
xlnx-zynqmp: Don't create rpu-cluster if there are no RPUs
checkpatch: Don't emit spurious warnings about block comments
tests/microbit-test: Check nRF51 UART functionality
tests/microbit-test: Make test independent of global_qtest
tests/libqtest: Introduce qtest_init_with_serial()
memory: add memory_region_flush_rom_device()
target/arm: Don't clear supported PMU events when initializing PMCEID1
MAINTAINERS: update microbit ARM board files
accel/tcg/user-exec: Don't parse aarch64 insns to test for read vs write
exec.c: Use correct attrs in cpu_memory_rw_debug()
tests/microbit-test: add TWI stub device test
arm: Stub out NRF51 TWI magnetometer/accelerometer detection
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/ssi/aspeed_smc.c')
-rw-r--r-- | hw/ssi/aspeed_smc.c | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 1270842..f1e6687 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -98,8 +98,8 @@ /* Misc Control Register #1 */ #define R_MISC_CTRL1 (0x50 / 4) -/* Misc Control Register #2 */ -#define R_MISC_CTRL2 (0x54 / 4) +/* SPI dummy cycle data */ +#define R_DUMMY_DATA (0x54 / 4) /* DMA Control/Status Register */ #define R_DMA_CTRL (0x80 / 4) @@ -145,6 +145,9 @@ /* Flash opcodes. */ #define SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ +#define SNOOP_OFF 0xFF +#define SNOOP_START 0x0 + /* * Default segments mapping addresses and size for each slave per * controller. These can be changed when board is initialized with the @@ -529,7 +532,7 @@ static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr) */ if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) { for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { - ssi_transfer(fl->controller->spi, 0xFF); + ssi_transfer(fl->controller->spi, s->regs[R_DUMMY_DATA] & 0xff); } } } @@ -566,6 +569,101 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) return ret; } +/* + * TODO (clg@kaod.org): stolen from xilinx_spips.c. Should move to a + * common include header. + */ +typedef enum { + READ = 0x3, READ_4 = 0x13, + FAST_READ = 0xb, FAST_READ_4 = 0x0c, + DOR = 0x3b, DOR_4 = 0x3c, + QOR = 0x6b, QOR_4 = 0x6c, + DIOR = 0xbb, DIOR_4 = 0xbc, + QIOR = 0xeb, QIOR_4 = 0xec, + + PP = 0x2, PP_4 = 0x12, + DPP = 0xa2, + QPP = 0x32, QPP_4 = 0x34, +} FlashCMD; + +static int aspeed_smc_num_dummies(uint8_t command) +{ + switch (command) { /* check for dummies */ + case READ: /* no dummy bytes/cycles */ + case PP: + case DPP: + case QPP: + case READ_4: + case PP_4: + case QPP_4: + return 0; + case FAST_READ: + case DOR: + case QOR: + case DOR_4: + case QOR_4: + return 1; + case DIOR: + case FAST_READ_4: + case DIOR_4: + return 2; + case QIOR: + case QIOR_4: + return 4; + default: + return -1; + } +} + +static bool aspeed_smc_do_snoop(AspeedSMCFlash *fl, uint64_t data, + unsigned size) +{ + AspeedSMCState *s = fl->controller; + uint8_t addr_width = aspeed_smc_flash_is_4byte(fl) ? 4 : 3; + + if (s->snoop_index == SNOOP_OFF) { + return false; /* Do nothing */ + + } else if (s->snoop_index == SNOOP_START) { + uint8_t cmd = data & 0xff; + int ndummies = aspeed_smc_num_dummies(cmd); + + /* + * No dummy cycles are expected with the current command. Turn + * off snooping and let the transfer proceed normally. + */ + if (ndummies <= 0) { + s->snoop_index = SNOOP_OFF; + return false; + } + + s->snoop_dummies = ndummies * 8; + + } else if (s->snoop_index >= addr_width + 1) { + + /* The SPI transfer has reached the dummy cycles sequence */ + for (; s->snoop_dummies; s->snoop_dummies--) { + ssi_transfer(s->spi, s->regs[R_DUMMY_DATA] & 0xff); + } + + /* If no more dummy cycles are expected, turn off snooping */ + if (!s->snoop_dummies) { + s->snoop_index = SNOOP_OFF; + } else { + s->snoop_index += size; + } + + /* + * Dummy cycles have been faked already. Ignore the current + * SPI transfer + */ + return true; + } + + s->snoop_index += size; + return false; +} + static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { @@ -581,6 +679,10 @@ static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, switch (aspeed_smc_flash_mode(fl)) { case CTRL_USERMODE: + if (aspeed_smc_do_snoop(fl, data, size)) { + break; + } + for (i = 0; i < size; i++) { ssi_transfer(s->spi, (data >> (8 * i)) & 0xff); } @@ -613,7 +715,9 @@ static const MemoryRegionOps aspeed_smc_flash_ops = { static void aspeed_smc_flash_update_cs(AspeedSMCFlash *fl) { - const AspeedSMCState *s = fl->controller; + AspeedSMCState *s = fl->controller; + + s->snoop_index = aspeed_smc_is_ce_stop_active(fl) ? SNOOP_OFF : SNOOP_START; qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl)); } @@ -652,6 +756,9 @@ static void aspeed_smc_reset(DeviceState *d) if (s->ctrl->segments == aspeed_segments_fmc) { s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); } + + s->snoop_index = SNOOP_OFF; + s->snoop_dummies = 0; } static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) @@ -664,13 +771,14 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) addr == s->r_timings || addr == s->r_ce_ctrl || addr == R_INTR_CTRL || + addr == R_DUMMY_DATA || (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_slaves) || - (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs)) { + (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_slaves)) { return s->regs[addr]; } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); - return 0; + return -1; } } @@ -697,6 +805,8 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, if (value != s->regs[R_SEG_ADDR0 + cs]) { aspeed_smc_flash_set_segment(s, cs, value); } + } else if (addr == R_DUMMY_DATA) { + s->regs[addr] = value & 0xff; } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -790,10 +900,12 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) static const VMStateDescription vmstate_aspeed_smc = { .name = "aspeed.smc", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX), + VMSTATE_UINT8(snoop_index, AspeedSMCState), + VMSTATE_UINT8(snoop_dummies, AspeedSMCState), VMSTATE_END_OF_LIST() } }; |