diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ssi/aspeed_smc.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index fe1cd96..0b8488a 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -178,13 +178,17 @@ * DMA flash addresses should be 4 bytes aligned and the valid address * range is 0x20000000 - 0x2FFFFFFF. * - * DMA length is from 4 bytes to 32MB + * DMA length is from 4 bytes to 32MB (AST2500) * 0: 4 bytes - * 0x7FFFFF: 32M bytes + * 0x1FFFFFC: 32M bytes + * + * DMA length is from 1 byte to 32MB (AST2600, AST10x0) + * 0: 1 byte + * 0x1FFFFFF: 32M bytes */ #define DMA_DRAM_ADDR(asc, val) ((val) & (asc)->dma_dram_mask) #define DMA_FLASH_ADDR(asc, val) ((val) & (asc)->dma_flash_mask) -#define DMA_LENGTH(val) ((val) & 0x01FFFFFC) +#define DMA_LENGTH(val) ((val) & 0x01FFFFFF) /* Flash opcodes. */ #define SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ @@ -843,6 +847,13 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s) } } +static uint32_t aspeed_smc_dma_len(AspeedSMCState *s) +{ + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + return QEMU_ALIGN_UP(s->regs[R_DMA_LEN] + asc->dma_start_length, 4); +} + /* * Accumulate the result of the reads to provide a checksum that will * be used to validate the read timing settings. @@ -850,6 +861,7 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s) static void aspeed_smc_dma_checksum(AspeedSMCState *s) { MemTxResult result; + uint32_t dma_len; uint32_t data; if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) { @@ -861,7 +873,9 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s) aspeed_smc_dma_calibration(s); } - while (s->regs[R_DMA_LEN]) { + dma_len = aspeed_smc_dma_len(s); + + while (dma_len) { data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR], MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { @@ -877,7 +891,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s) */ s->regs[R_DMA_CHECKSUM] += data; s->regs[R_DMA_FLASH_ADDR] += 4; - s->regs[R_DMA_LEN] -= 4; + dma_len -= 4; + s->regs[R_DMA_LEN] = dma_len; } if (s->inject_failure && aspeed_smc_inject_read_failure(s)) { @@ -889,14 +904,17 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s) static void aspeed_smc_dma_rw(AspeedSMCState *s) { MemTxResult result; + uint32_t dma_len; uint32_t data; + dma_len = aspeed_smc_dma_len(s); + trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ? "write" : "read", s->regs[R_DMA_FLASH_ADDR], s->regs[R_DMA_DRAM_ADDR], - s->regs[R_DMA_LEN]); - while (s->regs[R_DMA_LEN]) { + dma_len); + while (dma_len) { if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) { data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR], MEMTXATTRS_UNSPECIFIED, &result); @@ -937,7 +955,8 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s) */ s->regs[R_DMA_FLASH_ADDR] += 4; s->regs[R_DMA_DRAM_ADDR] += 4; - s->regs[R_DMA_LEN] -= 4; + dma_len -= 4; + s->regs[R_DMA_LEN] = dma_len; s->regs[R_DMA_CHECKSUM] += data; } } @@ -1382,6 +1401,7 @@ static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data) asc->features = ASPEED_SMC_FEATURE_DMA; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x1FFFFFFC; + asc->dma_start_length = 4; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_smc_segment_to_reg; asc->reg_to_segment = aspeed_smc_reg_to_segment; @@ -1465,6 +1485,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data) asc->features = ASPEED_SMC_FEATURE_DMA; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x3FFFFFFC; + asc->dma_start_length = 4; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_smc_segment_to_reg; asc->reg_to_segment = aspeed_smc_reg_to_segment; @@ -1621,6 +1642,7 @@ static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data) ASPEED_SMC_FEATURE_WDT_CONTROL; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x3FFFFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; @@ -1659,6 +1681,7 @@ static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data) ASPEED_SMC_FEATURE_DMA_GRANT; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x3FFFFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; @@ -1698,6 +1721,7 @@ static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data) ASPEED_SMC_FEATURE_DMA_GRANT; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x3FFFFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; @@ -1779,6 +1803,7 @@ static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data) asc->features = ASPEED_SMC_FEATURE_DMA; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x000BFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_1030_smc_segment_to_reg; asc->reg_to_segment = aspeed_1030_smc_reg_to_segment; @@ -1816,6 +1841,7 @@ static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data) asc->features = ASPEED_SMC_FEATURE_DMA; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x000BFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; @@ -1852,6 +1878,7 @@ static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data) asc->features = ASPEED_SMC_FEATURE_DMA; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0x000BFFFC; + asc->dma_start_length = 1; asc->nregs = ASPEED_SMC_R_MAX; asc->segment_to_reg = aspeed_2600_smc_segment_to_reg; asc->reg_to_segment = aspeed_2600_smc_reg_to_segment; |