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