Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 371e6bb5 authored by Sujeev Dias's avatar Sujeev Dias
Browse files

mhi_bus: core: Add support for MHI host interface



MHI Host Interface is a communication protocol to be used by the host
to control and communcate with modem over a high speed peripheral bus.
This module will allow host to communicate with external devices that
support MHI protocol.

CRs-Fixed: 2204910
Change-Id: I6057f9167ebbb5d4dc2ebb91e46ede6bc7054325
Signed-off-by: default avatarSujeev Dias <sdias@codeaurora.org>
parent b2bdf7dc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -280,6 +280,8 @@ men-chameleon-bus.txt
	- info on MEN chameleon bus.
metag/
	- directory with info about Linux on Meta architecture.
mhi.txt
	- Modem Host Interface
mic/
	- Intel Many Integrated Core (MIC) architecture device driver.
mips/
+136 −0
Original line number Diff line number Diff line
MHI Host Interface

MHI used by the host to control and communicate with modem over
high speed peripheral bus.

==============
Node Structure
==============

Main node properties:

- mhi,max-channels
  Usage: required
  Value type: <u32>
  Definition: Maximum number of channels supported by this controller

- mhi,chan-cfg
  Usage: required
  Value type: Array of <u32>
  Definition: Array of tuples describe channel configuration.
	1st element: Physical channel number
	2nd element: Transfer ring length in elements
	3rd element: Event ring associated with this channel
	4th element: Channel direction as defined by enum dma_data_direction
		1 = UL data transfer
		2 = DL data transfer
	5th element: Channel doorbell mode configuration as defined by
	enum MHI_BRSTMODE
		2 = burst mode disabled
		3 = burst mode enabled
	6th element: mhi doorbell configuration, valid only when burst mode
	enabled.
		0 = Use default (device specific) polling configuration
		For UL channels, value specifies the timer to poll MHI context
		in milliseconds.
		For DL channels, the threshold to poll the MHI context
		in multiple of eight ring element.
	7th element: Channel execution enviornment as defined by enum MHI_EE
		1 = Bootloader stage
		2 = AMSS mode
	8th element: data transfer type accepted as defined by enum
	MHI_XFER_TYPE
		0 = accept cpu address for buffer
		1 = accept skb
		2 = accept scatterlist
		3 = offload channel, does not accept any transfer type
	9th element: Bitwise configuration settings for the channel
		Bit mask:
		BIT(0) : LPM notify, this channel master requre lpm enter/exit
		notifications.
		BIT(1) : Offload channel, MHI host only involved in setting up
		the data pipe. Not involved in active data transfer.

- mhi,chan-names
  Usage: required
  Value type: Array of <string>
  Definition: Channel names configured in mhi,chan-cfg.

- mhi,ev-cfg
  Usage: required
  Value type: Array of <u32>
  Definition: Array of tuples describe event configuration.
	1st element: Event ring length in elements
	2nd element: Interrupt moderation time in ms
	3rd element: MSI associated with this event ring
	4th element: Dedicated channel number, if it's a dedicated event ring
	5th element: Event ring priority, set to 1 for now
	6th element: Event doorbell mode configuration as defined by
	enum MHI_BRSTMODE
		2 = burst mode disabled
		3 = burst mode enabled
	7th element: Bitwise configuration settings for the channel
		Bit mask:
		BIT(0) : Event ring associated with hardware channels
		BIT(1) : Client manages the event ring (use by napi_poll)
		BIT(2) : Event ring associated with offload channel
		BIT(3) : Event ring dedicated to control events only

- mhi,timeout
  Usage: optional
  Value type: <u32>
  Definition: Maximum timeout in ms wait for state and cmd completion

- mhi,fw-name
  Usage: optional
  Value type: <string>
  Definition: Firmware image name to upload

- mhi,edl-name
  Usage: optional
  Value type: <string>
  Definition: Firmware image name for emergency download

- mhi,fbc-download
  Usage: optional
  Value type: <bool>
  Definition: If set true, image specified by fw-name is for full image

- mhi,sbl-size
  Usage: optional
  Value type: <u32>
  Definition: Size of SBL image in bytes

- mhi,seg-len
  Usage: optional
  Value type: <u32>
  Definition: Size of each segment to allocate for BHIe vector table

Children node properties:

MHI drivers that require DT can add driver specific information as a child node.

- mhi,chan
  Usage: Required
  Value type: <string>
  Definition: Channel name

