183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
210e8bf88SStefan Roese /*
310e8bf88SStefan Roese * Copyright (C) 2012
410e8bf88SStefan Roese * Altera Corporation <www.altera.com>
510e8bf88SStefan Roese */
610e8bf88SStefan Roese
710e8bf88SStefan Roese #include <common.h>
810e8bf88SStefan Roese #include <dm.h>
910e8bf88SStefan Roese #include <fdtdec.h>
1010e8bf88SStefan Roese #include <malloc.h>
1110e8bf88SStefan Roese #include <spi.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
1310e8bf88SStefan Roese #include "cadence_qspi.h"
1410e8bf88SStefan Roese
1510e8bf88SStefan Roese #define CQSPI_STIG_READ 0
1610e8bf88SStefan Roese #define CQSPI_STIG_WRITE 1
1710e8bf88SStefan Roese #define CQSPI_INDIRECT_READ 2
1810e8bf88SStefan Roese #define CQSPI_INDIRECT_WRITE 3
1910e8bf88SStefan Roese
2010e8bf88SStefan Roese DECLARE_GLOBAL_DATA_PTR;
2110e8bf88SStefan Roese
cadence_spi_write_speed(struct udevice * bus,uint hz)2210e8bf88SStefan Roese static int cadence_spi_write_speed(struct udevice *bus, uint hz)
2310e8bf88SStefan Roese {
2410e8bf88SStefan Roese struct cadence_spi_platdata *plat = bus->platdata;
2510e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
2610e8bf88SStefan Roese
2710e8bf88SStefan Roese cadence_qspi_apb_config_baudrate_div(priv->regbase,
2810e8bf88SStefan Roese CONFIG_CQSPI_REF_CLK, hz);
2910e8bf88SStefan Roese
3010e8bf88SStefan Roese /* Reconfigure delay timing if speed is changed. */
3110e8bf88SStefan Roese cadence_qspi_apb_delay(priv->regbase, CONFIG_CQSPI_REF_CLK, hz,
3210e8bf88SStefan Roese plat->tshsl_ns, plat->tsd2d_ns,
3310e8bf88SStefan Roese plat->tchsh_ns, plat->tslch_ns);
3410e8bf88SStefan Roese
3510e8bf88SStefan Roese return 0;
3610e8bf88SStefan Roese }
3710e8bf88SStefan Roese
3810e8bf88SStefan Roese /* Calibration sequence to determine the read data capture delay register */
spi_calibration(struct udevice * bus,uint hz)3998fbd71dSChin Liang See static int spi_calibration(struct udevice *bus, uint hz)
4010e8bf88SStefan Roese {
4110e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
4210e8bf88SStefan Roese void *base = priv->regbase;
4310e8bf88SStefan Roese u8 opcode_rdid = 0x9F;
4410e8bf88SStefan Roese unsigned int idcode = 0, temp = 0;
4510e8bf88SStefan Roese int err = 0, i, range_lo = -1, range_hi = -1;
4610e8bf88SStefan Roese
4710e8bf88SStefan Roese /* start with slowest clock (1 MHz) */
4810e8bf88SStefan Roese cadence_spi_write_speed(bus, 1000000);
4910e8bf88SStefan Roese
5010e8bf88SStefan Roese /* configure the read data capture delay register to 0 */
5110e8bf88SStefan Roese cadence_qspi_apb_readdata_capture(base, 1, 0);
5210e8bf88SStefan Roese
5310e8bf88SStefan Roese /* Enable QSPI */
5410e8bf88SStefan Roese cadence_qspi_apb_controller_enable(base);
5510e8bf88SStefan Roese
5610e8bf88SStefan Roese /* read the ID which will be our golden value */
5710e8bf88SStefan Roese err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
5810e8bf88SStefan Roese 3, (u8 *)&idcode);
5910e8bf88SStefan Roese if (err) {
6010e8bf88SStefan Roese puts("SF: Calibration failed (read)\n");
6110e8bf88SStefan Roese return err;
6210e8bf88SStefan Roese }
6310e8bf88SStefan Roese
6410e8bf88SStefan Roese /* use back the intended clock and find low range */
6598fbd71dSChin Liang See cadence_spi_write_speed(bus, hz);
6610e8bf88SStefan Roese for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) {
6710e8bf88SStefan Roese /* Disable QSPI */
6810e8bf88SStefan Roese cadence_qspi_apb_controller_disable(base);
6910e8bf88SStefan Roese
7010e8bf88SStefan Roese /* reconfigure the read data capture delay register */
7110e8bf88SStefan Roese cadence_qspi_apb_readdata_capture(base, 1, i);
7210e8bf88SStefan Roese
7310e8bf88SStefan Roese /* Enable back QSPI */
7410e8bf88SStefan Roese cadence_qspi_apb_controller_enable(base);
7510e8bf88SStefan Roese
7610e8bf88SStefan Roese /* issue a RDID to get the ID value */
7710e8bf88SStefan Roese err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
7810e8bf88SStefan Roese 3, (u8 *)&temp);
7910e8bf88SStefan Roese if (err) {
8010e8bf88SStefan Roese puts("SF: Calibration failed (read)\n");
8110e8bf88SStefan Roese return err;
8210e8bf88SStefan Roese }
8310e8bf88SStefan Roese
8410e8bf88SStefan Roese /* search for range lo */
8510e8bf88SStefan Roese if (range_lo == -1 && temp == idcode) {
8610e8bf88SStefan Roese range_lo = i;
8710e8bf88SStefan Roese continue;
8810e8bf88SStefan Roese }
8910e8bf88SStefan Roese
9010e8bf88SStefan Roese /* search for range hi */
9110e8bf88SStefan Roese if (range_lo != -1 && temp != idcode) {
9210e8bf88SStefan Roese range_hi = i - 1;
9310e8bf88SStefan Roese break;
9410e8bf88SStefan Roese }
9510e8bf88SStefan Roese range_hi = i;
9610e8bf88SStefan Roese }
9710e8bf88SStefan Roese
9810e8bf88SStefan Roese if (range_lo == -1) {
9910e8bf88SStefan Roese puts("SF: Calibration failed (low range)\n");
10010e8bf88SStefan Roese return err;
10110e8bf88SStefan Roese }
10210e8bf88SStefan Roese
10310e8bf88SStefan Roese /* Disable QSPI for subsequent initialization */
10410e8bf88SStefan Roese cadence_qspi_apb_controller_disable(base);
10510e8bf88SStefan Roese
10610e8bf88SStefan Roese /* configure the final value for read data capture delay register */
10710e8bf88SStefan Roese cadence_qspi_apb_readdata_capture(base, 1, (range_hi + range_lo) / 2);
10810e8bf88SStefan Roese debug("SF: Read data capture delay calibrated to %i (%i - %i)\n",
10910e8bf88SStefan Roese (range_hi + range_lo) / 2, range_lo, range_hi);
11010e8bf88SStefan Roese
11110e8bf88SStefan Roese /* just to ensure we do once only when speed or chip select change */
11298fbd71dSChin Liang See priv->qspi_calibrated_hz = hz;
11310e8bf88SStefan Roese priv->qspi_calibrated_cs = spi_chip_select(bus);
11410e8bf88SStefan Roese
11510e8bf88SStefan Roese return 0;
11610e8bf88SStefan Roese }
11710e8bf88SStefan Roese
cadence_spi_set_speed(struct udevice * bus,uint hz)11810e8bf88SStefan Roese static int cadence_spi_set_speed(struct udevice *bus, uint hz)
11910e8bf88SStefan Roese {
12010e8bf88SStefan Roese struct cadence_spi_platdata *plat = bus->platdata;
12110e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
12210e8bf88SStefan Roese int err;
12310e8bf88SStefan Roese
1244e609b6cSChin Liang See if (hz > plat->max_hz)
1254e609b6cSChin Liang See hz = plat->max_hz;
1264e609b6cSChin Liang See
12710e8bf88SStefan Roese /* Disable QSPI */
12810e8bf88SStefan Roese cadence_qspi_apb_controller_disable(priv->regbase);
12910e8bf88SStefan Roese
13098fbd71dSChin Liang See /*
13198fbd71dSChin Liang See * Calibration required for different current SCLK speed, requested
13298fbd71dSChin Liang See * SCLK speed or chip select
13398fbd71dSChin Liang See */
13498fbd71dSChin Liang See if (priv->previous_hz != hz ||
13598fbd71dSChin Liang See priv->qspi_calibrated_hz != hz ||
13610e8bf88SStefan Roese priv->qspi_calibrated_cs != spi_chip_select(bus)) {
13798fbd71dSChin Liang See err = spi_calibration(bus, hz);
13810e8bf88SStefan Roese if (err)
13910e8bf88SStefan Roese return err;
14098fbd71dSChin Liang See
14198fbd71dSChin Liang See /* prevent calibration run when same as previous request */
14298fbd71dSChin Liang See priv->previous_hz = hz;
14310e8bf88SStefan Roese }
14410e8bf88SStefan Roese
14510e8bf88SStefan Roese /* Enable QSPI */
14610e8bf88SStefan Roese cadence_qspi_apb_controller_enable(priv->regbase);
14710e8bf88SStefan Roese
14810e8bf88SStefan Roese debug("%s: speed=%d\n", __func__, hz);
14910e8bf88SStefan Roese
15010e8bf88SStefan Roese return 0;
15110e8bf88SStefan Roese }
15210e8bf88SStefan Roese
cadence_spi_probe(struct udevice * bus)15310e8bf88SStefan Roese static int cadence_spi_probe(struct udevice *bus)
15410e8bf88SStefan Roese {
15510e8bf88SStefan Roese struct cadence_spi_platdata *plat = bus->platdata;
15610e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
15710e8bf88SStefan Roese
15810e8bf88SStefan Roese priv->regbase = plat->regbase;
15910e8bf88SStefan Roese priv->ahbbase = plat->ahbbase;
16010e8bf88SStefan Roese
16110e8bf88SStefan Roese if (!priv->qspi_is_init) {
16210e8bf88SStefan Roese cadence_qspi_apb_controller_init(plat);
16310e8bf88SStefan Roese priv->qspi_is_init = 1;
16410e8bf88SStefan Roese }
16510e8bf88SStefan Roese
16610e8bf88SStefan Roese return 0;
16710e8bf88SStefan Roese }
16810e8bf88SStefan Roese
cadence_spi_set_mode(struct udevice * bus,uint mode)16910e8bf88SStefan Roese static int cadence_spi_set_mode(struct udevice *bus, uint mode)
17010e8bf88SStefan Roese {
17110e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
17210e8bf88SStefan Roese
17310e8bf88SStefan Roese /* Disable QSPI */
17410e8bf88SStefan Roese cadence_qspi_apb_controller_disable(priv->regbase);
17510e8bf88SStefan Roese
17610e8bf88SStefan Roese /* Set SPI mode */
1777d403f28SPhil Edworthy cadence_qspi_apb_set_clk_mode(priv->regbase, mode);
17810e8bf88SStefan Roese
17910e8bf88SStefan Roese /* Enable QSPI */
18010e8bf88SStefan Roese cadence_qspi_apb_controller_enable(priv->regbase);
18110e8bf88SStefan Roese
18210e8bf88SStefan Roese return 0;
18310e8bf88SStefan Roese }
18410e8bf88SStefan Roese
cadence_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)18510e8bf88SStefan Roese static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
18610e8bf88SStefan Roese const void *dout, void *din, unsigned long flags)
18710e8bf88SStefan Roese {
18810e8bf88SStefan Roese struct udevice *bus = dev->parent;
18910e8bf88SStefan Roese struct cadence_spi_platdata *plat = bus->platdata;
19010e8bf88SStefan Roese struct cadence_spi_priv *priv = dev_get_priv(bus);
1912372e14fSVignesh R struct dm_spi_slave_platdata *dm_plat = dev_get_parent_platdata(dev);
19210e8bf88SStefan Roese void *base = priv->regbase;
19310e8bf88SStefan Roese u8 *cmd_buf = priv->cmd_buf;
19410e8bf88SStefan Roese size_t data_bytes;
19510e8bf88SStefan Roese int err = 0;
19610e8bf88SStefan Roese u32 mode = CQSPI_STIG_WRITE;
19710e8bf88SStefan Roese
19810e8bf88SStefan Roese if (flags & SPI_XFER_BEGIN) {
19910e8bf88SStefan Roese /* copy command to local buffer */
20010e8bf88SStefan Roese priv->cmd_len = bitlen / 8;
20110e8bf88SStefan Roese memcpy(cmd_buf, dout, priv->cmd_len);
20210e8bf88SStefan Roese }
20310e8bf88SStefan Roese
20410e8bf88SStefan Roese if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
20510e8bf88SStefan Roese /* if start and end bit are set, the data bytes is 0. */
20610e8bf88SStefan Roese data_bytes = 0;
20710e8bf88SStefan Roese } else {
20810e8bf88SStefan Roese data_bytes = bitlen / 8;
20910e8bf88SStefan Roese }
2109bd39dd8SLey Foon Tan debug("%s: len=%zu [bytes]\n", __func__, data_bytes);
21110e8bf88SStefan Roese
21210e8bf88SStefan Roese /* Set Chip select */
21310e8bf88SStefan Roese cadence_qspi_apb_chipselect(base, spi_chip_select(dev),
21415a70a5dSJason Rush plat->is_decoded_cs);
21510e8bf88SStefan Roese
21610e8bf88SStefan Roese if ((flags & SPI_XFER_END) || (flags == 0)) {
21710e8bf88SStefan Roese if (priv->cmd_len == 0) {
21810e8bf88SStefan Roese printf("QSPI: Error, command is empty.\n");
21910e8bf88SStefan Roese return -1;
22010e8bf88SStefan Roese }
22110e8bf88SStefan Roese
22210e8bf88SStefan Roese if (din && data_bytes) {
22310e8bf88SStefan Roese /* read */
22410e8bf88SStefan Roese /* Use STIG if no address. */
22510e8bf88SStefan Roese if (!CQSPI_IS_ADDR(priv->cmd_len))
22610e8bf88SStefan Roese mode = CQSPI_STIG_READ;
22710e8bf88SStefan Roese else
22810e8bf88SStefan Roese mode = CQSPI_INDIRECT_READ;
22910e8bf88SStefan Roese } else if (dout && !(flags & SPI_XFER_BEGIN)) {
23010e8bf88SStefan Roese /* write */
23110e8bf88SStefan Roese if (!CQSPI_IS_ADDR(priv->cmd_len))
23210e8bf88SStefan Roese mode = CQSPI_STIG_WRITE;
23310e8bf88SStefan Roese else
23410e8bf88SStefan Roese mode = CQSPI_INDIRECT_WRITE;
23510e8bf88SStefan Roese }
23610e8bf88SStefan Roese
23710e8bf88SStefan Roese switch (mode) {
23810e8bf88SStefan Roese case CQSPI_STIG_READ:
23910e8bf88SStefan Roese err = cadence_qspi_apb_command_read(
24010e8bf88SStefan Roese base, priv->cmd_len, cmd_buf,
24110e8bf88SStefan Roese data_bytes, din);
24210e8bf88SStefan Roese
24310e8bf88SStefan Roese break;
24410e8bf88SStefan Roese case CQSPI_STIG_WRITE:
24510e8bf88SStefan Roese err = cadence_qspi_apb_command_write(base,
24610e8bf88SStefan Roese priv->cmd_len, cmd_buf,
24710e8bf88SStefan Roese data_bytes, dout);
24810e8bf88SStefan Roese break;
24910e8bf88SStefan Roese case CQSPI_INDIRECT_READ:
25010e8bf88SStefan Roese err = cadence_qspi_apb_indirect_read_setup(plat,
25108fe9c29SJagan Teki priv->cmd_len, dm_plat->mode, cmd_buf);
25210e8bf88SStefan Roese if (!err) {
25310e8bf88SStefan Roese err = cadence_qspi_apb_indirect_read_execute
25410e8bf88SStefan Roese (plat, data_bytes, din);
25510e8bf88SStefan Roese }
25610e8bf88SStefan Roese break;
25710e8bf88SStefan Roese case CQSPI_INDIRECT_WRITE:
25810e8bf88SStefan Roese err = cadence_qspi_apb_indirect_write_setup
25910e8bf88SStefan Roese (plat, priv->cmd_len, cmd_buf);
26010e8bf88SStefan Roese if (!err) {
26110e8bf88SStefan Roese err = cadence_qspi_apb_indirect_write_execute
26210e8bf88SStefan Roese (plat, data_bytes, dout);
26310e8bf88SStefan Roese }
26410e8bf88SStefan Roese break;
26510e8bf88SStefan Roese default:
26610e8bf88SStefan Roese err = -1;
26710e8bf88SStefan Roese break;
26810e8bf88SStefan Roese }
26910e8bf88SStefan Roese
27010e8bf88SStefan Roese if (flags & SPI_XFER_END) {
27110e8bf88SStefan Roese /* clear command buffer */
27210e8bf88SStefan Roese memset(cmd_buf, 0, sizeof(priv->cmd_buf));
27310e8bf88SStefan Roese priv->cmd_len = 0;
27410e8bf88SStefan Roese }
27510e8bf88SStefan Roese }
27610e8bf88SStefan Roese
27710e8bf88SStefan Roese return err;
27810e8bf88SStefan Roese }
27910e8bf88SStefan Roese
cadence_spi_ofdata_to_platdata(struct udevice * bus)28010e8bf88SStefan Roese static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
28110e8bf88SStefan Roese {
28210e8bf88SStefan Roese struct cadence_spi_platdata *plat = bus->platdata;
28310e8bf88SStefan Roese const void *blob = gd->fdt_blob;
284e160f7d4SSimon Glass int node = dev_of_offset(bus);
28510e8bf88SStefan Roese int subnode;
28610e8bf88SStefan Roese
2876c353674SLey Foon Tan plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
2886c353674SLey Foon Tan plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1);
28915a70a5dSJason Rush plat->is_decoded_cs = fdtdec_get_bool(blob, node, "cdns,is-decoded-cs");
29015a70a5dSJason Rush plat->fifo_depth = fdtdec_get_uint(blob, node, "cdns,fifo-depth", 128);
29115a70a5dSJason Rush plat->fifo_width = fdtdec_get_uint(blob, node, "cdns,fifo-width", 4);
29215a70a5dSJason Rush plat->trigger_address = fdtdec_get_uint(blob, node,
29315a70a5dSJason Rush "cdns,trigger-address", 0);
29410e8bf88SStefan Roese
29510e8bf88SStefan Roese /* All other paramters are embedded in the child node */
29610e8bf88SStefan Roese subnode = fdt_first_subnode(blob, node);
2971dc7d00fSAxel Lin if (subnode < 0) {
29810e8bf88SStefan Roese printf("Error: subnode with SPI flash config missing!\n");
29910e8bf88SStefan Roese return -ENODEV;
30010e8bf88SStefan Roese }
30110e8bf88SStefan Roese
302040f4ba7SChin Liang See /* Use 500 KHz as a suitable default */
303040f4ba7SChin Liang See plat->max_hz = fdtdec_get_uint(blob, subnode, "spi-max-frequency",
304040f4ba7SChin Liang See 500000);
305040f4ba7SChin Liang See
30610e8bf88SStefan Roese /* Read other parameters from DT */
30715a70a5dSJason Rush plat->page_size = fdtdec_get_uint(blob, subnode, "page-size", 256);
30815a70a5dSJason Rush plat->block_size = fdtdec_get_uint(blob, subnode, "block-size", 16);
30915a70a5dSJason Rush plat->tshsl_ns = fdtdec_get_uint(blob, subnode, "cdns,tshsl-ns", 200);
31015a70a5dSJason Rush plat->tsd2d_ns = fdtdec_get_uint(blob, subnode, "cdns,tsd2d-ns", 255);
31115a70a5dSJason Rush plat->tchsh_ns = fdtdec_get_uint(blob, subnode, "cdns,tchsh-ns", 20);
31215a70a5dSJason Rush plat->tslch_ns = fdtdec_get_uint(blob, subnode, "cdns,tslch-ns", 20);
31310e8bf88SStefan Roese
31410e8bf88SStefan Roese debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n",
31510e8bf88SStefan Roese __func__, plat->regbase, plat->ahbbase, plat->max_hz,
31610e8bf88SStefan Roese plat->page_size);
31710e8bf88SStefan Roese
31810e8bf88SStefan Roese return 0;
31910e8bf88SStefan Roese }
32010e8bf88SStefan Roese
32110e8bf88SStefan Roese static const struct dm_spi_ops cadence_spi_ops = {
32210e8bf88SStefan Roese .xfer = cadence_spi_xfer,
32310e8bf88SStefan Roese .set_speed = cadence_spi_set_speed,
32410e8bf88SStefan Roese .set_mode = cadence_spi_set_mode,
32510e8bf88SStefan Roese /*
32610e8bf88SStefan Roese * cs_info is not needed, since we require all chip selects to be
32710e8bf88SStefan Roese * in the device tree explicitly
32810e8bf88SStefan Roese */
32910e8bf88SStefan Roese };
33010e8bf88SStefan Roese
33110e8bf88SStefan Roese static const struct udevice_id cadence_spi_ids[] = {
332*2a3a9993SSimon Goldschmidt { .compatible = "cdns,qspi-nor" },
33310e8bf88SStefan Roese { }
33410e8bf88SStefan Roese };
33510e8bf88SStefan Roese
33610e8bf88SStefan Roese U_BOOT_DRIVER(cadence_spi) = {
33710e8bf88SStefan Roese .name = "cadence_spi",
33810e8bf88SStefan Roese .id = UCLASS_SPI,
33910e8bf88SStefan Roese .of_match = cadence_spi_ids,
34010e8bf88SStefan Roese .ops = &cadence_spi_ops,
34110e8bf88SStefan Roese .ofdata_to_platdata = cadence_spi_ofdata_to_platdata,
34210e8bf88SStefan Roese .platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata),
34310e8bf88SStefan Roese .priv_auto_alloc_size = sizeof(struct cadence_spi_priv),
34410e8bf88SStefan Roese .probe = cadence_spi_probe,
34510e8bf88SStefan Roese };
346