Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions drivers/bus/mhi/host/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,29 @@ const char *to_mhi_pm_state_str(u32 state)
return mhi_pm_state_str[index];
}

static ssize_t fw_update_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mhi_device *mhi_dev = to_mhi_device(dev);
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;

return sysfs_emit(buf, "%u\n", mhi_cntrl->xfp);
}

static ssize_t fw_update_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
{
struct mhi_device *mhi_dev = to_mhi_device(dev);
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
bool enable;

if (strtobool(buf, &enable))
return -EINVAL;

mhi_cntrl->xfp = enable ? XFP_STATE_FLASHING : XFP_STATE_NEED_RESET;

return len;
}
static DEVICE_ATTR_RW(fw_update);

static ssize_t serial_number_show(struct device *dev,
struct device_attribute *attr,
char *buf)
Expand Down Expand Up @@ -124,6 +147,7 @@ static struct attribute *mhi_dev_attrs[] = {
&dev_attr_serial_number.attr,
&dev_attr_oem_pk_hash.attr,
&dev_attr_soc_reset.attr,
&dev_attr_fw_update.attr,
NULL,
};
ATTRIBUTE_GROUPS(mhi_dev);
Expand Down
2 changes: 1 addition & 1 deletion drivers/bus/mhi/host/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ extern const char * const mhi_ee_str[MHI_EE_MAX];

#define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \
ee == MHI_EE_EDL)
#define MHI_POWER_UP_CAPABLE(ee) (MHI_IN_PBL(ee) || ee == MHI_EE_AMSS)
#define MHI_POWER_UP_CAPABLE(ee) (MHI_IN_PBL(ee) || ee == MHI_EE_AMSS || ee == MHI_EE_SBL)
#define MHI_FW_LOAD_CAPABLE(ee) (ee == MHI_EE_PBL || ee == MHI_EE_EDL)
#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW || \
ee == MHI_EE_FP)
Expand Down
11 changes: 11 additions & 0 deletions drivers/bus/mhi/host/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ int mhi_destroy_device(struct device *dev, void *data)
dev_dbg(&mhi_cntrl->mhi_dev->dev, "destroy device for chan:%s\n",
mhi_dev->name);

if (!strcmp(mhi_dev->name, "IP_CTRL")) {
dev_dbg(dev, "destroying IP_CTRL\n");
mhi_cntrl->mhi_dev_ip_ctrl = NULL;
}

/* Notify the client and remove the device from MHI bus */
device_del(dev);
put_device(dev);
Expand Down Expand Up @@ -423,6 +428,12 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
ret = device_add(&mhi_dev->dev);
if (ret)
put_device(&mhi_dev->dev);
else {
if (!strcmp(mhi_dev->name, "IP_CTRL")) {
dev_dbg(dev, "IP_CTRL supported\n");
mhi_cntrl->mhi_dev_ip_ctrl = mhi_dev;
}
}
}
}

Expand Down
109 changes: 103 additions & 6 deletions drivers/bus/mhi/host/pci_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#define MHI_POST_RESET_DELAY_MS 2000

#define HEALTH_CHECK_PERIOD (HZ * 2)
#define HEALTH_CHECK_PERIOD (HZ / 2)

/* PCI VID definitions */
#define PCI_VENDOR_ID_THALES 0x1269
Expand Down Expand Up @@ -50,6 +50,36 @@ struct mhi_pci_dev_info {
bool sideband_wake;
};

#define MHI_CHANNEL_CONFIG_AMSS_SBL_UL(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
.name = ch_name, \
.num_elements = el_count, \
.event_ring = ev_ring, \
.dir = DMA_TO_DEVICE, \
.ee_mask = BIT(MHI_EE_SBL) | BIT(MHI_EE_AMSS), \
.pollcfg = 0, \
.doorbell = MHI_DB_BRST_DISABLE, \
.lpm_notify = false, \
.offload_channel = false, \
.doorbell_mode_switch = false, \
} \

#define MHI_CHANNEL_CONFIG_AMSS_SBL_DL(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
.name = ch_name, \
.num_elements = el_count, \
.event_ring = ev_ring, \
.dir = DMA_FROM_DEVICE, \
.ee_mask = BIT(MHI_EE_SBL) | BIT(MHI_EE_AMSS), \
.pollcfg = 0, \
.doorbell = MHI_DB_BRST_DISABLE, \
.lpm_notify = false, \
.offload_channel = false, \
.doorbell_mode_switch = false, \
}

