Loading Documentation/devicetree/bindings/bus/mhi.txt +80 −22 Original line number Diff line number Diff line Loading @@ -65,26 +65,6 @@ Main node properties: 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> Loading Loading @@ -115,6 +95,67 @@ Main node properties: Value type: <u32> Definition: Size of each segment to allocate for BHIe vector table ========================== mhi event node properties: ========================== - mhi,num-elements Usage: required Value type: <u32> Definition: Number of elements event ring support - mhi,intmod Usage: required Value type: <u32> Definition: interrupt moderation time in ms - mhi,msi Usage: required Value type: <u32> Definition: MSI associated with this event ring - mhi,chan Usage: optional Value type: <u32> Definition: Dedicated channel number, if it's a dedicated event ring - mhi,priority Usage: required Value type: <u32> Definition: Event ring priority, set to 1 for now - mhi,brstmode Usage: required Value type: <u32> Definition: Event doorbell mode configuration as defined by enum MHI_BRSTMODE 2 = burst mode disabled 3 = burst mode enabled - mhi,data-type Usage: optional Value type: <u32> Definition: Type of data this event ring will process as defined by enum mhi_er_data_type 0 = process data packets (default) 1 = process mhi control packets - mhi,hw-ev Usage: optional Value type: <bool> Definition: Event ring associated with hardware channels - mhi,client-manage Usage: optional Value type: <bool> Definition: Client manages the event ring (use by napi_poll) - mhi,offload Usage: optional Value type: <bool> Definition: Event ring associated with offload channel Children node properties: MHI drivers that require DT can add driver specific information as a child node. Loading @@ -133,8 +174,25 @@ mhi_controller { <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_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; mhi,msi = <1>; mhi,chan = <0>; mhi,priority = <1>; mhi,bstmode = <2>; mhi,data-type = <1>; }; mhi_event@1 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <2>; mhi,chan = <0>; mhi,priority = <1>; mhi,bstmode = <2>; }; mhi,fw-name = "sbl1.mbn"; mhi,timeout = <500>; Loading arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi 0 → 100644 +135 −0 Original line number Diff line number Diff line /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ &soc { mhi_0: qcom,mhi { /* controller specific configuration */ compatible = "qcom,mhi"; qcom,pci-domain = <1>; qcom,pci-bus = <1>; qcom,pci-slot = <0>; qcom,smmu-cfg = <0x3>; qcom,msm-bus,name = "mhi"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <100 512 0 0>, <100 512 1200000000 650000000>; /* 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_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; mhi,msi = <1>; mhi,priority = <1>; mhi,brstmode = <2>; mhi,data-type = <1>; }; mhi_event@1 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <2>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@2 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <3>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@3 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <4>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@4 { mhi,num-elements = <1024>; mhi,intmod = <5>; mhi,msi = <5>; mhi,chan = <100>; mhi,priority = <1>; mhi,brstmode = <3>; mhi,hw-ev; }; mhi_event@5 { mhi,num-elements = <1024>; mhi,intmod = <5>; mhi,msi = <6>; mhi,chan = <101>; mhi,priority = <1>; mhi,brstmode = <3>; mhi,hw-ev; mhi,client-manage; }; mhi_netdev_0: mhi_rmnet@0 { reg = <0x0>; mhi,chan = "IP_HW0"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; mhi_netdev_1: mhi_rmnet@1 { reg = <0x1>; mhi,chan = "IP_HW_ADPL"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; }; }; arch/arm64/boot/dts/qcom/sm8150.dtsi +1 −67 Original line number Diff line number Diff line Loading @@ -3525,73 +3525,6 @@ qcom,smmu-coherent; status = "disabled"; }; mhi_0: qcom,mhi@0 { /* controller specific configuration */ compatible = "qcom,mhi"; qcom,pci-domain = <1>; qcom,pci-bus = <1>; qcom,pci-slot = <0>; qcom,smmu-cfg = <0x3>; qcom,msm-bus,name = "mhi"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <100 512 0 0>, <100 512 1200000000 650000000>; /* 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 0x4>, <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,ev-cfg = <32 0 1 0 1 2 0x8>, <256 1 2 0 1 2 0>, <256 1 3 0 1 2 0>, <256 1 4 0 1 2 0>, <1024 5 5 100 1 3 0x1>, <1024 5 6 101 1 3 0x3>; mhi,timeout = <2000>; status = "disabled"; mhi_netdev_0: mhi_rmnet@0 { mhi,chan = "IP_HW0"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; mhi_netdev_1: mhi_rmnet@1 { mhi,chan = "IP_HW_ADPL"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; }; }; &emac_gdsc { Loading Loading @@ -3827,3 +3760,4 @@ #include "sm8150-thermal.dtsi" #include "sm8150-usb.dtsi" #include "sm8150-gpu.dtsi" #include "sm8150-mhi.dtsi" drivers/bus/mhi/core/mhi_dtr.c +62 −11 Original line number Diff line number Diff line Loading @@ -34,18 +34,30 @@ struct __packed dtr_ctrl_msg { #define CTRL_MAGIC (0x4C525443) #define CTRL_MSG_DTR BIT(0) #define CTRL_MSG_ID (0x10) #define CTRL_MSG_RTS BIT(1) #define CTRL_MSG_DCD BIT(0) #define CTRL_MSG_DSR BIT(1) #define CTRL_MSG_RI BIT(2) #define CTRL_HOST_STATE (0x10) #define CTRL_DEVICE_STATE (0x11) #define CTRL_GET_CHID(dtr) (dtr->dest_id & 0xFF) static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, struct mhi_device *mhi_dev, u32 tiocm) { struct dtr_ctrl_msg *dtr_msg = NULL; struct mhi_chan *dtr_chan = mhi_cntrl->dtr_dev->ul_chan; spinlock_t *res_lock = &mhi_dev->dev.devres_lock; u32 cur_tiocm; int ret = 0; tiocm &= TIOCM_DTR; if (mhi_chan->tiocm == tiocm) cur_tiocm = mhi_dev->tiocm & ~(TIOCM_CD | TIOCM_DSR | TIOCM_RI); tiocm &= (TIOCM_DTR | TIOCM_RTS); /* state did not changed */ if (cur_tiocm == tiocm) return 0; mutex_lock(&dtr_chan->mutex); Loading @@ -57,11 +69,13 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, } dtr_msg->preamble = CTRL_MAGIC; dtr_msg->msg_id = CTRL_MSG_ID; dtr_msg->dest_id = mhi_chan->chan; dtr_msg->msg_id = CTRL_HOST_STATE; dtr_msg->dest_id = mhi_dev->ul_chan_id; dtr_msg->size = sizeof(u32); if (tiocm & TIOCM_DTR) dtr_msg->msg |= CTRL_MSG_DTR; if (tiocm & TIOCM_RTS) dtr_msg->msg |= CTRL_MSG_RTS; reinit_completion(&dtr_chan->completion); ret = mhi_queue_transfer(mhi_cntrl->dtr_dev, DMA_TO_DEVICE, dtr_msg, Loading @@ -71,7 +85,6 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, ret = wait_for_completion_timeout(&dtr_chan->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (!ret) { MHI_ERR("Failed to receive transfer callback\n"); ret = -EIO; Loading @@ -79,7 +92,10 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, } ret = 0; mhi_chan->tiocm = tiocm; spin_lock_irq(res_lock); mhi_dev->tiocm &= ~(TIOCM_DTR | TIOCM_RTS); mhi_dev->tiocm |= tiocm; spin_unlock_irq(res_lock); tiocm_exit: kfree(dtr_msg); Loading @@ -91,7 +107,6 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_chan *mhi_chan = mhi_dev->ul_chan; int ret; /* ioctl not supported by this controller */ Loading @@ -100,7 +115,7 @@ long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCMGET: return mhi_chan->tiocm; return mhi_dev->tiocm; case TIOCMSET: { u32 tiocm; Loading @@ -109,7 +124,7 @@ long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) if (ret) return ret; return mhi_dtr_tiocmset(mhi_cntrl, mhi_chan, tiocm); return mhi_dtr_tiocmset(mhi_cntrl, mhi_dev, tiocm); } default: break; Loading @@ -122,6 +137,42 @@ EXPORT_SYMBOL(mhi_ioctl); static void mhi_dtr_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct dtr_ctrl_msg *dtr_msg = mhi_result->buf_addr; u32 chan; spinlock_t *res_lock; if (mhi_result->bytes_xferd != sizeof(*dtr_msg)) { MHI_ERR("Unexpected length %zu received\n", mhi_result->bytes_xferd); return; } MHI_VERB("preamble:0x%x msg_id:%u dest_id:%u msg:0x%x\n", dtr_msg->preamble, dtr_msg->msg_id, dtr_msg->dest_id, dtr_msg->msg); chan = CTRL_GET_CHID(dtr_msg); if (chan >= mhi_cntrl->max_chan) return; mhi_dev = mhi_cntrl->mhi_chan[chan].mhi_dev; if (!mhi_dev) return; res_lock = &mhi_dev->dev.devres_lock; spin_lock_irq(res_lock); mhi_dev->tiocm &= ~(TIOCM_CD | TIOCM_DSR | TIOCM_RI); if (dtr_msg->msg & CTRL_MSG_DCD) mhi_dev->tiocm |= TIOCM_CD; if (dtr_msg->msg & CTRL_MSG_DSR) mhi_dev->tiocm |= TIOCM_DSR; if (dtr_msg->msg & CTRL_MSG_RI) mhi_dev->tiocm |= TIOCM_RI; spin_unlock_irq(res_lock); } static void mhi_dtr_ul_xfer_cb(struct mhi_device *mhi_dev, Loading drivers/bus/mhi/core/mhi_init.c +71 −47 Original line number Diff line number Diff line Loading @@ -669,75 +669,99 @@ int mhi_device_configure(struct mhi_device *mhi_dev, static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { struct { u32 ev_cfg[MHI_EV_CFG_MAX]; } *ev_cfg; int num, i, ret; int i, ret, num = 0; struct mhi_event *mhi_event; u32 bit_cfg; struct device_node *child; num = of_property_count_elems_of_size(of_node, "mhi,ev-cfg", sizeof(*ev_cfg)); if (num <= 0) return -EINVAL; for_each_available_child_of_node(of_node, child) { if (!strcmp(child->name, "mhi_event")) num++; } ev_cfg = kcalloc(num, sizeof(*ev_cfg), GFP_KERNEL); if (!ev_cfg) return -ENOMEM; if (!num) return -EINVAL; mhi_cntrl->total_ev_rings = num; mhi_cntrl->mhi_event = kcalloc(num, sizeof(*mhi_cntrl->mhi_event), GFP_KERNEL); if (!mhi_cntrl->mhi_event) { kfree(ev_cfg); if (!mhi_cntrl->mhi_event) return -ENOMEM; } ret = of_property_read_u32_array(of_node, "mhi,ev-cfg", (u32 *)ev_cfg, num * sizeof(*ev_cfg) / sizeof(u32)); /* populate ev ring */ mhi_event = mhi_cntrl->mhi_event; i = 0; for_each_available_child_of_node(of_node, child) { if (strcmp(child->name, "mhi_event")) continue; mhi_event->er_index = i++; ret = of_property_read_u32(child, "mhi,num-elements", (u32 *)&mhi_event->ring.elements); if (ret) goto error_ev_cfg; /* populate ev ring */ mhi_event = mhi_cntrl->mhi_event; for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { mhi_event->er_index = i; mhi_event->ring.elements = ev_cfg[i].ev_cfg[MHI_EV_CFG_ELEMENTS]; mhi_event->intmod = ev_cfg[i].ev_cfg[MHI_EV_CFG_INTMOD]; mhi_event->msi = ev_cfg[i].ev_cfg[MHI_EV_CFG_MSI]; mhi_event->chan = ev_cfg[i].ev_cfg[MHI_EV_CFG_CHAN]; if (mhi_event->chan >= mhi_cntrl->max_chan) ret = of_property_read_u32(child, "mhi,intmod", &mhi_event->intmod); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,msi", &mhi_event->msi); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,chan", &mhi_event->chan); if (!ret) { if (mhi_event->chan >= mhi_cntrl->max_chan) goto error_ev_cfg; /* this event ring has a dedicated channel */ if (mhi_event->chan) mhi_event->mhi_chan = &mhi_cntrl->mhi_chan[mhi_event->chan]; } mhi_event->priority = ev_cfg[i].ev_cfg[MHI_EV_CFG_PRIORITY]; mhi_event->db_cfg.brstmode = ev_cfg[i].ev_cfg[MHI_EV_CFG_BRSTMODE]; if (MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode)) ret = of_property_read_u32(child, "mhi,priority", &mhi_event->priority); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,brstmode", &mhi_event->db_cfg.brstmode); if (ret || MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode)) goto error_ev_cfg; mhi_event->db_cfg.process_db = (mhi_event->db_cfg.brstmode == MHI_BRSTMODE_ENABLE) ? mhi_db_brstmode : mhi_db_brstmode_disable; bit_cfg = ev_cfg[i].ev_cfg[MHI_EV_CFG_BITCFG]; if (bit_cfg & MHI_EV_CFG_BIT_HW_EV) { mhi_event->hw_ring = true; mhi_cntrl->hw_ev_rings++; } else mhi_cntrl->sw_ev_rings++; ret = of_property_read_u32(child, "mhi,data-type", &mhi_event->data_type); if (ret) mhi_event->data_type = MHI_ER_DATA_ELEMENT_TYPE; mhi_event->cl_manage = !!(bit_cfg & MHI_EV_CFG_BIT_CL_MANAGE); mhi_event->offload_ev = !!(bit_cfg & MHI_EV_CFG_BIT_OFFLOAD_EV); mhi_event->ctrl_ev = !!(bit_cfg & MHI_EV_CFG_BIT_CTRL_EV); if (mhi_event->data_type > MHI_ER_DATA_TYPE_MAX) goto error_ev_cfg; switch (mhi_event->data_type) { case MHI_ER_DATA_ELEMENT_TYPE: mhi_event->process_event = mhi_process_data_event_ring; break; case MHI_ER_CTRL_ELEMENT_TYPE: mhi_event->process_event = mhi_process_ctrl_ev_ring; break; } kfree(ev_cfg); mhi_event->hw_ring = of_property_read_bool(child, "mhi,hw-ev"); if (mhi_event->hw_ring) mhi_cntrl->hw_ev_rings++; else mhi_cntrl->sw_ev_rings++; mhi_event->cl_manage = of_property_read_bool(child, "mhi,client-manage"); mhi_event->offload_ev = of_property_read_bool(child, "mhi,offload"); mhi_event++; } /* we need msi for each event ring + additional one for BHI */ mhi_cntrl->msi_required = mhi_cntrl->total_ev_rings + 1; Loading @@ -745,7 +769,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, return 0; error_ev_cfg: kfree(ev_cfg); kfree(mhi_cntrl->mhi_event); return -EINVAL; } Loading Loading @@ -977,7 +1001,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) mhi_event->mhi_cntrl = mhi_cntrl; spin_lock_init(&mhi_event->lock); if (mhi_event->ctrl_ev) if (mhi_event->data_type == MHI_ER_CTRL_ELEMENT_TYPE) tasklet_init(&mhi_event->task, mhi_ctrl_ev_task, (ulong)mhi_event); else Loading Loading
Documentation/devicetree/bindings/bus/mhi.txt +80 −22 Original line number Diff line number Diff line Loading @@ -65,26 +65,6 @@ Main node properties: 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> Loading Loading @@ -115,6 +95,67 @@ Main node properties: Value type: <u32> Definition: Size of each segment to allocate for BHIe vector table ========================== mhi event node properties: ========================== - mhi,num-elements Usage: required Value type: <u32> Definition: Number of elements event ring support - mhi,intmod Usage: required Value type: <u32> Definition: interrupt moderation time in ms - mhi,msi Usage: required Value type: <u32> Definition: MSI associated with this event ring - mhi,chan Usage: optional Value type: <u32> Definition: Dedicated channel number, if it's a dedicated event ring - mhi,priority Usage: required Value type: <u32> Definition: Event ring priority, set to 1 for now - mhi,brstmode Usage: required Value type: <u32> Definition: Event doorbell mode configuration as defined by enum MHI_BRSTMODE 2 = burst mode disabled 3 = burst mode enabled - mhi,data-type Usage: optional Value type: <u32> Definition: Type of data this event ring will process as defined by enum mhi_er_data_type 0 = process data packets (default) 1 = process mhi control packets - mhi,hw-ev Usage: optional Value type: <bool> Definition: Event ring associated with hardware channels - mhi,client-manage Usage: optional Value type: <bool> Definition: Client manages the event ring (use by napi_poll) - mhi,offload Usage: optional Value type: <bool> Definition: Event ring associated with offload channel Children node properties: MHI drivers that require DT can add driver specific information as a child node. Loading @@ -133,8 +174,25 @@ mhi_controller { <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_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; mhi,msi = <1>; mhi,chan = <0>; mhi,priority = <1>; mhi,bstmode = <2>; mhi,data-type = <1>; }; mhi_event@1 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <2>; mhi,chan = <0>; mhi,priority = <1>; mhi,bstmode = <2>; }; mhi,fw-name = "sbl1.mbn"; mhi,timeout = <500>; Loading
arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi 0 → 100644 +135 −0 Original line number Diff line number Diff line /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ &soc { mhi_0: qcom,mhi { /* controller specific configuration */ compatible = "qcom,mhi"; qcom,pci-domain = <1>; qcom,pci-bus = <1>; qcom,pci-slot = <0>; qcom,smmu-cfg = <0x3>; qcom,msm-bus,name = "mhi"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <100 512 0 0>, <100 512 1200000000 650000000>; /* 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_event@0 { mhi,num-elements = <32>; mhi,intmod = <1>; mhi,msi = <1>; mhi,priority = <1>; mhi,brstmode = <2>; mhi,data-type = <1>; }; mhi_event@1 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <2>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@2 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <3>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@3 { mhi,num-elements = <256>; mhi,intmod = <1>; mhi,msi = <4>; mhi,priority = <1>; mhi,brstmode = <2>; }; mhi_event@4 { mhi,num-elements = <1024>; mhi,intmod = <5>; mhi,msi = <5>; mhi,chan = <100>; mhi,priority = <1>; mhi,brstmode = <3>; mhi,hw-ev; }; mhi_event@5 { mhi,num-elements = <1024>; mhi,intmod = <5>; mhi,msi = <6>; mhi,chan = <101>; mhi,priority = <1>; mhi,brstmode = <3>; mhi,hw-ev; mhi,client-manage; }; mhi_netdev_0: mhi_rmnet@0 { reg = <0x0>; mhi,chan = "IP_HW0"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; mhi_netdev_1: mhi_rmnet@1 { reg = <0x1>; mhi,chan = "IP_HW_ADPL"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; }; };
arch/arm64/boot/dts/qcom/sm8150.dtsi +1 −67 Original line number Diff line number Diff line Loading @@ -3525,73 +3525,6 @@ qcom,smmu-coherent; status = "disabled"; }; mhi_0: qcom,mhi@0 { /* controller specific configuration */ compatible = "qcom,mhi"; qcom,pci-domain = <1>; qcom,pci-bus = <1>; qcom,pci-slot = <0>; qcom,smmu-cfg = <0x3>; qcom,msm-bus,name = "mhi"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <100 512 0 0>, <100 512 1200000000 650000000>; /* 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 0x4>, <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,ev-cfg = <32 0 1 0 1 2 0x8>, <256 1 2 0 1 2 0>, <256 1 3 0 1 2 0>, <256 1 4 0 1 2 0>, <1024 5 5 100 1 3 0x1>, <1024 5 6 101 1 3 0x3>; mhi,timeout = <2000>; status = "disabled"; mhi_netdev_0: mhi_rmnet@0 { mhi,chan = "IP_HW0"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; mhi_netdev_1: mhi_rmnet@1 { mhi,chan = "IP_HW_ADPL"; mhi,interface-name = "rmnet_mhi"; mhi,mru = <0x4000>; }; }; }; &emac_gdsc { Loading Loading @@ -3827,3 +3760,4 @@ #include "sm8150-thermal.dtsi" #include "sm8150-usb.dtsi" #include "sm8150-gpu.dtsi" #include "sm8150-mhi.dtsi"
drivers/bus/mhi/core/mhi_dtr.c +62 −11 Original line number Diff line number Diff line Loading @@ -34,18 +34,30 @@ struct __packed dtr_ctrl_msg { #define CTRL_MAGIC (0x4C525443) #define CTRL_MSG_DTR BIT(0) #define CTRL_MSG_ID (0x10) #define CTRL_MSG_RTS BIT(1) #define CTRL_MSG_DCD BIT(0) #define CTRL_MSG_DSR BIT(1) #define CTRL_MSG_RI BIT(2) #define CTRL_HOST_STATE (0x10) #define CTRL_DEVICE_STATE (0x11) #define CTRL_GET_CHID(dtr) (dtr->dest_id & 0xFF) static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, struct mhi_device *mhi_dev, u32 tiocm) { struct dtr_ctrl_msg *dtr_msg = NULL; struct mhi_chan *dtr_chan = mhi_cntrl->dtr_dev->ul_chan; spinlock_t *res_lock = &mhi_dev->dev.devres_lock; u32 cur_tiocm; int ret = 0; tiocm &= TIOCM_DTR; if (mhi_chan->tiocm == tiocm) cur_tiocm = mhi_dev->tiocm & ~(TIOCM_CD | TIOCM_DSR | TIOCM_RI); tiocm &= (TIOCM_DTR | TIOCM_RTS); /* state did not changed */ if (cur_tiocm == tiocm) return 0; mutex_lock(&dtr_chan->mutex); Loading @@ -57,11 +69,13 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, } dtr_msg->preamble = CTRL_MAGIC; dtr_msg->msg_id = CTRL_MSG_ID; dtr_msg->dest_id = mhi_chan->chan; dtr_msg->msg_id = CTRL_HOST_STATE; dtr_msg->dest_id = mhi_dev->ul_chan_id; dtr_msg->size = sizeof(u32); if (tiocm & TIOCM_DTR) dtr_msg->msg |= CTRL_MSG_DTR; if (tiocm & TIOCM_RTS) dtr_msg->msg |= CTRL_MSG_RTS; reinit_completion(&dtr_chan->completion); ret = mhi_queue_transfer(mhi_cntrl->dtr_dev, DMA_TO_DEVICE, dtr_msg, Loading @@ -71,7 +85,6 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, ret = wait_for_completion_timeout(&dtr_chan->completion, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (!ret) { MHI_ERR("Failed to receive transfer callback\n"); ret = -EIO; Loading @@ -79,7 +92,10 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, } ret = 0; mhi_chan->tiocm = tiocm; spin_lock_irq(res_lock); mhi_dev->tiocm &= ~(TIOCM_DTR | TIOCM_RTS); mhi_dev->tiocm |= tiocm; spin_unlock_irq(res_lock); tiocm_exit: kfree(dtr_msg); Loading @@ -91,7 +107,6 @@ static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl, long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_chan *mhi_chan = mhi_dev->ul_chan; int ret; /* ioctl not supported by this controller */ Loading @@ -100,7 +115,7 @@ long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCMGET: return mhi_chan->tiocm; return mhi_dev->tiocm; case TIOCMSET: { u32 tiocm; Loading @@ -109,7 +124,7 @@ long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) if (ret) return ret; return mhi_dtr_tiocmset(mhi_cntrl, mhi_chan, tiocm); return mhi_dtr_tiocmset(mhi_cntrl, mhi_dev, tiocm); } default: break; Loading @@ -122,6 +137,42 @@ EXPORT_SYMBOL(mhi_ioctl); static void mhi_dtr_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct dtr_ctrl_msg *dtr_msg = mhi_result->buf_addr; u32 chan; spinlock_t *res_lock; if (mhi_result->bytes_xferd != sizeof(*dtr_msg)) { MHI_ERR("Unexpected length %zu received\n", mhi_result->bytes_xferd); return; } MHI_VERB("preamble:0x%x msg_id:%u dest_id:%u msg:0x%x\n", dtr_msg->preamble, dtr_msg->msg_id, dtr_msg->dest_id, dtr_msg->msg); chan = CTRL_GET_CHID(dtr_msg); if (chan >= mhi_cntrl->max_chan) return; mhi_dev = mhi_cntrl->mhi_chan[chan].mhi_dev; if (!mhi_dev) return; res_lock = &mhi_dev->dev.devres_lock; spin_lock_irq(res_lock); mhi_dev->tiocm &= ~(TIOCM_CD | TIOCM_DSR | TIOCM_RI); if (dtr_msg->msg & CTRL_MSG_DCD) mhi_dev->tiocm |= TIOCM_CD; if (dtr_msg->msg & CTRL_MSG_DSR) mhi_dev->tiocm |= TIOCM_DSR; if (dtr_msg->msg & CTRL_MSG_RI) mhi_dev->tiocm |= TIOCM_RI; spin_unlock_irq(res_lock); } static void mhi_dtr_ul_xfer_cb(struct mhi_device *mhi_dev, Loading
drivers/bus/mhi/core/mhi_init.c +71 −47 Original line number Diff line number Diff line Loading @@ -669,75 +669,99 @@ int mhi_device_configure(struct mhi_device *mhi_dev, static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, struct device_node *of_node) { struct { u32 ev_cfg[MHI_EV_CFG_MAX]; } *ev_cfg; int num, i, ret; int i, ret, num = 0; struct mhi_event *mhi_event; u32 bit_cfg; struct device_node *child; num = of_property_count_elems_of_size(of_node, "mhi,ev-cfg", sizeof(*ev_cfg)); if (num <= 0) return -EINVAL; for_each_available_child_of_node(of_node, child) { if (!strcmp(child->name, "mhi_event")) num++; } ev_cfg = kcalloc(num, sizeof(*ev_cfg), GFP_KERNEL); if (!ev_cfg) return -ENOMEM; if (!num) return -EINVAL; mhi_cntrl->total_ev_rings = num; mhi_cntrl->mhi_event = kcalloc(num, sizeof(*mhi_cntrl->mhi_event), GFP_KERNEL); if (!mhi_cntrl->mhi_event) { kfree(ev_cfg); if (!mhi_cntrl->mhi_event) return -ENOMEM; } ret = of_property_read_u32_array(of_node, "mhi,ev-cfg", (u32 *)ev_cfg, num * sizeof(*ev_cfg) / sizeof(u32)); /* populate ev ring */ mhi_event = mhi_cntrl->mhi_event; i = 0; for_each_available_child_of_node(of_node, child) { if (strcmp(child->name, "mhi_event")) continue; mhi_event->er_index = i++; ret = of_property_read_u32(child, "mhi,num-elements", (u32 *)&mhi_event->ring.elements); if (ret) goto error_ev_cfg; /* populate ev ring */ mhi_event = mhi_cntrl->mhi_event; for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { mhi_event->er_index = i; mhi_event->ring.elements = ev_cfg[i].ev_cfg[MHI_EV_CFG_ELEMENTS]; mhi_event->intmod = ev_cfg[i].ev_cfg[MHI_EV_CFG_INTMOD]; mhi_event->msi = ev_cfg[i].ev_cfg[MHI_EV_CFG_MSI]; mhi_event->chan = ev_cfg[i].ev_cfg[MHI_EV_CFG_CHAN]; if (mhi_event->chan >= mhi_cntrl->max_chan) ret = of_property_read_u32(child, "mhi,intmod", &mhi_event->intmod); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,msi", &mhi_event->msi); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,chan", &mhi_event->chan); if (!ret) { if (mhi_event->chan >= mhi_cntrl->max_chan) goto error_ev_cfg; /* this event ring has a dedicated channel */ if (mhi_event->chan) mhi_event->mhi_chan = &mhi_cntrl->mhi_chan[mhi_event->chan]; } mhi_event->priority = ev_cfg[i].ev_cfg[MHI_EV_CFG_PRIORITY]; mhi_event->db_cfg.brstmode = ev_cfg[i].ev_cfg[MHI_EV_CFG_BRSTMODE]; if (MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode)) ret = of_property_read_u32(child, "mhi,priority", &mhi_event->priority); if (ret) goto error_ev_cfg; ret = of_property_read_u32(child, "mhi,brstmode", &mhi_event->db_cfg.brstmode); if (ret || MHI_INVALID_BRSTMODE(mhi_event->db_cfg.brstmode)) goto error_ev_cfg; mhi_event->db_cfg.process_db = (mhi_event->db_cfg.brstmode == MHI_BRSTMODE_ENABLE) ? mhi_db_brstmode : mhi_db_brstmode_disable; bit_cfg = ev_cfg[i].ev_cfg[MHI_EV_CFG_BITCFG]; if (bit_cfg & MHI_EV_CFG_BIT_HW_EV) { mhi_event->hw_ring = true; mhi_cntrl->hw_ev_rings++; } else mhi_cntrl->sw_ev_rings++; ret = of_property_read_u32(child, "mhi,data-type", &mhi_event->data_type); if (ret) mhi_event->data_type = MHI_ER_DATA_ELEMENT_TYPE; mhi_event->cl_manage = !!(bit_cfg & MHI_EV_CFG_BIT_CL_MANAGE); mhi_event->offload_ev = !!(bit_cfg & MHI_EV_CFG_BIT_OFFLOAD_EV); mhi_event->ctrl_ev = !!(bit_cfg & MHI_EV_CFG_BIT_CTRL_EV); if (mhi_event->data_type > MHI_ER_DATA_TYPE_MAX) goto error_ev_cfg; switch (mhi_event->data_type) { case MHI_ER_DATA_ELEMENT_TYPE: mhi_event->process_event = mhi_process_data_event_ring; break; case MHI_ER_CTRL_ELEMENT_TYPE: mhi_event->process_event = mhi_process_ctrl_ev_ring; break; } kfree(ev_cfg); mhi_event->hw_ring = of_property_read_bool(child, "mhi,hw-ev"); if (mhi_event->hw_ring) mhi_cntrl->hw_ev_rings++; else mhi_cntrl->sw_ev_rings++; mhi_event->cl_manage = of_property_read_bool(child, "mhi,client-manage"); mhi_event->offload_ev = of_property_read_bool(child, "mhi,offload"); mhi_event++; } /* we need msi for each event ring + additional one for BHI */ mhi_cntrl->msi_required = mhi_cntrl->total_ev_rings + 1; Loading @@ -745,7 +769,7 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl, return 0; error_ev_cfg: kfree(ev_cfg); kfree(mhi_cntrl->mhi_event); return -EINVAL; } Loading Loading @@ -977,7 +1001,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) mhi_event->mhi_cntrl = mhi_cntrl; spin_lock_init(&mhi_event->lock); if (mhi_event->ctrl_ev) if (mhi_event->data_type == MHI_ER_CTRL_ELEMENT_TYPE) tasklet_init(&mhi_event->task, mhi_ctrl_ev_task, (ulong)mhi_event); else Loading