提交 0d72c717 编写于 作者: C Cédric Le Goater 提交者: Peter Maydell

aspeed/smc: Add DMA calibration settings

When doing calibration, the SPI clock rate in the CE0 Control Register
and the read delay cycles in the Read Timing Compensation Register are
set using bit[11:4] of the DMA Control Register.
Signed-off-by: NCédric Le Goater <clg@kaod.org>
Acked-by: NJoel Stanley <joel@jms.id.au>
Reviewed-by: NPeter Maydell <peter.maydell@linaro.org>
Message-id: 20190904070506.1052-7-clg@kaod.org
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
上级 c4e1f0b4
......@@ -77,6 +77,10 @@
#define CTRL_CMD_MASK 0xff
#define CTRL_DUMMY_HIGH_SHIFT 14
#define CTRL_AST2400_SPI_4BYTE (1 << 13)
#define CE_CTRL_CLOCK_FREQ_SHIFT 8
#define CE_CTRL_CLOCK_FREQ_MASK 0xf
#define CE_CTRL_CLOCK_FREQ(div) \
(((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT)
#define CTRL_DUMMY_LOW_SHIFT 6 /* 2 bits [7:6] */
#define CTRL_CE_STOP_ACTIVE (1 << 2)
#define CTRL_CMD_MODE_MASK 0x3
......@@ -112,7 +116,7 @@
#define DMA_CTRL_DELAY_SHIFT 8
#define DMA_CTRL_FREQ_MASK 0xf
#define DMA_CTRL_FREQ_SHIFT 4
#define DMA_CTRL_MODE (1 << 3)
#define DMA_CTRL_CALIB (1 << 3)
#define DMA_CTRL_CKSUM (1 << 2)
#define DMA_CTRL_WRITE (1 << 1)
#define DMA_CTRL_ENABLE (1 << 0)
......@@ -811,6 +815,60 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
}
}
static uint8_t aspeed_smc_hclk_divisor(uint8_t hclk_mask)
{
/* HCLK/1 .. HCLK/16 */
const uint8_t hclk_divisors[] = {
15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
};
int i;
for (i = 0; i < ARRAY_SIZE(hclk_divisors); i++) {
if (hclk_mask == hclk_divisors[i]) {
return i + 1;
}
}
qemu_log_mask(LOG_GUEST_ERROR, "invalid HCLK mask %x", hclk_mask);
return 0;
}
/*
* When doing calibration, the SPI clock rate in the CE0 Control
* Register and the read delay cycles in the Read Timing Compensation
* Register are set using bit[11:4] of the DMA Control Register.
*/
static void aspeed_smc_dma_calibration(AspeedSMCState *s)
{
uint8_t delay =
(s->regs[R_DMA_CTRL] >> DMA_CTRL_DELAY_SHIFT) & DMA_CTRL_DELAY_MASK;
uint8_t hclk_mask =
(s->regs[R_DMA_CTRL] >> DMA_CTRL_FREQ_SHIFT) & DMA_CTRL_FREQ_MASK;
uint8_t hclk_div = aspeed_smc_hclk_divisor(hclk_mask);
uint32_t hclk_shift = (hclk_div - 1) << 2;
uint8_t cs;
/*
* The Read Timing Compensation Register values apply to all CS on
* the SPI bus and only HCLK/1 - HCLK/5 can have tunable delays
*/
if (hclk_div && hclk_div < 6) {
s->regs[s->r_timings] &= ~(0xf << hclk_shift);
s->regs[s->r_timings] |= delay << hclk_shift;
}
/*
* TODO: compute the CS from the DMA address and the segment
* registers. This is not really a problem for now because the
* Timing Register values apply to all CS and software uses CS0 to
* do calibration.
*/
cs = 0;
s->regs[s->r_ctrl0 + cs] &=
~(CE_CTRL_CLOCK_FREQ_MASK << CE_CTRL_CLOCK_FREQ_SHIFT);
s->regs[s->r_ctrl0 + cs] |= CE_CTRL_CLOCK_FREQ(hclk_div);
}
/*
* Accumulate the result of the reads to provide a checksum that will
* be used to validate the read timing settings.
......@@ -826,6 +884,10 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
return;
}
if (s->regs[R_DMA_CTRL] & DMA_CTRL_CALIB) {
aspeed_smc_dma_calibration(s);
}
while (s->regs[R_DMA_LEN]) {
data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR],
MEMTXATTRS_UNSPECIFIED, &result);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册