Loading Documentation/devicetree/bindings/bus/mhi.txt +122 −55 Original line number Diff line number Diff line Loading @@ -14,57 +14,6 @@ Main node properties: 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 0 = Bidirectional data transfer 1 = UL data transfer 2 = DL data transfer 3 = No direction, not a regular data transfer channel 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. BIT(2) : Must switch to doorbell mode whenever MHI M0 state transition happens. BIT(3) : MHI bus driver pre-allocate buffer for this channel. If set, clients not allowed to queue buffers. Valid only for DL direction. BIT(4) : MHI host driver to automatically start channels once mhi device driver probe is complete. - mhi,chan-names Usage: required Value type: Array of <string> Definition: Channel names configured in mhi,chan-cfg. - mhi,timeout Usage: optional Value type: <u32> Loading Loading @@ -102,6 +51,105 @@ Main node properties: feature for time synchronization between host processor and external modem. ============================ mhi channel node properties: ============================ - reg Usage: required Value type: <u32> Definition: physical channel number - label Usage: required Value type: <string> Definition: given name for the channel - mhi,num-elements Usage: optional Value type: <u32> Definition: Number of elements transfer ring support - mhi,event-ring Usage: required Value type: <u32> Definition: Event ring index associated with this channel - mhi,chan-dir Usage: required Value type: <u32> Definition: Channel direction as defined by enum dma_data_direction 0 = Bidirectional data transfer 1 = UL data transfer 2 = DL data transfer 3 = No direction, not a regular data transfer channel - mhi,ee Usage: required Value type: <u32> Definition: Channel execution enviornment as defined by enum MHI_EE 1 = Bootloader stage 2 = AMSS mode - mhi,pollcfg Usage: optional Value type: <u32> Definition: MHI poll configuration, valid only when burst mode is 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. - mhi,data-type Usage: required Value type: <u32> Definition: 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 - mhi,doorbell-mode Usage: required Value type: <u32> Definition: Channel doorbell mode configuration as defined by enum MHI_BRSTMODE 2 = burst mode disabled 3 = burst mode enabled - mhi,lpm-notify Usage: optional Value type: <bool> Definition: This channel master require low power mode enter and exit notifications from mhi bus master. - mhi,offload-chan Usage: optional Value type: <bool> Definition: Client managed channel, MHI host only involved in setting up the data path, not involved in active data path. - mhi,db-mode-switch Usage: optional Value type: <bool> Definition: Must switch to doorbell mode whenever MHI M0 state transition happens. - mhi,auto-queue Usage: optional Value type: <bool> Definition: MHI bus driver will pre-allocate buffers for this channel and queue to hardware. If set, client not allowed to queue buffers. Valid only for downlink direction. - mhi,auto-start Usage: optional Value type: <bool> Definition: MHI host driver to automatically start channels once mhi device driver probe is complete. This should be only set true if initial handshake iniaitead by external modem. ========================== mhi event node properties: ========================== Loading Loading @@ -177,10 +225,29 @@ 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_chan@0 { reg = <0>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@1 { reg = <1>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; Loading arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +313 −30 Original line number Diff line number Diff line Loading @@ -28,42 +28,325 @@ /* mhi bus specific settings */ mhi,max-channels = <106>; mhi,chan-cfg = <0 64 2 1 2 0 2 0 0>, <1 64 2 2 2 0 2 0 0>, <2 128 1 1 2 0 1 0 0>, <3 128 1 2 2 0 1 0 0>, <4 64 1 1 2 0 2 0 0>, <5 64 3 2 2 0 2 0 0>, <8 64 1 1 2 0 2 0 0>, <9 64 1 2 2 0 2 0 0>, <10 64 1 1 2 0 2 0 0>, <11 64 1 2 2 0 2 0 0>, <14 64 1 1 2 0 2 0 0>, <15 64 2 2 2 0 2 0 0>, <16 64 3 1 2 0 2 0 0>, <17 64 3 2 2 0 2 0 0>, <18 64 1 1 2 0 2 0 0>, <19 64 1 2 2 0 2 0 8>, <20 64 2 1 2 0 2 1 16>, <21 64 2 2 2 0 2 0 24>, <22 64 2 1 2 0 2 0 0>, <23 64 2 2 2 0 2 0 0>, <24 64 2 1 2 0 1 0 0>, <25 64 2 2 2 0 1 0 0>, <26 64 3 1 2 0 2 0 0>, <27 64 3 2 2 0 2 0 0>, <32 64 3 1 2 0 2 0 0>, <33 64 3 2 2 0 2 0 0>, <100 512 4 1 3 1 2 1 4>, <101 512 5 2 3 1 2 1 0>; mhi,chan-names = "LOOPBACK", "LOOPBACK", "SAHARA", "SAHARA", "DIAG", "DIAG", "QDSS", "QDSS", "EFS", "EFS", "QMI0", "QMI0", "QMI1", "QMI1", "IP_CTRL", "IP_CTRL", "IPCR", "IPCR", "TF", "TF", "BL", "BL", "DCI", "DCI", "DUN", "DUN", "IP_HW0", "IP_HW0"; mhi,timeout = <2000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; mhi_chan@0 { reg = <0>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@1 { reg = <1>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@2 { reg = <2>; label = "SAHARA"; mhi,num-elements = <128>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@3 { reg = <3>; label = "SAHARA"; mhi,num-elements = <128>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@4 { reg = <4>; label = "DIAG"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@5 { reg = <5>; label = "DIAG"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@8 { reg = <8>; label = "QDSS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@9 { reg = <9>; label = "QDSS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@10 { reg = <10>; label = "EFS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@11 { reg = <11>; label = "EFS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@14 { reg = <14>; label = "QMI0"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@15 { reg = <15>; label = "QMI0"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@16 { reg = <16>; label = "QMI1"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@17 { reg = <17>; label = "QMI1"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@18 { reg = <18>; label = "IP_CTRL"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@19 { reg = <19>; label = "IP_CTRL"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-queue; }; mhi_chan@20 { reg = <20>; label = "IPCR"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-start; }; mhi_chan@21 { reg = <21>; label = "IPCR"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-queue; mhi,auto-start; }; mhi_chan@22 { reg = <22>; label = "TF"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@23 { reg = <23>; label = "TF"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@24 { reg = <24>; label = "BL"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@25 { reg = <25>; label = "BL"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@26 { reg = <26>; label = "DCI"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@27 { reg = <27>; label = "DCI"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@32 { reg = <32>; label = "DUN"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@33 { reg = <33>; label = "DUN"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@100 { reg = <100>; label = "IP_HW0"; mhi,num-elements = <512>; mhi,event-ring = <4>; mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; mhi,ee = <2>; mhi,db-mode-switch; }; mhi_chan@101 { reg = <101>; label = "IP_HW0"; mhi,num-elements = <512>; mhi,event-ring = <5>; mhi,chan-dir = <2>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; mhi,ee = <2>; }; mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; Loading drivers/bus/mhi/core/mhi_init.c +55 −52 Original line number Diff line number Diff line Loading @@ -850,65 +850,70 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { int num, i, ret; struct { u32 chan_cfg[MHI_CH_CFG_MAX]; } *chan_cfg; int ret; struct device_node *child; u32 chan; ret = of_property_read_u32(of_node, "mhi,max-channels", &mhi_cntrl->max_chan); if (ret) return ret; num = of_property_count_elems_of_size(of_node, "mhi,chan-cfg", sizeof(*chan_cfg)); if (num <= 0 || num >= mhi_cntrl->max_chan) return -EINVAL; if (of_property_count_strings(of_node, "mhi,chan-names") != num) return -EINVAL; mhi_cntrl->mhi_chan = kcalloc(mhi_cntrl->max_chan, sizeof(*mhi_cntrl->mhi_chan), GFP_KERNEL); if (!mhi_cntrl->mhi_chan) return -ENOMEM; chan_cfg = kcalloc(num, sizeof(*chan_cfg), GFP_KERNEL); if (!chan_cfg) { kfree(mhi_cntrl->mhi_chan); return -ENOMEM; } ret = of_property_read_u32_array(of_node, "mhi,chan-cfg", (u32 *)chan_cfg, num * sizeof(*chan_cfg) / sizeof(u32)); if (ret) goto error_chan_cfg; INIT_LIST_HEAD(&mhi_cntrl->lpm_chans); /* populate channel configurations */ for (i = 0; i < num; i++) { for_each_available_child_of_node(of_node, child) { struct mhi_chan *mhi_chan; int chan = chan_cfg[i].chan_cfg[MHI_CH_CFG_CHAN_ID]; u32 bit_cfg = chan_cfg[i].chan_cfg[MHI_CH_CFG_BITCFG]; if (chan >= mhi_cntrl->max_chan) if (strcmp(child->name, "mhi_chan")) continue; ret = of_property_read_u32(child, "reg", &chan); if (ret || chan >= mhi_cntrl->max_chan) goto error_chan_cfg; mhi_chan = &mhi_cntrl->mhi_chan[chan]; ret = of_property_read_string(child, "label", &mhi_chan->name); if (ret) goto error_chan_cfg; mhi_chan->chan = chan; mhi_chan->buf_ring.elements = chan_cfg[i].chan_cfg[MHI_CH_CFG_ELEMENTS]; ret = of_property_read_u32(child, "mhi,num-elements", (u32 *)&mhi_chan->buf_ring.elements); if (!ret && !mhi_chan->buf_ring.elements) goto error_chan_cfg; mhi_chan->tre_ring.elements = mhi_chan->buf_ring.elements; mhi_chan->er_index = chan_cfg[i].chan_cfg[MHI_CH_CFG_ER_INDEX]; mhi_chan->dir = chan_cfg[i].chan_cfg[MHI_CH_CFG_DIRECTION]; mhi_chan->db_cfg.pollcfg = chan_cfg[i].chan_cfg[MHI_CH_CFG_POLLCFG]; mhi_chan->ee = chan_cfg[i].chan_cfg[MHI_CH_CFG_EE]; if (mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) ret = of_property_read_u32(child, "mhi,event-ring", &mhi_chan->er_index); if (ret) goto error_chan_cfg; ret = of_property_read_u32(child, "mhi,chan-dir", &mhi_chan->dir); if (ret) goto error_chan_cfg; ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee); if (ret || mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) goto error_chan_cfg; mhi_chan->xfer_type = chan_cfg[i].chan_cfg[MHI_CH_CFG_XFER_TYPE]; of_property_read_u32(child, "mhi,pollcfg", &mhi_chan->db_cfg.pollcfg); ret = of_property_read_u32(child, "mhi,data-type", &mhi_chan->xfer_type); if (ret) goto error_chan_cfg; switch (mhi_chan->xfer_type) { case MHI_XFER_BUFFER: Loading @@ -929,12 +934,16 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, goto error_chan_cfg; } mhi_chan->lpm_notify = !!(bit_cfg & MHI_CH_CFG_BIT_LPM_NOTIFY); mhi_chan->offload_ch = !!(bit_cfg & MHI_CH_CFG_BIT_OFFLOAD_CH); mhi_chan->db_cfg.reset_req = !!(bit_cfg & MHI_CH_CFG_BIT_DBMODE_RESET_CH); mhi_chan->pre_alloc = !!(bit_cfg & MHI_CH_CFG_BIT_PRE_ALLOC); mhi_chan->auto_start = !!(bit_cfg & MHI_CH_CFG_BIT_AUTO_START); mhi_chan->lpm_notify = of_property_read_bool(child, "mhi,lpm-notify"); mhi_chan->offload_ch = of_property_read_bool(child, "mhi,offload-chan"); mhi_chan->db_cfg.reset_req = of_property_read_bool(child, "mhi,db-mode-switch"); mhi_chan->pre_alloc = of_property_read_bool(child, "mhi,auto-queue"); mhi_chan->auto_start = of_property_read_bool(child, "mhi,auto-start"); if (mhi_chan->pre_alloc && (mhi_chan->dir != DMA_FROM_DEVICE || Loading @@ -950,15 +959,11 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, if (mhi_chan->pre_alloc) mhi_chan->queue_xfer = mhi_queue_nop; ret = of_property_read_string_index(of_node, "mhi,chan-names", i, &mhi_chan->name); if (ret) goto error_chan_cfg; if (!mhi_chan->offload_ch) { mhi_chan->db_cfg.brstmode = chan_cfg[i].chan_cfg[MHI_CH_CFG_BRSTMODE]; if (MHI_INVALID_BRSTMODE(mhi_chan->db_cfg.brstmode)) ret = of_property_read_u32(child, "mhi,doorbell-mode", &mhi_chan->db_cfg.brstmode); if (ret || MHI_INVALID_BRSTMODE(mhi_chan->db_cfg.brstmode)) goto error_chan_cfg; mhi_chan->db_cfg.process_db = Loading @@ -966,19 +971,17 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, MHI_BRSTMODE_ENABLE) ? mhi_db_brstmode : mhi_db_brstmode_disable; } mhi_chan->configured = true; if (mhi_chan->lpm_notify) list_add_tail(&mhi_chan->node, &mhi_cntrl->lpm_chans); } kfree(chan_cfg); return 0; error_chan_cfg: kfree(mhi_cntrl->mhi_chan); kfree(chan_cfg); return -EINVAL; } Loading drivers/bus/mhi/core/mhi_internal.h +0 −19 Original line number Diff line number Diff line Loading @@ -364,25 +364,6 @@ enum MHI_CH_STATE { MHI_CH_STATE_ERROR = 0x5, }; enum MHI_CH_CFG { MHI_CH_CFG_CHAN_ID = 0, MHI_CH_CFG_ELEMENTS = 1, MHI_CH_CFG_ER_INDEX = 2, MHI_CH_CFG_DIRECTION = 3, MHI_CH_CFG_BRSTMODE = 4, MHI_CH_CFG_POLLCFG = 5, MHI_CH_CFG_EE = 6, MHI_CH_CFG_XFER_TYPE = 7, MHI_CH_CFG_BITCFG = 8, MHI_CH_CFG_MAX }; #define MHI_CH_CFG_BIT_LPM_NOTIFY BIT(0) /* require LPM notification */ #define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */ #define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */ #define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */ #define MHI_CH_CFG_BIT_AUTO_START BIT(4) /* host auto start channels */ enum MHI_BRSTMODE { MHI_BRSTMODE_DISABLE = 0x2, MHI_BRSTMODE_ENABLE = 0x3, Loading Loading
Documentation/devicetree/bindings/bus/mhi.txt +122 −55 Original line number Diff line number Diff line Loading @@ -14,57 +14,6 @@ Main node properties: 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 0 = Bidirectional data transfer 1 = UL data transfer 2 = DL data transfer 3 = No direction, not a regular data transfer channel 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. BIT(2) : Must switch to doorbell mode whenever MHI M0 state transition happens. BIT(3) : MHI bus driver pre-allocate buffer for this channel. If set, clients not allowed to queue buffers. Valid only for DL direction. BIT(4) : MHI host driver to automatically start channels once mhi device driver probe is complete. - mhi,chan-names Usage: required Value type: Array of <string> Definition: Channel names configured in mhi,chan-cfg. - mhi,timeout Usage: optional Value type: <u32> Loading Loading @@ -102,6 +51,105 @@ Main node properties: feature for time synchronization between host processor and external modem. ============================ mhi channel node properties: ============================ - reg Usage: required Value type: <u32> Definition: physical channel number - label Usage: required Value type: <string> Definition: given name for the channel - mhi,num-elements Usage: optional Value type: <u32> Definition: Number of elements transfer ring support - mhi,event-ring Usage: required Value type: <u32> Definition: Event ring index associated with this channel - mhi,chan-dir Usage: required Value type: <u32> Definition: Channel direction as defined by enum dma_data_direction 0 = Bidirectional data transfer 1 = UL data transfer 2 = DL data transfer 3 = No direction, not a regular data transfer channel - mhi,ee Usage: required Value type: <u32> Definition: Channel execution enviornment as defined by enum MHI_EE 1 = Bootloader stage 2 = AMSS mode - mhi,pollcfg Usage: optional Value type: <u32> Definition: MHI poll configuration, valid only when burst mode is 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. - mhi,data-type Usage: required Value type: <u32> Definition: 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 - mhi,doorbell-mode Usage: required Value type: <u32> Definition: Channel doorbell mode configuration as defined by enum MHI_BRSTMODE 2 = burst mode disabled 3 = burst mode enabled - mhi,lpm-notify Usage: optional Value type: <bool> Definition: This channel master require low power mode enter and exit notifications from mhi bus master. - mhi,offload-chan Usage: optional Value type: <bool> Definition: Client managed channel, MHI host only involved in setting up the data path, not involved in active data path. - mhi,db-mode-switch Usage: optional Value type: <bool> Definition: Must switch to doorbell mode whenever MHI M0 state transition happens. - mhi,auto-queue Usage: optional Value type: <bool> Definition: MHI bus driver will pre-allocate buffers for this channel and queue to hardware. If set, client not allowed to queue buffers. Valid only for downlink direction. - mhi,auto-start Usage: optional Value type: <bool> Definition: MHI host driver to automatically start channels once mhi device driver probe is complete. This should be only set true if initial handshake iniaitead by external modem. ========================== mhi event node properties: ========================== Loading Loading @@ -177,10 +225,29 @@ 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_chan@0 { reg = <0>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@1 { reg = <1>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; Loading
arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +313 −30 Original line number Diff line number Diff line Loading @@ -28,42 +28,325 @@ /* mhi bus specific settings */ mhi,max-channels = <106>; mhi,chan-cfg = <0 64 2 1 2 0 2 0 0>, <1 64 2 2 2 0 2 0 0>, <2 128 1 1 2 0 1 0 0>, <3 128 1 2 2 0 1 0 0>, <4 64 1 1 2 0 2 0 0>, <5 64 3 2 2 0 2 0 0>, <8 64 1 1 2 0 2 0 0>, <9 64 1 2 2 0 2 0 0>, <10 64 1 1 2 0 2 0 0>, <11 64 1 2 2 0 2 0 0>, <14 64 1 1 2 0 2 0 0>, <15 64 2 2 2 0 2 0 0>, <16 64 3 1 2 0 2 0 0>, <17 64 3 2 2 0 2 0 0>, <18 64 1 1 2 0 2 0 0>, <19 64 1 2 2 0 2 0 8>, <20 64 2 1 2 0 2 1 16>, <21 64 2 2 2 0 2 0 24>, <22 64 2 1 2 0 2 0 0>, <23 64 2 2 2 0 2 0 0>, <24 64 2 1 2 0 1 0 0>, <25 64 2 2 2 0 1 0 0>, <26 64 3 1 2 0 2 0 0>, <27 64 3 2 2 0 2 0 0>, <32 64 3 1 2 0 2 0 0>, <33 64 3 2 2 0 2 0 0>, <100 512 4 1 3 1 2 1 4>, <101 512 5 2 3 1 2 1 0>; mhi,chan-names = "LOOPBACK", "LOOPBACK", "SAHARA", "SAHARA", "DIAG", "DIAG", "QDSS", "QDSS", "EFS", "EFS", "QMI0", "QMI0", "QMI1", "QMI1", "IP_CTRL", "IP_CTRL", "IPCR", "IPCR", "TF", "TF", "BL", "BL", "DCI", "DCI", "DUN", "DUN", "IP_HW0", "IP_HW0"; mhi,timeout = <2000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; mhi_chan@0 { reg = <0>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@1 { reg = <1>; label = "LOOPBACK"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@2 { reg = <2>; label = "SAHARA"; mhi,num-elements = <128>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@3 { reg = <3>; label = "SAHARA"; mhi,num-elements = <128>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@4 { reg = <4>; label = "DIAG"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@5 { reg = <5>; label = "DIAG"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@8 { reg = <8>; label = "QDSS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@9 { reg = <9>; label = "QDSS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@10 { reg = <10>; label = "EFS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@11 { reg = <11>; label = "EFS"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@14 { reg = <14>; label = "QMI0"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@15 { reg = <15>; label = "QMI0"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@16 { reg = <16>; label = "QMI1"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@17 { reg = <17>; label = "QMI1"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@18 { reg = <18>; label = "IP_CTRL"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@19 { reg = <19>; label = "IP_CTRL"; mhi,num-elements = <64>; mhi,event-ring = <1>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-queue; }; mhi_chan@20 { reg = <20>; label = "IPCR"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-start; }; mhi_chan@21 { reg = <21>; label = "IPCR"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; mhi,auto-queue; mhi,auto-start; }; mhi_chan@22 { reg = <22>; label = "TF"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@23 { reg = <23>; label = "TF"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@24 { reg = <24>; label = "BL"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@25 { reg = <25>; label = "BL"; mhi,num-elements = <64>; mhi,event-ring = <2>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <1>; }; mhi_chan@26 { reg = <26>; label = "DCI"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@27 { reg = <27>; label = "DCI"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@32 { reg = <32>; label = "DUN"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@33 { reg = <33>; label = "DUN"; mhi,num-elements = <64>; mhi,event-ring = <3>; mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <2>; }; mhi_chan@100 { reg = <100>; label = "IP_HW0"; mhi,num-elements = <512>; mhi,event-ring = <4>; mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; mhi,ee = <2>; mhi,db-mode-switch; }; mhi_chan@101 { reg = <101>; label = "IP_HW0"; mhi,num-elements = <512>; mhi,event-ring = <5>; mhi,chan-dir = <2>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; mhi,ee = <2>; }; mhi_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; Loading
drivers/bus/mhi/core/mhi_init.c +55 −52 Original line number Diff line number Diff line Loading @@ -850,65 +850,70 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { int num, i, ret; struct { u32 chan_cfg[MHI_CH_CFG_MAX]; } *chan_cfg; int ret; struct device_node *child; u32 chan; ret = of_property_read_u32(of_node, "mhi,max-channels", &mhi_cntrl->max_chan); if (ret) return ret; num = of_property_count_elems_of_size(of_node, "mhi,chan-cfg", sizeof(*chan_cfg)); if (num <= 0 || num >= mhi_cntrl->max_chan) return -EINVAL; if (of_property_count_strings(of_node, "mhi,chan-names") != num) return -EINVAL; mhi_cntrl->mhi_chan = kcalloc(mhi_cntrl->max_chan, sizeof(*mhi_cntrl->mhi_chan), GFP_KERNEL); if (!mhi_cntrl->mhi_chan) return -ENOMEM; chan_cfg = kcalloc(num, sizeof(*chan_cfg), GFP_KERNEL); if (!chan_cfg) { kfree(mhi_cntrl->mhi_chan); return -ENOMEM; } ret = of_property_read_u32_array(of_node, "mhi,chan-cfg", (u32 *)chan_cfg, num * sizeof(*chan_cfg) / sizeof(u32)); if (ret) goto error_chan_cfg; INIT_LIST_HEAD(&mhi_cntrl->lpm_chans); /* populate channel configurations */ for (i = 0; i < num; i++) { for_each_available_child_of_node(of_node, child) { struct mhi_chan *mhi_chan; int chan = chan_cfg[i].chan_cfg[MHI_CH_CFG_CHAN_ID]; u32 bit_cfg = chan_cfg[i].chan_cfg[MHI_CH_CFG_BITCFG]; if (chan >= mhi_cntrl->max_chan) if (strcmp(child->name, "mhi_chan")) continue; ret = of_property_read_u32(child, "reg", &chan); if (ret || chan >= mhi_cntrl->max_chan) goto error_chan_cfg; mhi_chan = &mhi_cntrl->mhi_chan[chan]; ret = of_property_read_string(child, "label", &mhi_chan->name); if (ret) goto error_chan_cfg; mhi_chan->chan = chan; mhi_chan->buf_ring.elements = chan_cfg[i].chan_cfg[MHI_CH_CFG_ELEMENTS]; ret = of_property_read_u32(child, "mhi,num-elements", (u32 *)&mhi_chan->buf_ring.elements); if (!ret && !mhi_chan->buf_ring.elements) goto error_chan_cfg; mhi_chan->tre_ring.elements = mhi_chan->buf_ring.elements; mhi_chan->er_index = chan_cfg[i].chan_cfg[MHI_CH_CFG_ER_INDEX]; mhi_chan->dir = chan_cfg[i].chan_cfg[MHI_CH_CFG_DIRECTION]; mhi_chan->db_cfg.pollcfg = chan_cfg[i].chan_cfg[MHI_CH_CFG_POLLCFG]; mhi_chan->ee = chan_cfg[i].chan_cfg[MHI_CH_CFG_EE]; if (mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) ret = of_property_read_u32(child, "mhi,event-ring", &mhi_chan->er_index); if (ret) goto error_chan_cfg; ret = of_property_read_u32(child, "mhi,chan-dir", &mhi_chan->dir); if (ret) goto error_chan_cfg; ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee); if (ret || mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) goto error_chan_cfg; mhi_chan->xfer_type = chan_cfg[i].chan_cfg[MHI_CH_CFG_XFER_TYPE]; of_property_read_u32(child, "mhi,pollcfg", &mhi_chan->db_cfg.pollcfg); ret = of_property_read_u32(child, "mhi,data-type", &mhi_chan->xfer_type); if (ret) goto error_chan_cfg; switch (mhi_chan->xfer_type) { case MHI_XFER_BUFFER: Loading @@ -929,12 +934,16 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, goto error_chan_cfg; } mhi_chan->lpm_notify = !!(bit_cfg & MHI_CH_CFG_BIT_LPM_NOTIFY); mhi_chan->offload_ch = !!(bit_cfg & MHI_CH_CFG_BIT_OFFLOAD_CH); mhi_chan->db_cfg.reset_req = !!(bit_cfg & MHI_CH_CFG_BIT_DBMODE_RESET_CH); mhi_chan->pre_alloc = !!(bit_cfg & MHI_CH_CFG_BIT_PRE_ALLOC); mhi_chan->auto_start = !!(bit_cfg & MHI_CH_CFG_BIT_AUTO_START); mhi_chan->lpm_notify = of_property_read_bool(child, "mhi,lpm-notify"); mhi_chan->offload_ch = of_property_read_bool(child, "mhi,offload-chan"); mhi_chan->db_cfg.reset_req = of_property_read_bool(child, "mhi,db-mode-switch"); mhi_chan->pre_alloc = of_property_read_bool(child, "mhi,auto-queue"); mhi_chan->auto_start = of_property_read_bool(child, "mhi,auto-start"); if (mhi_chan->pre_alloc && (mhi_chan->dir != DMA_FROM_DEVICE || Loading @@ -950,15 +959,11 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, if (mhi_chan->pre_alloc) mhi_chan->queue_xfer = mhi_queue_nop; ret = of_property_read_string_index(of_node, "mhi,chan-names", i, &mhi_chan->name); if (ret) goto error_chan_cfg; if (!mhi_chan->offload_ch) { mhi_chan->db_cfg.brstmode = chan_cfg[i].chan_cfg[MHI_CH_CFG_BRSTMODE]; if (MHI_INVALID_BRSTMODE(mhi_chan->db_cfg.brstmode)) ret = of_property_read_u32(child, "mhi,doorbell-mode", &mhi_chan->db_cfg.brstmode); if (ret || MHI_INVALID_BRSTMODE(mhi_chan->db_cfg.brstmode)) goto error_chan_cfg; mhi_chan->db_cfg.process_db = Loading @@ -966,19 +971,17 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, MHI_BRSTMODE_ENABLE) ? mhi_db_brstmode : mhi_db_brstmode_disable; } mhi_chan->configured = true; if (mhi_chan->lpm_notify) list_add_tail(&mhi_chan->node, &mhi_cntrl->lpm_chans); } kfree(chan_cfg); return 0; error_chan_cfg: kfree(mhi_cntrl->mhi_chan); kfree(chan_cfg); return -EINVAL; } Loading
drivers/bus/mhi/core/mhi_internal.h +0 −19 Original line number Diff line number Diff line Loading @@ -364,25 +364,6 @@ enum MHI_CH_STATE { MHI_CH_STATE_ERROR = 0x5, }; enum MHI_CH_CFG { MHI_CH_CFG_CHAN_ID = 0, MHI_CH_CFG_ELEMENTS = 1, MHI_CH_CFG_ER_INDEX = 2, MHI_CH_CFG_DIRECTION = 3, MHI_CH_CFG_BRSTMODE = 4, MHI_CH_CFG_POLLCFG = 5, MHI_CH_CFG_EE = 6, MHI_CH_CFG_XFER_TYPE = 7, MHI_CH_CFG_BITCFG = 8, MHI_CH_CFG_MAX }; #define MHI_CH_CFG_BIT_LPM_NOTIFY BIT(0) /* require LPM notification */ #define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */ #define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */ #define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */ #define MHI_CH_CFG_BIT_AUTO_START BIT(4) /* host auto start channels */ enum MHI_BRSTMODE { MHI_BRSTMODE_DISABLE = 0x2, MHI_BRSTMODE_ENABLE = 0x3, Loading