#define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
Expand Down Expand Up @@ -538,17 +568,69 @@ static const struct mhi_pci_dev_info mhi_telit_fn980_hw_v1_info = {
.sideband_wake = false,
};

static const struct mhi_channel_config mhi_telit_fn980_hw_v2_channels[] = {
MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
MHI_CHANNEL_CONFIG_AMSS_SBL_UL(4, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_AMSS_SBL_DL(5, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_UL(18, "IP_CTRL", 8, 1),
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(19, "IP_CTRL", 8, 1),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_UL(32, "DUN", 8, 1),
MHI_CHANNEL_CONFIG_DL(33, "DUN", 8, 1),
MHI_CHANNEL_CONFIG_UL(92, "DUN2", 8, 1),
MHI_CHANNEL_CONFIG_DL(93, "DUN2", 8, 1),
MHI_CHANNEL_CONFIG_UL(94, "NMEA", 8, 1),
MHI_CHANNEL_CONFIG_DL(95, "NMEA", 8, 1),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
};

static struct mhi_event_config mhi_telit_fn980_hw_v2_events[] = {
MHI_EVENT_CONFIG_CTRL(0, 128),
MHI_EVENT_CONFIG_DATA(1, 128),
MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101),
};

static struct mhi_controller_config modem_telit_fn980_hw_v2_config = {
.max_channels = 128,
.timeout_ms = 20000,
.num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v2_channels),
.ch_cfg = mhi_telit_fn980_hw_v2_channels,
.num_events = ARRAY_SIZE(mhi_telit_fn980_hw_v2_events),
.event_cfg = mhi_telit_fn980_hw_v2_events,
};

static const struct mhi_pci_dev_info mhi_telit_fn980_hw_v2_info = {
.name = "telit-fn980",
.fw = "qcom/sdx55m/sbl1.mbn",
.edl = "qcom/sdx55m/edl.mbn",
.config = &modem_telit_fn980_hw_v2_config,
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
.dma_data_width = 32,
.mru_default = 32768,
.sideband_wake = false,
};

static const struct mhi_channel_config mhi_telit_fn990_channels[] = {
MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_AMSS_SBL_UL(4, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_AMSS_SBL_DL(5, "DIAG", 64, 1),
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
MHI_CHANNEL_CONFIG_UL(18, "IP_CTRL", 8, 1),
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(19, "IP_CTRL", 8, 1),
MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
MHI_CHANNEL_CONFIG_UL(94, "NMEA", 8, 1),
MHI_CHANNEL_CONFIG_DL(95, "NMEA", 8, 1),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
};
Expand Down Expand Up @@ -582,16 +664,15 @@ static const struct mhi_pci_dev_info mhi_telit_fn990_info = {
static const struct pci_device_id mhi_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c),
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
/* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200),
.driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info },
/* Telit FN980 hardware revision v1 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000),
.driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info },
/* Modified Qualcomm default entry for FN980 firmware release without Telit SSIDs */
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info },
.driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v2_info },
/* Telit FN990 */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2010),
.driver_data = (kernel_ulong_t) &mhi_telit_fn990_info },
Expand Down Expand Up @@ -859,6 +940,10 @@ static void mhi_pci_recovery_work(struct work_struct *work)
mhi_unprepare_after_power_down(mhi_cntrl);
}

dev_dbg(&pdev->dev, "Waiting 40 seconds for allowing the modem to restore PCIe\n");
msleep(40000);
dev_dbg(&pdev->dev, "Restoring PCI saved state\n");

pci_set_power_state(pdev, PCI_D0);
pci_load_saved_state(pdev, mhi_pdev->pci_state);
pci_restore_state(pdev);
Expand Down Expand Up @@ -896,6 +981,18 @@ static void health_check(struct timer_list *t)
test_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status))
return;

if (mhi_cntrl->xfp == XFP_STATE_FLASHING) {
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
return;
}

if (mhi_cntrl->xfp == XFP_STATE_NEED_RESET) {
mhi_cntrl->xfp = XFP_STATE_IDLE;
dev_dbg(mhi_cntrl->cntrl_dev, "Device needs to be resetted EE = %d\n", mhi_cntrl->ee);
queue_work(system_long_wq, &mhi_pdev->recovery_work);
return;
}

if (!mhi_pci_is_alive(mhi_cntrl)) {
dev_err(mhi_cntrl->cntrl_dev, "Device died\n");
queue_work(system_long_wq, &mhi_pdev->recovery_work);
Expand Down
3 changes: 2 additions & 1 deletion drivers/bus/mhi/host/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1208,10 +1208,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)

wait_event_timeout(mhi_cntrl->state_event,
MHI_IN_MISSION_MODE(mhi_cntrl->ee) ||
mhi_cntrl->ee == MHI_EE_SBL ||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
msecs_to_jiffies(mhi_cntrl->timeout_ms));

ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee) || mhi_cntrl->ee == MHI_EE_SBL) ? 0 : -ETIMEDOUT;
if (ret)
mhi_power_down(mhi_cntrl, false);

Expand Down
11 changes: 11 additions & 0 deletions drivers/net/wwan/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ config WWAN_HWSIM
config MHI_WWAN_CTRL
tristate "MHI WWAN control driver for QCOM-based PCIe modems"
depends on MHI_BUS
select MHI_WWAN_DTR
help
MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem
control protocols/ports to userspace, including AT, MBIM, QMI, DIAG
Expand All @@ -49,6 +50,16 @@ config MHI_WWAN_CTRL
To compile this driver as a module, choose M here: the module will be
called mhi_wwan_ctrl.

config MHI_WWAN_DTR
tristate "MHI WWAN DTR driver for QCOM-based PCIe modems"
depends on MHI_BUS
help
MHI WWAN DTR allows to set DTR and RTS signals on QCOM-based PCIe
DUN ports.

To compile this driver as a module, choose M here: the module will be
called mhi_wwan_dtr.

config MHI_WWAN_MBIM
tristate "MHI WWAN MBIM network driver for QCOM-based PCIe modems"
depends on MHI_BUS
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wwan/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ wwan-objs += wwan_core.o

obj-$(CONFIG_WWAN_HWSIM) += wwan_hwsim.o

obj-$(CONFIG_MHI_WWAN_DTR) += mhi_wwan_dtr.o
obj-$(CONFIG_MHI_WWAN_CTRL) += mhi_wwan_ctrl.o
obj-$(CONFIG_MHI_WWAN_MBIM) += mhi_wwan_mbim.o
obj-$(CONFIG_QCOM_BAM_DMUX) += qcom_bam_dmux.o
Expand Down
16 changes: 15 additions & 1 deletion drivers/net/wwan/mhi_wwan_ctrl.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2021, Linaro Ltd <loic.poulain@linaro.org> */
/* Copyright (c) 2023, Linaro Ltd <loic.poulain@linaro.org> */
#include <linux/kernel.h>
#include <linux/mhi.h>
#include <linux/mod_devicetable.h>
Expand Down Expand Up @@ -104,6 +104,8 @@ static void mhi_wwan_ctrl_refill_work(struct work_struct *work)
}
}

int mhi_wwan_dtr_set(struct wwan_port *port, int dtr, int rts);

static int mhi_wwan_ctrl_start(struct wwan_port *port)
{
struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port);
Expand All @@ -123,13 +125,23 @@ static int mhi_wwan_ctrl_start(struct wwan_port *port)
mhi_wwan_ctrl_refill_work(&mhiwwan->rx_refill);
}

if (wwan_port_get_type(port) == WWAN_PORT_AT) {
dev_dbg(&mhiwwan->mhi_dev->dev, "Setting DTR and RTS for port\n");
mhi_wwan_dtr_set(port, 1, 1);
}

return 0;
}

static void mhi_wwan_ctrl_stop(struct wwan_port *port)
{
struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port);

if (wwan_port_get_type(port) == WWAN_PORT_AT) {
dev_dbg(&mhiwwan->mhi_dev->dev, "Unsetting DTR and RTS for port\n");
mhi_wwan_dtr_set(port, 0, 0);
}

spin_lock_bh(&mhiwwan->rx_lock);
clear_bit(MHI_WWAN_RX_REFILL, &mhiwwan->flags);
spin_unlock_bh(&mhiwwan->rx_lock);
Expand Down Expand Up @@ -263,6 +275,8 @@ static const struct mhi_device_id mhi_wwan_ctrl_match_table[] = {
{ .chan = "QMI", .driver_data = WWAN_PORT_QMI },
{ .chan = "DIAG", .driver_data = WWAN_PORT_QCDM },
{ .chan = "FIREHOSE", .driver_data = WWAN_PORT_FIREHOSE },
{ .chan = "SAHARA", .driver_data = WWAN_PORT_SAHARA },
{ .chan = "NMEA", .driver_data = WWAN_PORT_NMEA },
{},
};
MODULE_DEVICE_TABLE(mhi, mhi_wwan_ctrl_match_table);
Expand Down
Loading