========
Example:
========
mhi_controller {
	mhi,max-channels = <105>;
	mhi,chan-cfg = <0 64 2 1 2 1 2 0 0>, <1 64 2 2 2 1 2 0 0>,
		       <2 64 1 1 2 1 1 0 0>, <3 64 1 2 2 1 1 0 0>;
	mhi,chan-names = "LOOPBACK", "LOOPBACK",
			 "SAHARA", "SAHARA";
	mhi,ev-cfg = <64 1 1 0 1 2 8>
		     <64 1 2 0 1 2 0>;
	mhi,fw-name = "sbl1.mbn";
	mhi,timeout = <500>;

	children_node {
		mhi,chan = "LOOPBACK"
		<driver specific properties>
	};
};

Documentation/mhi.txt

0 → 100644
+235 −0
Original line number Diff line number Diff line
Overview of Linux kernel MHI support
====================================

Modem-Host Interface (MHI)
=========================
MHI used by the host to control and communicate with modem over high speed
peripheral bus. Even though MHI can be easily adapt to any peripheral buses,
primarily used with PCIe based devices. The host has one or more PCIe root
ports connected to modem device. The host has limited access to device memory
space, including register configuration and control the device operation.
Data transfers are invoked from the device.

All data structures used by MHI are in the host system memory. Using PCIe
interface, the device accesses those data structures. MHI data structures and
data buffers in the host system memory regions are mapped for device.

Memory spaces
-------------
PCIe Configurations : Used for enumeration and resource management, such as
interrupt and base addresses.  This is done by mhi control driver.

MMIO
----
MHI MMIO : Memory mapped IO consists of set of registers in the device hardware,
which are mapped to the host memory space through PCIe base address register
(BAR)

MHI control registers : Access to MHI configurations registers
(struct mhi_controller.regs).

MHI BHI register: Boot host interface registers (struct mhi_controller.bhi) used
for firmware download before MHI initialization.

Channel db array : Doorbell registers (struct mhi_chan.tre_ring.db_addr) used by
host to notify device there is new work to do.

Event db array : Associated with event context array
(struct mhi_event.ring.db_addr), host uses to notify device free events are
available.

Data structures
---------------
Host memory : Directly accessed by the host to manage the MHI data structures
and buffers. The device accesses the host memory over the PCIe interface.

Channel context array : All channel configurations are organized in channel
context data array.

struct __packed mhi_chan_ctxt;
struct mhi_ctxt.chan_ctxt;

Transfer rings : Used by host to schedule work items for a channel and organized
as a circular queue of transfer descriptors (TD).

struct __packed mhi_tre;
struct mhi_chan.tre_ring;

Event context array : All event configurations are organized in event context
data array.

struct mhi_ctxt.er_ctxt;
struct __packed mhi_event_ctxt;

Event rings: Used by device to send completion and state transition messages to
host

struct mhi_event.ring;
struct __packed mhi_tre;

Command context array: All command configurations are organized in command
context data array.

struct __packed mhi_cmd_ctxt;
struct mhi_ctxt.cmd_ctxt;

Command rings: Used by host to send MHI commands to device

struct __packed mhi_tre;
struct mhi_cmd.ring;

Transfer rings
--------------
MHI channels are logical, unidirectional data pipes between host and device.
Each channel associated with a single transfer ring.  The data direction can be
either inbound (device to host) or outbound (host to device).  Transfer
descriptors are managed by using transfer rings, which are defined for each
channel between device and host and resides in the host memory.

Transfer ring Pointer:	  	Transfer Ring Array
[Read Pointer (RP)] ----------->[Ring Element] } TD
[Write Pointer (WP)]-		[Ring Element]
                     -		[Ring Element]
		      --------->[Ring Element]
				[Ring Element]

1. Host allocate memory for transfer ring
2. Host sets base, read pointer, write pointer in corresponding channel context
3. Ring is considered empty when RP == WP
4. Ring is considered full when WP + 1 == RP
4. RP indicates the next element to be serviced by device
4. When host new buffer to send, host update the Ring element with buffer
   information
5. Host increment the WP to next element
6. Ring the associated channel DB.

Event rings
-----------
Events from the device to host are organized in event rings and defined in event
descriptors.  Event rings are array of EDs that resides in the host memory.

Transfer ring Pointer:	  	Event Ring Array
[Read Pointer (RP)] ----------->[Ring Element] } ED
[Write Pointer (WP)]-		[Ring Element]
                     -		[Ring Element]
		      --------->[Ring Element]
				[Ring Element]

1. Host allocate memory for event ring
2. Host sets base, read pointer, write pointer in corresponding channel context
3. Both host and device has local copy of RP, WP
3. Ring is considered empty (no events to service) when WP + 1 == RP
4. Ring is full of events when RP == WP
4. RP - 1 = last event device programmed
4. When there is a new event device need to send, device update ED pointed by RP
5. Device increment RP to next element
6. Device trigger and interrupt

