spi: meson-spicc: adapt burst handling for G12A support
The G12A SPICC controller variant has a different FIFO size and doesn't handle the RX Half interrupt the same way as GXL & AXG variants. Thus simplify the burst management and take in account a variable FIFO size. Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Link: https://lore.kernel.org/r/20200312133131.26430-8-narmstrong@baylibre.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
f27bff479e
commit
0eb707ac7d
@ -141,12 +141,10 @@
|
||||
#define writel_bits_relaxed(mask, val, addr) \
|
||||
writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)
|
||||
|
||||
#define SPICC_BURST_MAX 16
|
||||
#define SPICC_FIFO_HALF 10
|
||||
|
||||
struct meson_spicc_data {
|
||||
unsigned int max_speed_hz;
|
||||
unsigned int min_speed_hz;
|
||||
unsigned int fifo_size;
|
||||
bool has_oen;
|
||||
bool has_enhance_clk_div;
|
||||
};
|
||||
@ -166,8 +164,6 @@ struct meson_spicc_device {
|
||||
unsigned long tx_remain;
|
||||
unsigned long rx_remain;
|
||||
unsigned long xfer_remain;
|
||||
bool is_burst_end;
|
||||
bool is_last_burst;
|
||||
};
|
||||
|
||||
static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
|
||||
@ -191,7 +187,7 @@ static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
|
||||
|
||||
static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc)
|
||||
{
|
||||
return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF_EN,
|
||||
return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF,
|
||||
readl_relaxed(spicc->base + SPICC_STATREG));
|
||||
}
|
||||
|
||||
@ -246,34 +242,22 @@ static inline void meson_spicc_tx(struct meson_spicc_device *spicc)
|
||||
spicc->base + SPICC_TXDATA);
|
||||
}
|
||||
|
||||
static inline u32 meson_spicc_setup_rx_irq(struct meson_spicc_device *spicc,
|
||||
u32 irq_ctrl)
|
||||
static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc)
|
||||
{
|
||||
if (spicc->rx_remain > SPICC_FIFO_HALF)
|
||||
irq_ctrl |= SPICC_RH_EN;
|
||||
else
|
||||
irq_ctrl |= SPICC_RR_EN;
|
||||
|
||||
return irq_ctrl;
|
||||
}
|
||||
|
||||
static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc,
|
||||
unsigned int burst_len)
|
||||
{
|
||||
unsigned int burst_len = min_t(unsigned int,
|
||||
spicc->xfer_remain /
|
||||
spicc->bytes_per_word,
|
||||
spicc->data->fifo_size);
|
||||
/* Setup Xfer variables */
|
||||
spicc->tx_remain = burst_len;
|
||||
spicc->rx_remain = burst_len;
|
||||
spicc->xfer_remain -= burst_len * spicc->bytes_per_word;
|
||||
spicc->is_burst_end = false;
|
||||
if (burst_len < SPICC_BURST_MAX || !spicc->xfer_remain)
|
||||
spicc->is_last_burst = true;
|
||||
else
|
||||
spicc->is_last_burst = false;
|
||||
|
||||
/* Setup burst length */
|
||||
writel_bits_relaxed(SPICC_BURSTLENGTH_MASK,
|
||||
FIELD_PREP(SPICC_BURSTLENGTH_MASK,
|
||||
burst_len),
|
||||
burst_len - 1),
|
||||
spicc->base + SPICC_CONREG);
|
||||
|
||||
/* Fill TX FIFO */
|
||||
@ -283,61 +267,26 @@ static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc,
|
||||
static irqreturn_t meson_spicc_irq(int irq, void *data)
|
||||
{
|
||||
struct meson_spicc_device *spicc = (void *) data;
|
||||
u32 ctrl = readl_relaxed(spicc->base + SPICC_INTREG);
|
||||
u32 stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
|
||||
|
||||
ctrl &= ~(SPICC_RH_EN | SPICC_RR_EN);
|
||||
writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG);
|
||||
|
||||
/* Empty RX FIFO */
|
||||
meson_spicc_rx(spicc);
|
||||
|
||||
/* Enable TC interrupt since we transferred everything */
|
||||
if (!spicc->tx_remain && !spicc->rx_remain) {
|
||||
spicc->is_burst_end = true;
|
||||
if (!spicc->xfer_remain) {
|
||||
/* Disable all IRQs */
|
||||
writel(0, spicc->base + SPICC_INTREG);
|
||||
|
||||
/* Enable TC interrupt */
|
||||
ctrl |= SPICC_TC_EN;
|
||||
spi_finalize_current_transfer(spicc->master);
|
||||
|
||||
/* Reload IRQ status */
|
||||
stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Check transfer complete */
|
||||
if ((stat & SPICC_TC) && spicc->is_burst_end) {
|
||||
unsigned int burst_len;
|
||||
/* Setup burst */
|
||||
meson_spicc_setup_burst(spicc);
|
||||
|
||||
/* Clear TC bit */
|
||||
writel_relaxed(SPICC_TC, spicc->base + SPICC_STATREG);
|
||||
|
||||
/* Disable TC interrupt */
|
||||
ctrl &= ~SPICC_TC_EN;
|
||||
|
||||
if (spicc->is_last_burst) {
|
||||
/* Disable all IRQs */
|
||||
writel(0, spicc->base + SPICC_INTREG);
|
||||
|
||||
spi_finalize_current_transfer(spicc->master);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
burst_len = min_t(unsigned int,
|
||||
spicc->xfer_remain / spicc->bytes_per_word,
|
||||
SPICC_BURST_MAX);
|
||||
|
||||
/* Setup burst */
|
||||
meson_spicc_setup_burst(spicc, burst_len);
|
||||
|
||||
/* Restart burst */
|
||||
writel_bits_relaxed(SPICC_XCH, SPICC_XCH,
|
||||
spicc->base + SPICC_CONREG);
|
||||
}
|
||||
|
||||
/* Setup RX interrupt trigger */
|
||||
ctrl = meson_spicc_setup_rx_irq(spicc, ctrl);
|
||||
|
||||
/* Reconfigure interrupts */
|
||||
writel(ctrl, spicc->base + SPICC_INTREG);
|
||||
/* Start burst */
|
||||
writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -405,6 +354,28 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
|
||||
clk_set_rate(spicc->clk, xfer->speed_hz);
|
||||
|
||||
meson_spicc_auto_io_delay(spicc);
|
||||
|
||||
writel_relaxed(0, spicc->base + SPICC_DMAREG);
|
||||
}
|
||||
|
||||
static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
if (spicc->data->has_oen)
|
||||
writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO,
|
||||
SPICC_ENH_MAIN_CLK_AO,
|
||||
spicc->base + SPICC_ENH_CTL0);
|
||||
|
||||
writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK,
|
||||
spicc->base + SPICC_TESTREG);
|
||||
|
||||
while (meson_spicc_rxready(spicc))
|
||||
data = readl_relaxed(spicc->base + SPICC_RXDATA);
|
||||
|
||||
if (spicc->data->has_oen)
|
||||
writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0,
|
||||
spicc->base + SPICC_ENH_CTL0);
|
||||
}
|
||||
|
||||
static int meson_spicc_transfer_one(struct spi_master *master,
|
||||
@ -412,8 +383,6 @@ static int meson_spicc_transfer_one(struct spi_master *master,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct meson_spicc_device *spicc = spi_master_get_devdata(master);
|
||||
unsigned int burst_len;
|
||||
u32 irq = 0;
|
||||
|
||||
/* Store current transfer */
|
||||
spicc->xfer = xfer;
|
||||
@ -427,22 +396,22 @@ static int meson_spicc_transfer_one(struct spi_master *master,
|
||||
spicc->bytes_per_word =
|
||||
DIV_ROUND_UP(spicc->xfer->bits_per_word, 8);
|
||||
|
||||
if (xfer->len % spicc->bytes_per_word)
|
||||
return -EINVAL;
|
||||
|
||||
/* Setup transfer parameters */
|
||||
meson_spicc_setup_xfer(spicc, xfer);
|
||||
|
||||
burst_len = min_t(unsigned int,
|
||||
spicc->xfer_remain / spicc->bytes_per_word,
|
||||
SPICC_BURST_MAX);
|
||||
meson_spicc_reset_fifo(spicc);
|
||||
|
||||
meson_spicc_setup_burst(spicc, burst_len);
|
||||
|
||||
irq = meson_spicc_setup_rx_irq(spicc, irq);
|
||||
/* Setup burst */
|
||||
meson_spicc_setup_burst(spicc);
|
||||
|
||||
/* Start burst */
|
||||
writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
|
||||
|
||||
/* Enable interrupts */
|
||||
writel_relaxed(irq, spicc->base + SPICC_INTREG);
|
||||
writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -499,7 +468,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
|
||||
/* Setup no wait cycles by default */
|
||||
writel_relaxed(0, spicc->base + SPICC_PERIODREG);
|
||||
|
||||
writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG);
|
||||
writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -797,11 +766,13 @@ static int meson_spicc_remove(struct platform_device *pdev)
|
||||
static const struct meson_spicc_data meson_spicc_gx_data = {
|
||||
.max_speed_hz = 30000000,
|
||||
.min_speed_hz = 325000,
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static const struct meson_spicc_data meson_spicc_axg_data = {
|
||||
.max_speed_hz = 80000000,
|
||||
.min_speed_hz = 325000,
|
||||
.fifo_size = 16,
|
||||
.has_oen = true,
|
||||
.has_enhance_clk_div = true,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user