123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- Introduction
- ============
- USB UICC connectivity is required for MSM8x12. This SoC has only 1 USB
- controller which is used for peripheral mode and charging. Hence an external
- USB host controller over SPI is used to connect a USB UICC card. ICE40 FPGA
- based SPI to IC-USB (Inter-Chip USB) bridge chip is used.
- The ICE40 Host controller driver (ice40-hcd) is registered as a SPI protocol
- driver and interacts with the SPI subsystem on one side and interacts with the
- USB core on the other side.
- Hardware description
- ====================
- The ICE40 devices are SRAM-based FPGAs. The SRAM memory cells are volatile,
- meaning that once power is removed from the device, its configuration is lost
- and must be reloaded on the next power-up. An on-chip non-volatile configuration
- memory or an external SPI flash are not used to store the configuration data due
- to increased power consumption. Instead, the software loads the configuration
- data through SPI interface after powering up the bridge chip. Once the
- configuration data is programmed successfully, the bridge chip will be ready for
- the USB host controller operations.
- The ICE40 device has an interrupt signal apart from the standard SPI signals
- CSn, SCLK, MOSI and MISO. It has support for 25 to 50 MHz frequencies. The
- maximum operating frequency during configuration loading is 25 MHz.
- The bridge chip requires two power supplies, SPI_VCC (1.8v - 3.3v) and VCC_CORE
- (1.2v). The SPI_VCC manages the SPI slave portion and VCC_CORE manages the USB
- serial engine (SIE) portion. It requires a 19.2 MHz reference clock and a
- 32 MHz clock is required for remote wakeup detection during suspend.
- The configuration loading sequence:
- - Assert the RSTn pin. This keeps bridge chip in reset state after downloading
- the configuration data.
- - The bridge chip samples the SPI interface chip select pin during power-up and
- enters SPI slave mode if it is low. Drive the chip select pin low before
- powering up the bridge chip.
- - Power-up the bridge chip by enabling SPI_VCC and VCC_CORE
- - De-assert the chip select pin after 50 usec.
- - Transfer the configuration data over SPI. Note that the bridge chip requires
- 49 dummy clock cycles after sending the data.
- - The bridge chip indicates the status of the configuration loading via config
- done pin. It may take 50 usec to assert this pin.
- The 19.2 MHz clock should be supplied before de-asserting the RSTn pin. A PLL
- is used to generate a 48MHz clock signal that then creates a 12MHz clock signal
- by a divider. When the PLLOK bit is set in USB Transfer Result register, it
- indicates that the PLL output is locked to the input reference clock. When it
- is 0, it indicates that the PLL is out of lock. It is recommended to assert the
- RSTn pin to re-synchronize the PLL to the reference clock when the PLL loses
- lock. The chip will be ready for the USB host controller operations after it is
- brought out of reset and PLL is synchronized to the reference clock.
- The software is responsible for initiating all the USB host transfers by writing
- the associated registers. The SIE in the bridge chip performs the USB host
- operations via the IC-USB bus based on the registers set by the software. The
- USB transfer results as well as the bus status like the peripheral connection,
- disconnection, resume, etc. are notified to software through the interrupt and
- the internal registers.
- The bridge chip provides the DP & DM pull-down resistor control to the software.
- The pull-down resistors are enabled automatically after the power up to force
- the SE0 condition on the bus. The software is required to disable these
- resistors before driving the reset on the bus. Control, Bulk and Interrupt
- transfers are supported. The data toggling states are not maintained in the
- hardware and should be serviced by the software. The bridge chip returns
- one of the following values for a USB transaction (SETUP/IN/OUT) via Transfer
- result register.
- xSUCCESS: Successful transfer.
- xBUSY: The SIE is busy with a USB transfer.
- xPKTERR: Packet Error (stuff, EOP).
- xPIDERR: PID check bits are incorrect.
- xNAK: Device returned NAK. This is not an error condition for IN/OUT. But it
- is an error condition for SETUP.
- xSTALL: Device returned STALL.
- xWRONGPID: Wrong PID is received. For example a IN transaction is attempted on
- OUT endpoint.
- xCRCERR: CRC error.
- xTOGERR: Toggle bit error. The SIE returns ACK when the toggle mismatch happens
- for IN transaction and returns this error code. Software should discard the
- data as it was received already in the previous transaction.
- xBADLEN: Too big packet size received.
- xTIMEOUT: Device failed to respond in time.
- Software description
- ====================
- This driver is compiled as a module and is loaded by the userspace after
- getting the UICC card insertion event from the modem processor. The module is
- unloaded upon the UICC card removal.
- This driver registers as a SPI protocol driver. The SPI controller driver
- manages the chip select pin. This pin needs to be driven low before powering
- up the bridge chip. Hence this pin settings are overridden temporarily during
- the bridge chip power-up sequence. The original settings are restored before
- sending the configuration data to the bridge chip which acts as a SPI slave.
- Both pinctl and gpiomux framework allow this type of use case.
- The configuration data file is stored on the eMMC card. Firmware class API
- request_firmware() is used to read the configuration data file. The
- configuration data is then sent to the bridge chip via SPI interface. The
- bridge chip asserts the config done pin once the configuration is completed.
- The driver registers as a Full Speed (USB 1.1) HCD. The following methods
- are implemented that are part of hc_drive struct:
- reset: It is called one time by the core during HCD registration. The
- default address 0 is programmed and the line state is sampled to check if any
- device is connected. If any device is connected, the port flags are updated
- accordingly. As the module is loaded after the UICC card is inserted, the
- device would be present at this time.
- start: This method is called one time by the core during HCD registration.
- The bridge chip is programmed to transmit the SOFs.
- stop: The method is called one time by the core during HCD deregistration.
- The bridge chip is programmed to stop transmitting the SOFs.
- hub_control: This method is called by the core to manage the Root HUB. The
- hardware does not maintain port state. The software maintain the port
- state and provide the information to the core when required. The following
- HUB class requests are supported.
- - GetHubDescriptor: The HUB descriptor is sent to the core. Only 1 port
- is present. Over current protection and port power control are not supported.
- - SetPortFeature: The device reset and suspend are supported. The The DP & DM
- pull-down resistors are disabled before driving the reset as per the IC-USB
- spec. The reset signaling is stopped when the core queries the port status.
- - GetPortStatus: The device connection status is sent to the core. If a reset
- is in progress, it is stopped before returning the port status.
- - ClearPortFeature: The device resume (clear suspend) is supported.
- urb_enqueue: This method is called by the core to initiate a USB Control/Bulk
- transfer. If the endpoint private context is not present, it will be created to
- hold the endpoint number, host endpoint structure, transaction error count, halt
- state and unlink state. The URB is attached to the endpoint URB list. If the
- endpoint is not active, it is attached to the asynchronous schedule list and the
- work is scheduled to traverse this list. The traversal algorithm is explained
- later in this document.
- urb_dequeue: This method is called by the core when an URB is unlinked. If the
- endpoint is not active, the URB is unlinked immediately. Otherwise the endpoint
- is marked for unlink and URB is unlinked from the asynchronous schedule work.
- bus_suspend: This method is called by the core during root hub suspend. The SOFs
- are already stopped during the port suspend which happens before root hub
- suspend. Assert the RSTn pin to put the bridge chip in reset state and stop XO
- (19.2 MHz) clock.
- bus_resume: This method is called by the core during root hub resume. Turn on
- the XO clock and de-assert the RSTn signal to bring the chip out of reset.
- endpoint_disable: This method is called by the core during the device
- disconnect. All the URB are unlinked by this time, so free the endpoint private
- structure.
- Asynchronous scheduling:
- All the active endpoints are queued to the asynchronous schedule list. A worker
- thread iterates over this circular list and process the URBs. Processing an URB
- involves initiating multiple SETUP/IN/OUT transactions and checking the result.
- After receiving the DATA/ACK, the toggle bit is inverted.
- A URB is finished when any of the following events occur:
- - The entire data is received for an OUT endpoint or a short packet is received
- for an IN endpoint.
- - The endpoint is stalled by the device. -EPIPE is returned.
- - Transaction error is occurred consecutively 3 times. -EPROTO is returned.
- - A NAK received for a SETUP transaction.
- - The URB is unlinked.
- The next transaction is issued on the next endpoint (if available) irrespective
- of the result of the current transaction. But the IN/OUT transaction of data
- or status phase is attempted immediately after the SETUP transaction for a
- control endpoint. If a NAK is received for this transaction, the control
- transfer is resumed next time when the control endpoint is encountered in the
- asynchronous schedule list. This is to give the control transfers priority
- over the bulk transfers.
- The endpoint is marked as halted when a URB is finished due to transaction
- errors or stall condition. The halted endpoint is removed from the asynchronous
- schedule list. It will be added again next time when a URB is enqueued on this
- endpoint.
- This driver provides debugfs interface and exports a file called "command" under
- <debugfs root>/ice40 directory. The following strings can be echoed to this
- file.
- "poll": If the device is connected after the module is loaded, it will not be
- detected automatically. The bus is sampled when this string is echoed. If a
- device is connected, port flags are updated and core is notified about the
- device connect event.
- "rwtest": Function Address register is written and read back to validate the
- contents. This should NOT be used while the usb device is connected. This is
- strictly for debugging purpose.
- "dump": Dumps all the register values to the kernel log buffer.
- Design Goals:
- =============
- - Handle errors gracefully. Implement retry mechanism for transaction errors,
- memory failures. Mark HCD as dead for serious errors like SPI transaction
- errors to avoid further interactions with the attached USB device.
- - Keep the asynchronous schedule algorithm simple and efficient. Take advantage
- of the static configuration of the USB device. UICC cards has only CCID and Mass
- storage interfaces. These interface protocol allows only 1 active transfer on
- either in or out endpoint.
- - Add trace points to capture USB transactions.
- Driver parameters
- =================
- The driver is compiled as a module and it accepts the configuration data file
- name as a module param called "firmware". The default configuration file name
- is "ice40.bin".
- Config options
- ==============
- Set CONFIG_USB_SL811_HCD to m to compile this driver as a module. The driver
- should not be compiled statically, because the configuration data is not
- available during kernel boot.
- To do
- =====
- - The bridge chip has 2 IN FIFO and 2 OUT FIFO. Implement double buffering.
- - The bridge chip has an interrupt to indicate the transaction (IN/OUT)
- completion. The current implementation uses polling for simplicity and to avoid
- interrupt latencies. Evaluate interrupt approach.
- - The bridge chip can be completely power collapsed during suspend to avoid
- leakage currents. As the bridge chip does not have any non-volatile memory,
- the configuration data needs to be loaded during resume. This method has higher
- power savings with higher resume latencies. Evaluate this approach.
- - Implement Interrupt transfers if required.
- - The request_firmware() API copies the configuration data file to the kernel
- virtual memory. This memory can't be used for DMA. The current implementation
- copies this data into contiguous physical memory which is allocated via
- kmalloc. If this memory allocation fails, try to allocate multiple pages
- and submit the SPI message with multiple transfers.
|