Example Operation for data transfer:

1. Host prepare TD with buffer information
2. Host increment Chan[id].ctxt.WP
3. Host ring channel DB register
4. Device wakes up process the TD
5. Device generate a completion event for that TD by updating ED
6. Device increment Event[id].ctxt.RP
7. Device trigger MSI to wake host
8. Host wakes up and check event ring for completion event
9. Host update the Event[i].ctxt.WP to indicate processed of completion event.

MHI States
----------

enum MHI_STATE {
MHI_STATE_RESET : MHI is in reset state, POR state. Host is not allowed to
		  access device MMIO register space.
MHI_STATE_READY : Device is ready for initialization. Host can start MHI
		  initialization by programming MMIO
MHI_STATE_M0 : MHI is in fully active state, data transfer is active
MHI_STATE_M1 : Device in a suspended state
MHI_STATE_M2 : MHI in low power mode, device may enter lower power mode.
MHI_STATE_M3 : Both host and device in suspended state.  PCIe link is not
	       accessible to device.

MHI Initialization
------------------

1. After system boots, the device is enumerated over PCIe interface
2. Host allocate MHI context for event, channel and command arrays
3. Initialize context array, and prepare interrupts
3. Host waits until device enter READY state
4. Program MHI MMIO registers and set device into MHI_M0 state
5. Wait for device to enter M0 state

Linux Software Architecture
===========================

MHI Controller
--------------
MHI controller is also the MHI bus master. In charge of managing the physical
link between host and device.  Not involved in actual data transfer.  At least
for PCIe based buses, for other type of bus, we can expand to add support.

Roles:
1. Turn on PCIe bus and configure the link
2. Configure MSI, SMMU, and IOMEM
3. Allocate struct mhi_controller and register with MHI bus framework
2. Initiate power on and shutdown sequence
3. Initiate suspend and resume

Usage
-----

1. Allocate control data structure by calling mhi_alloc_controller()
2. Initialize mhi_controller with all the known information such as:
   - Device Topology
   - IOMMU window
   - IOMEM mapping
   - Device to use for memory allocation, and of_node with DT configuration
   - Configure asynchronous callback functions
3. Register MHI controller with MHI bus framework by calling
   of_register_mhi_controller()

After successfully registering controller can initiate any of these power modes:

1. Power up sequence
   - mhi_prepare_for_power_up()
   - mhi_async_power_up()
   - mhi_sync_power_up()
2. Power down sequence
   - mhi_power_down()
   - mhi_unprepare_after_power_down()
3. Initiate suspend
   - mhi_pm_suspend()
4. Initiate resume
   - mhi_pm_resume()

MHI Devices
-----------
Logical device that bind to maximum of two physical MHI channels. Once MHI is in
powered on state, each supported channel by controller will be allocated as a
mhi_device.

Each supported device would be enumerated under
/sys/bus/mhi/devices/

struct mhi_device;

MHI Driver
----------
Each MHI driver can bind to one or more MHI devices. MHI host driver will bind
mhi_device to mhi_driver.

All registered drivers are visible under
/sys/bus/mhi/drivers/

struct mhi_driver;

Usage
-----

1. Register driver using mhi_driver_register
2. Before sending data, prepare device for transfer by calling
   mhi_prepare_for_transfer
3. Initiate data transfer by calling mhi_queue_transfer
4. After finish, call mhi_unprepare_from_transfer to end data transfer
+17 −0
Original line number Diff line number Diff line
@@ -184,4 +184,21 @@ config DA8XX_MSTPRI
	  configuration. Allows to adjust the priorities of all master
	  peripherals.

config MHI_BUS
	tristate "Modem Host Interface"
	help
	  MHI Host Interface is a communication protocol to be used by the host
	  to control and communcate with modem over a high speed peripheral bus.
	  Enabling this module will allow host to communicate with external
	  devices that support MHI protocol.

config MHI_DEBUG
	 bool "MHI debug support"
	 depends on MHI_BUS
	 help
	   Say yes here to enable debugging support in the MHI transport
	   and individual MHI client drivers. This option will impact
	   throughput as individual MHI packets and state transitions
	   will be logged.

endmenu
+1 −0
Original line number Diff line number Diff line
@@ -25,3 +25,4 @@ obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o

obj-$(CONFIG_DA8XX_MSTPRI)	+= da8xx-mstpri.o
obj-$(CONFIG_MHI_BUS) += mhi/
Loading