Merge 0986efc3c7 ("spi: atmel-qspi: Memory barriers after memory-mapped I/O") into android14-6.1-lts

Steps on the way to 6.1.130

Change-Id: I9fa2d1d29e6523458cd471d93d06bfba78e920ba
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-03-12 16:32:40 +00:00

View File

@@ -138,11 +138,15 @@
#define QSPI_WPSR_WPVSRC_MASK GENMASK(15, 8)
#define QSPI_WPSR_WPVSRC(src) (((src) << 8) & QSPI_WPSR_WPVSRC)
#define ATMEL_QSPI_TIMEOUT 1000 /* ms */
struct atmel_qspi_caps {
bool has_qspick;
bool has_ricr;
};
struct atmel_qspi_ops;
struct atmel_qspi {
void __iomem *regs;
void __iomem *mem;
@@ -150,13 +154,22 @@ struct atmel_qspi {
struct clk *qspick;
struct platform_device *pdev;
const struct atmel_qspi_caps *caps;
const struct atmel_qspi_ops *ops;
resource_size_t mmap_size;
u32 pending;
u32 irq_mask;
u32 mr;
u32 scr;
struct completion cmd_completion;
};
struct atmel_qspi_ops {
int (*set_cfg)(struct atmel_qspi *aq, const struct spi_mem_op *op,
u32 *offset);
int (*transfer)(struct spi_mem *mem, const struct spi_mem_op *op,
u32 offset);
};
struct atmel_qspi_mode {
u8 cmd_buswidth;
u8 addr_buswidth;
@@ -404,10 +417,67 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
return 0;
}
static int atmel_qspi_wait_for_completion(struct atmel_qspi *aq, u32 irq_mask)
{
int err = 0;
u32 sr;
/* Poll INSTRuction End status */
sr = atmel_qspi_read(aq, QSPI_SR);
if ((sr & irq_mask) == irq_mask)
return 0;
/* Wait for INSTRuction End interrupt */
reinit_completion(&aq->cmd_completion);
aq->pending = sr & irq_mask;
aq->irq_mask = irq_mask;
atmel_qspi_write(irq_mask, aq, QSPI_IER);
if (!wait_for_completion_timeout(&aq->cmd_completion,
msecs_to_jiffies(ATMEL_QSPI_TIMEOUT)))
err = -ETIMEDOUT;
atmel_qspi_write(irq_mask, aq, QSPI_IDR);
return err;
}
static int atmel_qspi_transfer(struct spi_mem *mem,
const struct spi_mem_op *op, u32 offset)
{
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
/* Skip to the final steps if there is no data */
if (!op->data.nbytes)
return atmel_qspi_wait_for_completion(aq,
QSPI_SR_CMD_COMPLETED);
/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
(void)atmel_qspi_read(aq, QSPI_IFR);
/* Send/Receive data */
if (op->data.dir == SPI_MEM_DATA_IN) {
memcpy_fromio(op->data.buf.in, aq->mem + offset,
op->data.nbytes);
/* Synchronize AHB and APB accesses again */
rmb();
} else {
memcpy_toio(aq->mem + offset, op->data.buf.out,
op->data.nbytes);
/* Synchronize AHB and APB accesses again */
wmb();
}
/* Release the chip-select */
atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
return atmel_qspi_wait_for_completion(aq, QSPI_SR_CMD_COMPLETED);
}
static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->master);
u32 sr, offset;
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
u32 offset;
int err;
/*
@@ -416,46 +486,20 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
* when the flash memories overrun the controller's memory space.
*/
if (op->addr.val + op->data.nbytes > aq->mmap_size)
return -ENOTSUPP;
return -EOPNOTSUPP;
if (op->addr.nbytes > 4)
return -EOPNOTSUPP;
err = pm_runtime_resume_and_get(&aq->pdev->dev);
if (err < 0)
return err;
err = atmel_qspi_set_cfg(aq, op, &offset);
err = aq->ops->set_cfg(aq, op, &offset);
if (err)
goto pm_runtime_put;
/* Skip to the final steps if there is no data */
if (op->data.nbytes) {
/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
(void)atmel_qspi_read(aq, QSPI_IFR);
/* Send/Receive data */
if (op->data.dir == SPI_MEM_DATA_IN)
memcpy_fromio(op->data.buf.in, aq->mem + offset,
op->data.nbytes);
else
memcpy_toio(aq->mem + offset, op->data.buf.out,
op->data.nbytes);
/* Release the chip-select */
atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
}
/* Poll INSTRuction End status */
sr = atmel_qspi_read(aq, QSPI_SR);
if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
goto pm_runtime_put;
/* Wait for INSTRuction End interrupt */
reinit_completion(&aq->cmd_completion);
aq->pending = sr & QSPI_SR_CMD_COMPLETED;
atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IER);
if (!wait_for_completion_timeout(&aq->cmd_completion,
msecs_to_jiffies(1000)))
err = -ETIMEDOUT;
atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
err = aq->ops->transfer(mem, op, offset);
pm_runtime_put:
pm_runtime_mark_last_busy(&aq->pdev->dev);
@@ -476,7 +520,7 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
static int atmel_qspi_setup(struct spi_device *spi)
{
struct spi_controller *ctrl = spi->master;
struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long src_rate;
u32 scbr;
@@ -510,6 +554,39 @@ static int atmel_qspi_setup(struct spi_device *spi)
return 0;
}
static int atmel_qspi_set_cs_timing(struct spi_device *spi)
{
struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long clk_rate;
u32 cs_setup;
int delay;
int ret;
delay = spi_delay_to_ns(&spi->cs_setup, NULL);
if (delay <= 0)
return delay;
clk_rate = clk_get_rate(aq->pclk);
if (!clk_rate)
return -EINVAL;
cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)),
1000);
ret = pm_runtime_resume_and_get(ctrl->dev.parent);
if (ret < 0)
return ret;
aq->scr |= QSPI_SCR_DLYBS(cs_setup);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0;
}
static void atmel_qspi_init(struct atmel_qspi *aq)
{
/* Reset the QSPI controller */
@@ -536,12 +613,17 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
return IRQ_NONE;
aq->pending |= pending;
if ((aq->pending & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
if ((aq->pending & aq->irq_mask) == aq->irq_mask)
complete(&aq->cmd_completion);
return IRQ_HANDLED;
}
static const struct atmel_qspi_ops atmel_qspi_ops = {
.set_cfg = atmel_qspi_set_cfg,
.transfer = atmel_qspi_transfer,
};
static int atmel_qspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctrl;
@@ -555,6 +637,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
ctrl->setup = atmel_qspi_setup;
ctrl->set_cs_timing = atmel_qspi_set_cs_timing;
ctrl->bus_num = -1;
ctrl->mem_ops = &atmel_qspi_mem_ops;
ctrl->num_chipselect = 1;
@@ -565,6 +648,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
init_completion(&aq->cmd_completion);
aq->pdev = pdev;
aq->ops = &atmel_qspi_ops;
/* Map the registers */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");