drivers/spi/spi-facebook-u2s.c (601 lines of code) (raw):

// SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2020 Facebook Inc. #include <linux/err.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/kref.h> #include <linux/ioctl.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/mtd/spi-nor.h> #include <linux/mutex.h> #include <linux/spi/spi.h> #include <linux/uaccess.h> #include <linux/usb.h> #define FBUS_NUM_SPI_BUSES 8 #define USB_BULK_MAX_SIZE 512 /* * max_payload_size: USB_BULK_MAX_SIZE - 2_byte_type - 2_byte_length - * 4_byte_address. */ #define TLV_PAYLOAD_MAX_SIZE (USB_BULK_MAX_SIZE - 8) /* * Supported TLV types. */ #define TLV_TYPE_READ_RES 0x8200 #define TLV_TYPE_READ_REQ 0x0200 #define TLV_TYPE_WRITE 0x0100 /* * USPI Controller register/memory base address and offset. */ #define USPI_CSR_REG_BASE 0x0 #define USPI_CSR_REG_SIZE 0x80 #define USPI_DATA_BUF_BASE 0x2000 #define USPI_MOSI_BUF_SIZE 0x200 /* 512 bytes */ #define USPI_MISO_BUF_SIZE 0x200 /* 512 bytes */ #define USPI_DATA_BUF_SIZE (USPI_MOSI_BUF_SIZE + USPI_MISO_BUF_SIZE) /* * Bit fields in SPI Timing Profile Register. */ #define USPI_SAMPLE_DELAY_OFFSET 12 #define USPI_CLK_25MHZ 1 #define USPI_CLK_50MHZ 0 /* * Bit fields in SPI Descriptor Register. */ #define USPI_XFER_START_HW BIT(31) #define USPI_CONTINUOUS_CS BIT(29) #define USPI_XFER_LEN_OFFSET 8 #define USPI_XFER_LEN_MASK 0x1FF /* * Bit fields in SPI Status Register. */ #define USPI_STAT_XFER_DONE BIT(0) /* * Default timeout settings. */ #define USB_BULK_TIMEOUT_MS 2000 #define USPI_XFER_DELAY_US 10 #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif /* * usb-bridge chardev ioctl commands */ #define UBRG_CMD_MEM_IO 0x101 /* * Structure to pass usb memory read/write command and data between user * and kernel space. */ struct ubrg_ioc_xfer { u32 addr; void *buf; unsigned int len; unsigned int flags; #define UMEM_IOF_WRITE 0x1 }; /* * All the USB Bulk transactions should follow "fbus_tlv" format. */ struct fbus_tlv { u16 length; u16 type; u32 address; u8 data_buf[TLV_PAYLOAD_MAX_SIZE]; }; /* * Note: "tlv->length" doesn't cover the 4 byte header (length + type): * it defines the size of "data_buf" plus 4-byte "address". As a result: * * usb_pkt_size = tlv->length + sizeof(tlv->length) + sizeof(tlv->type) */ #define TLV_HDR_SIZE 4 /* type + length */ #define TLV_PKT_MIN_SIZE 8 /* type + length + address */ #define TLV_PKT_SIZE(_tlv) ((_tlv)->length + TLV_HDR_SIZE) #define TLV_PAYLOAD_SIZE(_tlv) ((_tlv)->length - sizeof((_tlv)->address)) /* * SPI Master Control/Status Registers. */ struct fbus_spi_csr { u32 timing; u32 ctrl; u32 desc; u32 status; }; /* * this spi_flow_ctrl is used to control part of the fpga tlv receiving * process because fpga has not yet separately supported all types of tlv * transmissions, BMC must send specific TLVs to fpga in sequence. * The fpga's multi-threaded is not complete, it just looks similar to * multi-threaded transmission. The lock should be dropped when multi-thread * support is implemented/fixed in fpga side. */ struct mutex spi_flow_ctrl; /* * Structure for a SPI master. */ struct fbus_spi_master { u32 spi_id; struct spi_master *master; /* * Only 1 slave device (flash) at present. */ struct spi_device *slave; /* * Control/Status registers. */ struct fbus_spi_csr reg_csr; /* * Register base address, initialized at probe time. */ unsigned long reg_csr_base; unsigned long reg_mosi_base; unsigned long reg_miso_base; /* * We cannot determine read length when read-related flash ops * are received, so let's cache the read op and combine it with * following "rx" operation. */ struct { u8 op; u8 addr[3]; } read_op_cache; unsigned int read_op_size; }; /* * List of endpoints (besides Control Endpoint #0) supported by the * USB-SPI Adapter. */ enum { USPI_BULK_IN = 0, USPI_BULK_OUT, USPI_EP_MAX, }; /* * Structure for the entire FPGA device (usb-spi bridge). */ static struct { struct usb_device *usb_dev; struct usb_interface *usb_intf; /* * "xfer_lock" is required to serilize usb device memory read and * write requests. */ struct mutex xfer_lock; u8 ep_list[USPI_EP_MAX]; #define BULK_IN_PIPE usb_rcvbulkpipe(fbus_bridge.usb_dev, \ fbus_bridge.ep_list[USPI_BULK_IN]) #define BULK_OUT_PIPE usb_sndbulkpipe(fbus_bridge.usb_dev, \ fbus_bridge.ep_list[USPI_BULK_OUT]) struct fbus_spi_master *spi_buses[FBUS_NUM_SPI_BUSES]; struct miscdevice miscdev; } fbus_bridge; static int fbus_spi_setup(struct spi_device *slave) { /* Nothing needed as of now */ return 0; } static void fbus_spi_set_cs(struct spi_device *slave, bool level) { /* Nothing needed as of now */ } /* * Build a TLV-format USB packet. */ static int fbus_tlv_init(struct fbus_tlv *tlv, u16 type, u32 address, const void *data_buf, unsigned int data_len) { if (data_len > sizeof(tlv->data_buf)) return -E2BIG; tlv->type = type; tlv->address = address; if (type == TLV_TYPE_WRITE) { memcpy(tlv->data_buf, data_buf, data_len); tlv->length = sizeof(tlv->address) + data_len; } else if (type == TLV_TYPE_READ_REQ) { /* * For read request, request length is specified by 4-byte * integer (u32). */ u32 req_len = data_len; req_len += 4; /* include 4-byte address */ memcpy(tlv->data_buf, &req_len, sizeof(req_len)); tlv->length = sizeof(tlv->address) + sizeof(req_len); } else { return -EINVAL; } return 0; } static int udev_mem_write(u32 addr, const void *buf, unsigned int size) { struct fbus_tlv *tlv; int ret, req_len, actual_len; tlv = kmalloc(sizeof(*tlv), GFP_KERNEL); if (tlv == NULL) return -ENOMEM; ret = fbus_tlv_init(tlv, TLV_TYPE_WRITE, addr, buf, size); if (ret < 0) goto exit; mutex_lock(&fbus_bridge.xfer_lock); req_len = TLV_PKT_SIZE(tlv); ret = usb_bulk_msg(fbus_bridge.usb_dev, BULK_OUT_PIPE, tlv, req_len, &actual_len, USB_BULK_TIMEOUT_MS); if ((ret == 0) && (actual_len < req_len)) { dev_err(&fbus_bridge.usb_intf->dev, "udevmem short write (type=0x%x, addr=0x%x): " "expect %u, actual %d\n", TLV_TYPE_WRITE, addr, req_len, actual_len); ret = -EBADMSG; } mutex_unlock(&fbus_bridge.xfer_lock); exit: kfree(tlv); return ret; } static int udev_mem_read(u32 addr, void *buf, unsigned int size) { struct fbus_tlv *tlv; int ret, req_len, actual_len; tlv = kmalloc(sizeof(*tlv), GFP_KERNEL); if (tlv == NULL) return -ENOMEM; /* * Send read request to the FPGA. */ ret = fbus_tlv_init(tlv, TLV_TYPE_READ_REQ, addr, NULL, size); if (ret < 0) goto exit_mem; mutex_lock(&fbus_bridge.xfer_lock); req_len = TLV_PKT_SIZE(tlv); ret = usb_bulk_msg(fbus_bridge.usb_dev, BULK_OUT_PIPE, tlv, req_len, &actual_len, USB_BULK_TIMEOUT_MS); if (ret < 0) { goto exit_lock; } else if (actual_len < req_len) { dev_err(&fbus_bridge.usb_intf->dev, "udevmem short write (type=0x%x, addr=0x%x): " "expect %u, actual %d\n", TLV_TYPE_READ_REQ, addr, req_len, actual_len); ret = -EBADMSG; goto exit_lock; } /* * Then read from bulk-in pipe. */ memset(tlv, 0, TLV_PKT_MIN_SIZE); /* reset tlv head only. */ req_len = TLV_PKT_MIN_SIZE + size; ret = usb_bulk_msg(fbus_bridge.usb_dev, BULK_IN_PIPE, tlv, req_len, &actual_len, USB_BULK_TIMEOUT_MS); if (ret < 0) { goto exit_lock; } else if (actual_len < req_len) { dev_err(&fbus_bridge.usb_intf->dev, "udevmem short read (addr=0x%x): " "expect %u, actual %d\n", addr, req_len, actual_len); ret = -EBADMSG; goto exit_lock; } memcpy(buf, tlv->data_buf, size); exit_lock: mutex_unlock(&fbus_bridge.xfer_lock); exit_mem: kfree(tlv); return ret; } static void fbus_spicsr_set_xfer_len(struct fbus_spi_master *uspi, unsigned int xfer_len) { u32 mask = (USPI_XFER_LEN_MASK << USPI_XFER_LEN_OFFSET); uspi->reg_csr.desc &= ~mask; uspi->reg_csr.desc |= ((u32)(xfer_len & USPI_XFER_LEN_MASK) << USPI_XFER_LEN_OFFSET); } static int fbus_spi_xfer_start_hw(struct fbus_spi_master *uspi, unsigned int xfer_len, int continue_cs) { /* * Update Control/Status registers. */ fbus_spicsr_set_xfer_len(uspi, xfer_len); uspi->reg_csr.desc |= USPI_XFER_START_HW; if (continue_cs) uspi->reg_csr.desc |= USPI_CONTINUOUS_CS; else uspi->reg_csr.desc &= ~USPI_CONTINUOUS_CS; /* * Send the updated CSR register values to the device. */ return udev_mem_write(uspi->reg_csr_base, &uspi->reg_csr, sizeof(uspi->reg_csr)); } static int fbus_spi_mosi_write(struct fbus_spi_master *uspi, const void *buf, unsigned int len) { return udev_mem_write(uspi->reg_mosi_base, buf, len); } static int fbus_spi_csr_read(struct fbus_spi_master *uspi, void *buf, unsigned int len) { return udev_mem_read(uspi->reg_csr_base, buf, len); } static int fbus_spi_miso_read(struct fbus_spi_master *uspi, void *buf, unsigned int len) { return udev_mem_read(uspi->reg_miso_base, buf, len); } /* * More flash read commands from flashrom spi.h. */ /* Some Atmel AT25F* models have bit 3 as don't care bit in commands */ #define AT25F_RDID 0x15 /* 0x15 or 0x1d */ /* Read Electronic Manufacturer Signature */ #define JEDEC_REMS 0x90 /* Read Electronic Signature */ #define JEDEC_RES 0xab /* Some ST M95X model */ #define ST_M95_RDID 0x83 static bool fbus_spi_is_read_op(u8 flash_op) { bool ret = false; switch (flash_op) { case SPINOR_OP_RDSR: case SPINOR_OP_RDSR2: case SPINOR_OP_READ: case SPINOR_OP_READ_FAST: case SPINOR_OP_RDID: case SPINOR_OP_RDSFDP: case SPINOR_OP_RDCR: case SPINOR_OP_RDFSR: case SPINOR_OP_RDEAR: ret = true; break; case AT25F_RDID: case ST_M95_RDID: case JEDEC_REMS: case JEDEC_RES: ret = true; break; } return ret; } static int fbus_spi_cache_flash_op(struct fbus_spi_master *uspi, struct spi_transfer *xfer) { unsigned int len; u8 flash_op = ((u8*)xfer->tx_buf)[0]; if (xfer->len <= sizeof(uspi->read_op_cache)) { len = xfer->len; } else { len = sizeof(uspi->read_op_cache); } memcpy(&uspi->read_op_cache, xfer->tx_buf, len); if (fbus_spi_is_read_op(flash_op)) uspi->read_op_size = len; return 0; } static int fbus_spi_xfer_tx(struct fbus_spi_master *uspi, struct spi_transfer *xfer) { int ret; /* * Step 1: upload command/data to mosi buffer. */ ret = fbus_spi_mosi_write(uspi, xfer->tx_buf, xfer->len); if (ret < 0) { dev_err(&uspi->master->dev, "failed to send %d bytes to MOSI, error=%d\n", xfer->len, ret); return ret; } /* * Step 2: update control register to start transaction. */ ret = fbus_spi_xfer_start_hw(uspi, xfer->len, 0); if (ret < 0) { dev_err(&uspi->master->dev, "failed to start spi hardware, error=%d\n", ret); return ret; } /* add 40us delay for spi write*/ udelay(4 * USPI_XFER_DELAY_US); return 0; } static int fbus_spi_xfer_rx_prepare_op(struct fbus_spi_master *uspi, struct spi_transfer *xfer) { int ret; /* * The read command should be cached, and let's verify it. */ if (uspi->read_op_size == 0) { dev_err(&uspi->master->dev, "no read_op command cached (len=%d): last op 0x%02x\n", xfer->len, uspi->read_op_cache.op); return -EINVAL; } /* * fill mosi buffer with flash op */ ret = fbus_spi_mosi_write(uspi, &uspi->read_op_cache, uspi->read_op_size); if (ret < 0) dev_err(&uspi->master->dev, "failed to send read_op 0x%02x (len=%u) to MOSI: " "error=%d\n", uspi->read_op_cache.op, uspi->read_op_size, ret); return ret; } static int fbus_spi_xfer_is_ready(struct fbus_spi_master *uspi) { int ret; int retry = 2; struct fbus_spi_csr csr; while (retry >= 0) { ret = fbus_spi_csr_read(uspi, &csr, sizeof(csr)); if (ret < 0) return ret; if (csr.status & USPI_STAT_XFER_DONE) return 0; /* transfer completed. */ retry--; udelay(USPI_XFER_DELAY_US); } return -EBUSY; } static int fbus_spi_xfer_single_rx(struct fbus_spi_master *uspi, struct spi_transfer *xfer, unsigned int op_size, unsigned int rx_offset) { int ret, continue_cs; u8 *rx_buf, *recv_buf; unsigned int nleft, nrequest, payload_max; nleft = xfer->len - rx_offset; payload_max = TLV_PAYLOAD_MAX_SIZE - op_size; nrequest = MIN(nleft, payload_max); continue_cs = ((nrequest == nleft) ? 0 : 1); ret = fbus_spi_xfer_start_hw(uspi, op_size + nrequest, continue_cs); if (ret < 0) { dev_err(&uspi->master->dev, "failed to start spi hardware, error=%d\n", ret); return ret; } ret = fbus_spi_xfer_is_ready(uspi); if (ret < 0) { dev_err(&uspi->master->dev, "failed to check transfer status, error=%d\n", ret); return ret; } recv_buf = kmalloc(nrequest + op_size, GFP_KERNEL); if (recv_buf == NULL) return -ENOMEM; ret = fbus_spi_miso_read(uspi, recv_buf, nrequest + op_size); if (ret < 0) { dev_err(&uspi->master->dev, "failed to read data from MISO, error=%d\n", ret); } else { rx_buf = xfer->rx_buf; memcpy(&rx_buf[rx_offset], &recv_buf[op_size], nrequest); } kfree(recv_buf); return (ret < 0 ? ret : nrequest); } static int fbus_spi_xfer_rx(struct fbus_spi_master *uspi, struct spi_transfer *xfer) { int ret; unsigned int op_size; unsigned int ndata = 0; ret = fbus_spi_xfer_rx_prepare_op(uspi, xfer); if (ret < 0) return ret; op_size = uspi->read_op_size; uspi->read_op_size = 0; while (ndata < xfer->len) { mutex_lock(&spi_flow_ctrl); ret = fbus_spi_xfer_single_rx(uspi, xfer, op_size, ndata); mutex_unlock(&spi_flow_ctrl); if (ret < 0) return ret; /* * flash op is only needed for the first spi transaction, * so let's set it to 0. */ op_size = 0; ndata += ret; } return 0; } static int fbus_spi_xfer_one(struct spi_master *master, struct spi_device *slave, struct spi_transfer *xfer) { int ret = 0; struct fbus_spi_master *uspi = spi_master_get_devdata(master); if (xfer->tx_buf != NULL) { u8 flash_op = ((u8*)(xfer->tx_buf))[0]; /* * We cache the read command and combine it with following "rx" * request. */ fbus_spi_cache_flash_op(uspi, xfer); if (!fbus_spi_is_read_op(flash_op)) { mutex_lock(&spi_flow_ctrl); ret = fbus_spi_xfer_tx(uspi, xfer); mutex_unlock(&spi_flow_ctrl); if (ret < 0) { return ret; } } } if (xfer->rx_buf != NULL) ret = fbus_spi_xfer_rx(uspi, xfer); return ret; } static long ubrg_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; u8 *xfer_buf; struct ubrg_ioc_xfer ioc_xfer; switch (cmd) { case UBRG_CMD_MEM_IO: if (copy_from_user(&ioc_xfer, (struct ubrg_ioc_xfer*)arg, sizeof(ioc_xfer))) return -EFAULT; if ((ioc_xfer.buf == NULL) || (ioc_xfer.len > TLV_PAYLOAD_MAX_SIZE)) return -EINVAL; xfer_buf = kmalloc(ioc_xfer.len, GFP_KERNEL); if (xfer_buf == NULL) return -ENOMEM; if (ioc_xfer.flags & UMEM_IOF_WRITE) { if (copy_from_user(xfer_buf, ioc_xfer.buf, ioc_xfer.len)) { ret = -EFAULT; goto io_exit; } ret = udev_mem_write(ioc_xfer.addr, xfer_buf, ioc_xfer.len); } else { ret = udev_mem_read(ioc_xfer.addr, xfer_buf, ioc_xfer.len); if (ret < 0) goto io_exit; if (copy_to_user(ioc_xfer.buf, xfer_buf, ioc_xfer.len)) ret = -EFAULT; } io_exit: kfree(xfer_buf); break; default: return -ENOTTY; } /* switch */ return ret; } static const struct file_operations ubrg_cdev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .unlocked_ioctl = ubrg_cdev_ioctl, }; static void misc_dev_destroy(struct miscdevice *miscdev) { misc_deregister(miscdev); kfree(miscdev->name); } static int misc_dev_init(struct device *parent, struct miscdevice *miscdev) { int ret; miscdev->parent = parent; miscdev->fops = &ubrg_cdev_fops; miscdev->minor = MISC_DYNAMIC_MINOR; miscdev->name = kasprintf(GFP_KERNEL, "usb-fpga"); if (miscdev->name == NULL) return -ENOMEM; ret = misc_register(miscdev); if (ret < 0) kfree(miscdev->name); return ret; } static int fbus_spi_master_init(u32 id) { int ret; struct spi_master *master; struct fbus_spi_master *uspi; struct device *parent = &fbus_bridge.usb_intf->dev; struct spi_board_info slave_info = { .modalias = "spidev", .max_speed_hz = 25000000, .chip_select = 0, }; master = spi_alloc_master(parent, sizeof(struct fbus_spi_master)); if (master == NULL) { dev_err(parent, "failed to allocate spi_master[%u]\n", id); return -ENOMEM; } master->num_chipselect = 1; master->setup = fbus_spi_setup; master->set_cs = fbus_spi_set_cs; master->transfer_one = fbus_spi_xfer_one; uspi = spi_master_get_devdata(master); uspi->spi_id = id; uspi->master = master; uspi->reg_csr_base = USPI_CSR_REG_BASE + (USPI_CSR_REG_SIZE * id); uspi->reg_mosi_base = USPI_DATA_BUF_BASE + (USPI_DATA_BUF_SIZE * id); uspi->reg_miso_base = uspi->reg_mosi_base + USPI_MOSI_BUF_SIZE; /* * Initialize Control/Status registers. */ uspi->reg_csr.timing = (USPI_CLK_50MHZ | (2 << USPI_SAMPLE_DELAY_OFFSET)); ret = spi_register_master(master); if (ret) { dev_err(parent, "failed to register spi_master[%u]\n", id); spi_master_put(master); return ret; } slave_info.bus_num = master->bus_num, uspi->slave = spi_new_device(master, &slave_info); if (uspi->slave == NULL) { dev_err(parent, "failed to create slave at spibus %u\n", id); spi_master_put(master); return -ENXIO; } fbus_bridge.spi_buses[id] = uspi; return 0; } static void fbus_spi_remove_all(void) { u32 i; struct fbus_tlv *tlv; struct fbus_spi_master *uspi; for (i = 0; i < ARRAY_SIZE(fbus_bridge.spi_buses); i++) { uspi = fbus_bridge.spi_buses[i]; if (uspi != NULL) { spi_unregister_device(uspi->slave); spi_unregister_master(uspi->master); } } } static int fbus_usb_probe(struct usb_interface *usb_intf, const struct usb_device_id *usb_id) { u32 i; int ret = 0; struct usb_endpoint_descriptor *bulk_in, *bulk_out; fbus_bridge.usb_intf = usb_intf; fbus_bridge.usb_dev = usb_get_dev(interface_to_usbdev(usb_intf)); /* * The device supports 1 bulk-in and 1 bulk-out endpoints now. */ ret = usb_find_common_endpoints(usb_intf->cur_altsetting, &bulk_in, &bulk_out, NULL, NULL); if (ret) { dev_err(&usb_intf->dev, "Could not find bulk-in and/or bulk-out endpoints\n"); return ret; } fbus_bridge.ep_list[USPI_BULK_IN] = bulk_in->bEndpointAddress; fbus_bridge.ep_list[USPI_BULK_OUT] = bulk_out->bEndpointAddress; mutex_init(&fbus_bridge.xfer_lock); for (i = 0; i < ARRAY_SIZE(fbus_bridge.spi_buses); i++) { ret = fbus_spi_master_init(i); if (ret < 0) goto error; } ret = misc_dev_init(&usb_intf->dev, &fbus_bridge.miscdev); if (ret < 0) { dev_err(&usb_intf->dev, "failed to initialize miscdevice, ret=%d\n", ret); goto error; } mutex_init(&spi_flow_ctrl); usb_set_intfdata(usb_intf, &fbus_bridge); dev_info(&usb_intf->dev, "ep_bulk_in: 0x%x, ep_bulk_out: 0x%x\n", fbus_bridge.ep_list[USPI_BULK_IN], fbus_bridge.ep_list[USPI_BULK_OUT]); return 0; error: fbus_spi_remove_all(); return ret; } static void fbus_usb_disconnect(struct usb_interface *usb_intf) { misc_dev_destroy(&fbus_bridge.miscdev); fbus_spi_remove_all(); usb_set_intfdata(usb_intf, NULL); usb_put_dev(fbus_bridge.usb_dev); } static const struct usb_device_id fbus_usb_table[] = { {USB_DEVICE(0x2ec6, 0x0100)}, /* XILINX */ {USB_DEVICE(0x0100, 0x2EC6)}, /* XILINX */ {} }; MODULE_DEVICE_TABLE(usb, fbus_usb_table); static struct usb_driver fbus_usb_driver = { .name = "fb-usb-spi", .probe = fbus_usb_probe, .disconnect = fbus_usb_disconnect, .id_table = fbus_usb_table, }; module_usb_driver(fbus_usb_driver); MODULE_AUTHOR("Tao Ren<taoren@fb.com>"); MODULE_DESCRIPTION("Facebook USB-SPI Adapter Driver"); MODULE_LICENSE("GPL");