From: Witold Sadowski <wsadowski@marvell.com>
To: <linux-kernel@vger.kernel.org>, <linux-spi@vger.kernel.org>,
<devicetree@vger.kernel.org>
Cc: <broonie@kernel.org>, <robh@kernel.org>,
<krzysztof.kozlowski+dt@linaro.org>, <conor+dt@kernel.org>,
<pthombar@cadence.com>, Witold Sadowski <wsadowski@marvell.com>
Subject: [PATCH 5/5] cadence-xspi: Add xfer capabilities
Date: Fri, 29 Mar 2024 12:48:49 -0700 [thread overview]
Message-ID: <20240329194849.25554-6-wsadowski@marvell.com> (raw)
In-Reply-To: <20240329194849.25554-1-wsadowski@marvell.com>
Add support for iMRVL xfer hw_overlay of Cadence xSPI
block.
MRVL Xfer overlay extend xSPI capabilities, to support
non-memory SPI operations.
With generic xSPI command it allows to create any
required SPI transaction
Signed-off-by: Witold Sadowski <wsadowski@marvell.com>
---
drivers/spi/spi-cadence-xspi.c | 249 +++++++++++++++++++++++++++++++++
1 file changed, 249 insertions(+)
diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c
index 01e81d40f04c..451f83d53898 100644
--- a/drivers/spi/spi-cadence-xspi.c
+++ b/drivers/spi/spi-cadence-xspi.c
@@ -219,19 +219,38 @@
#define CDNS_XSPI_DLL_RST_N BIT(24)
#define CDNS_XSPI_DLL_LOCK BIT(0)
+#define CDNS_XSPI_POLL_TIMEOUT_US 1000
+#define CDNS_XSPI_POLL_DELAY_US 10
+
/* Marvell clock config register */
#define CDNS_MRVL_XSPI_CLK_CTRL_AUX_REG 0x2020
#define CDNS_MRVL_XSPI_CLK_ENABLE BIT(0)
#define CDNS_MRVL_XSPI_CLK_DIV GENMASK(4, 1)
+
/* Marvell MSI-X clear interrupt register */
#define CDNS_MRVL_XSPI_SPIX_INTR_AUX 0x2000
#define CDNS_MRVL_MSIX_CLEAR_IRQ 0x01
+#define SPIX_XFER_FUNC_CTRL 0x210
+#define SPIX_XFER_FUNC_CTRL_READ_DATA(i) (0x000 + 8 * (i))
+
/* Marvell clock macros */
#define CDNS_MRVL_XSPI_CLOCK_IO_HZ 800000000
#define CDNS_MRVL_XSPI_CLOCK_DIVIDED(div) ((CDNS_MRVL_XSPI_CLOCK_IO_HZ) / (div))
+/* Marvell XFER registers */
+#define XFER_SOFT_RESET BIT(11)
+#define XFER_CS_N_HOLD GENMASK(9, 6)
+#define XFER_RECEIVE_ENABLE BIT(4)
+#define XFER_FUNC_ENABLE BIT(3)
+#define XFER_CLK_CAPTURE_POL BIT(2)
+#define XFER_CLK_DRIVE_POL BIT(1)
+#define XFER_FUNC_START BIT(0)
+
+#define XFER_QWORD_COUNT 32
+#define XFER_QWORD_BYTECOUNT 8
+
enum cdns_xspi_stig_instr_type {
CDNS_XSPI_STIG_INSTR_TYPE_0,
CDNS_XSPI_STIG_INSTR_TYPE_1,
@@ -256,6 +275,7 @@ struct cdns_xspi_dev {
void __iomem *iobase;
void __iomem *auxbase;
void __iomem *sdmabase;
+ void __iomem *xferbase;
int irq;
int cur_cs;
@@ -270,6 +290,9 @@ struct cdns_xspi_dev {
const void *out_buffer;
u8 hw_num_banks;
+
+ bool xfer_in_progress;
+ int current_xfer_qword;
};
#define MRVL_DEFAULT_CLK 25000000
@@ -884,6 +907,221 @@ static bool cdns_xspi_get_hw_overlay(struct platform_device *pdev)
return (err >= 0);
}
+
+static int cdns_xspi_prepare_generic(int cs, const void *dout, int len, int glue, u32 *cmd_regs)
+{
+ u8 *data = (u8 *)dout;
+ int i;
+ int data_counter = 0;
+
+ memset(cmd_regs, 0x00, 6*4);
+
+ if (len > 7) {
+ for (i = (len >= 10 ? 2 : len - 8); i >= 0 ; i--)
+ cmd_regs[3] |= data[data_counter++] << (8*i);
+ }
+ if (len > 3) {
+ for (i = (len >= 7 ? 3 : len - 4); i >= 0; i--)
+ cmd_regs[2] |= data[data_counter++] << (8*i);
+ }
+ for (i = (len >= 3 ? 2 : len - 1); i >= 0 ; i--)
+ cmd_regs[1] |= data[data_counter++] << (8 + 8*i);
+
+ cmd_regs[1] |= 96;
+ cmd_regs[3] |= len << 24;
+ cmd_regs[4] |= cs << 12;
+
+ if (glue == 1)
+ cmd_regs[4] |= 1 << 28;
+
+ return 0;
+}
+
+unsigned char reverse_bits(unsigned char num)
+{
+ unsigned int count = sizeof(num) * 8 - 1;
+ unsigned int reverse_num = num;
+
+ num >>= 1;
+ while (num) {
+ reverse_num <<= 1;
+ reverse_num |= num & 1;
+ num >>= 1;
+ count--;
+ }
+ reverse_num <<= count;
+ return reverse_num;
+}
+
+static void cdns_xspi_read_single_qword(struct cdns_xspi_dev *cdns_xspi, u8 **buffer)
+{
+ u64 d = readq(cdns_xspi->xferbase +
+ SPIX_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword));
+ u8 *ptr = (u8 *)&d;
+ int k;
+
+ for (k = 0; k < 8; k++) {
+ u8 val = reverse_bits((ptr[k]));
+ **buffer = val;
+ *buffer = *buffer + 1;
+ }
+
+ cdns_xspi->current_xfer_qword++;
+ cdns_xspi->current_xfer_qword %= XFER_QWORD_COUNT;
+}
+
+static void cdns_xspi_finish_read(struct cdns_xspi_dev *cdns_xspi, u8 **buffer, u32 data_count)
+{
+ u64 d = readq(cdns_xspi->xferbase +
+ SPIX_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword));
+ u8 *ptr = (u8 *)&d;
+ int k;
+
+ for (k = 0; k < data_count % XFER_QWORD_BYTECOUNT; k++) {
+ u8 val = reverse_bits((ptr[k]));
+ **buffer = val;
+ *buffer = *buffer + 1;
+ }
+
+ cdns_xspi->current_xfer_qword++;
+ cdns_xspi->current_xfer_qword %= XFER_QWORD_COUNT;
+}
+
+static int cdns_xspi_prepare_transfer(int cs, int dir, int len, u32 *cmd_regs)
+{
+ memset(cmd_regs, 0x00, 6*4);
+
+ cmd_regs[1] |= 127;
+ cmd_regs[2] |= len << 16;
+ cmd_regs[4] |= dir << 4; //dir = 0 read, dir =1 write
+ cmd_regs[4] |= cs << 12;
+
+ return 0;
+}
+
+bool cdns_xspi_stig_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep)
+{
+ u32 ctrl_stat;
+
+ return readl_relaxed_poll_timeout
+ (cdns_xspi->iobase + CDNS_XSPI_CTRL_STATUS_REG,
+ ctrl_stat,
+ ((ctrl_stat & BIT(3)) == 0),
+ sleep ? CDNS_XSPI_POLL_DELAY_US : 0,
+ sleep ? CDNS_XSPI_POLL_TIMEOUT_US : 0);
+}
+
+bool cdns_xspi_sdma_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep)
+{
+ u32 ctrl_stat;
+
+ return readl_relaxed_poll_timeout
+ (cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG,
+ ctrl_stat,
+ (ctrl_stat & CDNS_XSPI_SDMA_TRIGGER),
+ sleep ? CDNS_XSPI_POLL_DELAY_US : 0,
+ sleep ? CDNS_XSPI_POLL_TIMEOUT_US : 0);
+}
+
+int cdns_xspi_transfer_one_message_b0(struct spi_controller *master,
+ struct spi_message *m)
+{
+ struct cdns_xspi_dev *cdns_xspi = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+
+ const int max_len = XFER_QWORD_BYTECOUNT * XFER_QWORD_COUNT;
+ int current_cycle_count;
+ int cs = spi->chip_select;
+ int cs_change = 0;
+
+ /* Enable xfer state machine */
+ if (!cdns_xspi->xfer_in_progress) {
+ u32 xfer_control = readl(cdns_xspi->xferbase + SPIX_XFER_FUNC_CTRL);
+
+ cdns_xspi->current_xfer_qword = 0;
+ cdns_xspi->xfer_in_progress = true;
+ xfer_control |= (XFER_RECEIVE_ENABLE |
+ XFER_CLK_CAPTURE_POL |
+ XFER_FUNC_START |
+ XFER_SOFT_RESET |
+ FIELD_PREP(XFER_CS_N_HOLD, (1 << cs)));
+ xfer_control &= ~(XFER_FUNC_ENABLE | XFER_CLK_DRIVE_POL);
+ writel(xfer_control, cdns_xspi->xferbase + SPIX_XFER_FUNC_CTRL);
+ }
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *txd = (u8 *) t->tx_buf;
+ u8 *rxd = (u8 *) t->rx_buf;
+ u8 data[10];
+ u32 cmd_regs[6];
+
+ if (!txd)
+ txd = data;
+
+ cdns_xspi->in_buffer = txd + 1;
+ cdns_xspi->out_buffer = txd + 1;
+
+ while (t->len) {
+
+ current_cycle_count = t->len > max_len ? max_len : t->len;
+
+ if (current_cycle_count < 10) {
+ cdns_xspi_prepare_generic(cs, txd, current_cycle_count,
+ false, cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ if (cdns_xspi_stig_ready(cdns_xspi, true))
+ return -EIO;
+ } else {
+ cdns_xspi_prepare_generic(cs, txd, 1, true, cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ cdns_xspi_prepare_transfer(cs, 1, current_cycle_count - 1,
+ cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ if (cdns_xspi_sdma_ready(cdns_xspi, true))
+ return -EIO;
+ cdns_xspi_sdma_handle(cdns_xspi);
+ if (cdns_xspi_stig_ready(cdns_xspi, true))
+ return -EIO;
+
+ cdns_xspi->in_buffer += current_cycle_count;
+ cdns_xspi->out_buffer += current_cycle_count;
+ }
+
+ if (rxd) {
+ int j;
+
+ for (j = 0; j < current_cycle_count / 8; j++)
+ cdns_xspi_read_single_qword(cdns_xspi, &rxd);
+ cdns_xspi_finish_read(cdns_xspi, &rxd, current_cycle_count);
+ } else {
+ cdns_xspi->current_xfer_qword += current_cycle_count /
+ XFER_QWORD_BYTECOUNT;
+ if (current_cycle_count % XFER_QWORD_BYTECOUNT)
+ cdns_xspi->current_xfer_qword++;
+
+ cdns_xspi->current_xfer_qword %= XFER_QWORD_COUNT;
+ }
+ cs_change = t->cs_change;
+ t->len -= current_cycle_count;
+ }
+ }
+
+ if (!cs_change) {
+ u32 xfer_control = readl(cdns_xspi->xferbase + SPIX_XFER_FUNC_CTRL);
+
+ xfer_control &= ~(XFER_RECEIVE_ENABLE |
+ XFER_SOFT_RESET);
+ writel(xfer_control, cdns_xspi->xferbase + SPIX_XFER_FUNC_CTRL);
+ cdns_xspi->xfer_in_progress = false;
+ }
+
+ m->status = 0;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
static int cdns_xspi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -948,6 +1186,16 @@ static int cdns_xspi_probe(struct platform_device *pdev)
return PTR_ERR(cdns_xspi->auxbase);
}
+ if (hw_overlay) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ cdns_xspi->xferbase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(cdns_xspi->xferbase)) {
+ dev_info(dev, "XFER register base not found, set it\n");
+ // For compatibility with older firmware
+ cdns_xspi->xferbase = cdns_xspi->iobase + 0x8000;
+ }
+ }
+
cdns_xspi->irq = platform_get_irq(pdev, 0);
if (cdns_xspi->irq < 0)
return -ENXIO;
@@ -962,6 +1210,7 @@ static int cdns_xspi_probe(struct platform_device *pdev)
if (hw_overlay) {
cdns_mrvl_xspi_setup_clock(cdns_xspi, MRVL_DEFAULT_CLK);
cdns_xspi_configure_phy(cdns_xspi);
+ host->transfer_one_message = cdns_xspi_transfer_one_message_b0;
}
cdns_xspi_print_phy_config(cdns_xspi);
--
2.17.1
next prev parent reply other threads:[~2024-03-29 19:49 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-29 19:48 [PATCH 0/5] Support for Cadence xSPI Marvell modifications Witold Sadowski
2024-03-29 19:48 ` [PATCH 1/5] spi: cadence: Add new bindings documentation for Cadence XSPI Witold Sadowski
2024-03-29 21:09 ` Rob Herring
2024-03-30 11:32 ` Krzysztof Kozlowski
2024-04-29 7:48 ` Krzysztof Kozlowski
2024-03-31 10:43 ` kernel test robot
2024-03-29 19:48 ` [PATCH 2/5] spi: cadence: Add Marvell IP modification changes Witold Sadowski
2024-03-30 11:33 ` Krzysztof Kozlowski
2024-04-29 14:55 ` [EXTERNAL] " Witold Sadowski
2024-04-30 7:56 ` Krzysztof Kozlowski
2024-03-31 7:46 ` kernel test robot
2024-03-31 10:50 ` Krzysztof Kozlowski
2024-03-29 19:48 ` [PATCH 3/5] spi: cadence: Force single modebyte Witold Sadowski
2024-03-29 19:48 ` [PATCH 4/5] driver: spi: cadence: Add ACPI support Witold Sadowski
2024-03-30 11:36 ` Krzysztof Kozlowski
2024-03-31 7:35 ` kernel test robot
2024-03-29 19:48 ` Witold Sadowski [this message]
2024-03-30 11:37 ` [PATCH 5/5] cadence-xspi: Add xfer capabilities Krzysztof Kozlowski
2024-03-31 3:25 ` kernel test robot
2024-04-18 1:13 ` [PATCH v3 0/5] Marvell HW overlay support for Cadence xSPI Witold Sadowski
2024-04-18 1:13 ` [PATCH v3 1/5] spi: cadence: Ensure data lines set to low during dummy-cycle period Witold Sadowski
2024-04-18 1:13 ` [PATCH v3 2/5] spi: cadence: Add MRVL overlay bindings documentation for Cadence XSPI Witold Sadowski
2024-04-18 16:22 ` Conor Dooley
2024-04-29 14:47 ` [EXTERNAL] " Witold Sadowski
2024-04-29 21:33 ` Conor Dooley
2024-04-29 22:59 ` Witold Sadowski
2024-04-30 7:58 ` Krzysztof Kozlowski
2024-04-18 17:48 ` Krzysztof Kozlowski
2024-04-29 14:35 ` [EXTERNAL] " Witold Sadowski
2024-04-18 1:13 ` [PATCH v3 3/5] spi: cadence: Add Marvell xSPI IP overlay changes Witold Sadowski
2024-04-18 19:36 ` kernel test robot
2024-04-18 1:13 ` [PATCH v3 4/5] spi: cadence: Allow to read basic xSPI configuration from ACPI Witold Sadowski
2024-04-18 17:51 ` Krzysztof Kozlowski
2024-04-29 14:30 ` [EXTERNAL] " Witold Sadowski
2024-04-30 8:00 ` Krzysztof Kozlowski
2024-05-08 8:04 ` Witold Sadowski
2024-05-08 11:46 ` Mark Brown
2024-05-09 1:07 ` Witold Sadowski
2024-04-18 1:13 ` [PATCH v3 5/5] spi: cadence: Add MRVL overlay xfer operation support Witold Sadowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240329194849.25554-6-wsadowski@marvell.com \
--to=wsadowski@marvell.com \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=pthombar@cadence.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox