Skip to content

Commit 31d8df9

Browse files
committed
Merge tag 'mhi-for-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi into char-misc-next
Manivannan writes: MHI changes for v5.13 core: - Added support for Flash Programmer execution environment which allows the host machine (like x86) to flash the modem firmware to NAND or eMMC in the modem. The MHI bus will expose EDL channels (34, 35) and then the opensource QDL tool [1] can be used to flash the firmware from the host. - Added an internal helper for polling the MHI registers with a retry interval. This helper is used now to poll for the MHI ready state in MHI STATUS register. - Various fixes for issues found during the bringup of SDX24/SDX55 based Quectel and Telit modems. - Updates to the Execution environment handling for proper downloading of the AMSS image from SBL (Secondary Bootloader) mode. - Added support for sending STOP channel command to the MHI device and also made changes to the MHI core for proper handling of stop and restart. - Fixed the runtime_pm handling in the core by forcing the device to be in wake mode until TX completion and allowing it to suspend for RX. - Added sanity checks for values read from the device to avoid crash if those are corrupted somehow. - Fixed warnings generated by sparse (W=2) - Couple of kernel doc cleanups in mhi.h pci_generic: - Added support for runtime PM and generic PM - Added Firehose channels for flashing the firmware - Added support for modems such as Quectel EM1XXGR-L, SDX24, SDX65, Foxconn T99W175 exposing relevant channels. [1] https://git.linaro.org/landing-teams/working/qualcomm/qdl.git * tag 'mhi-for-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mani/mhi: (49 commits) bus: mhi: fix typo in comments for struct mhi_channel_config bus: mhi: core: Fix shadow declarations bus: mhi: pci_generic: Constify mhi_controller_config struct definitions bus: mhi: pci_generic: Introduce Foxconn T99W175 support bus: mhi: core: Sanity check values from remote device before use bus: mhi: pci_generic: Add FIREHOSE channels bus: mhi: pci_generic: Implement PCI shutdown callback bus: mhi: Improve documentation on channel transfer setup APIs bus: mhi: core: Remove __ prefix for MHI channel unprepare function bus: mhi: core: Check channel execution environment before issuing reset bus: mhi: core: Clear configuration from channel context during reset bus: mhi: core: Hold device wake for channel update commands bus: mhi: core: Update debug messages to use client device bus: mhi: core: Improvements to the channel handling state machine bus: mhi: core: Clear context for stopped channels from remove() bus: mhi: core: Allow sending the STOP channel command bus: mhi: pci_generic: Add SDX65 based modem support bus: mhi: core: Remove pre_init flag used for power purposes bus: mhi: pm: reduce PM state change verbosity bus: mhi: core: Fix MHI runtime_pm behavior ...
2 parents aa87e31 + a503d16 commit 31d8df9

File tree

8 files changed

+775
-276
lines changed

8 files changed

+775
-276
lines changed

drivers/bus/mhi/core/boot.c

+31-33
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,6 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
389389
void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
390390
{
391391
const struct firmware *firmware = NULL;
392-
struct image_info *image_info;
393392
struct device *dev = &mhi_cntrl->mhi_dev->dev;
394393
const char *fw_name;
395394
void *buf;
@@ -417,9 +416,9 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
417416
}
418417
}
419418

420-
/* If device is in pass through, do reset to ready state transition */
421-
if (mhi_cntrl->ee == MHI_EE_PTHRU)
422-
goto fw_load_ee_pthru;
419+
/* wait for ready on pass through or any other execution environment */
420+
if (mhi_cntrl->ee != MHI_EE_EDL && mhi_cntrl->ee != MHI_EE_PBL)
421+
goto fw_load_ready_state;
423422

424423
fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
425424
mhi_cntrl->edl_image : mhi_cntrl->fw_image;
@@ -461,9 +460,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
461460
goto error_fw_load;
462461
}
463462

464-
if (mhi_cntrl->ee == MHI_EE_EDL) {
463+
/* Wait for ready since EDL image was loaded */
464+
if (fw_name == mhi_cntrl->edl_image) {
465465
release_firmware(firmware);
466-
return;
466+
goto fw_load_ready_state;
467467
}
468468

469469
write_lock_irq(&mhi_cntrl->pm_lock);
@@ -488,47 +488,45 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
488488

489489
release_firmware(firmware);
490490

491-
fw_load_ee_pthru:
491+
fw_load_ready_state:
492492
/* Transitioning into MHI RESET->READY state */
493493
ret = mhi_ready_state_transition(mhi_cntrl);
494-
495-
if (!mhi_cntrl->fbc_download)
496-
return;
497-
498494
if (ret) {
499495
dev_err(dev, "MHI did not enter READY state\n");
500496
goto error_ready_state;
501497
}
502498

503-
/* Wait for the SBL event */
504-
ret = wait_event_timeout(mhi_cntrl->state_event,
505-
mhi_cntrl->ee == MHI_EE_SBL ||
506-
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
507-
msecs_to_jiffies(mhi_cntrl->timeout_ms));
499+
dev_info(dev, "Wait for device to enter SBL or Mission mode\n");
500+
return;
508501

509-
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
510-
dev_err(dev, "MHI did not enter SBL\n");
511-
goto error_ready_state;
502+
error_ready_state:
503+
if (mhi_cntrl->fbc_download) {
504+
mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
505+
mhi_cntrl->fbc_image = NULL;
512506
}
513507

514-
/* Start full firmware image download */
515-
image_info = mhi_cntrl->fbc_image;
508+
error_fw_load:
509+
mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
510+
wake_up_all(&mhi_cntrl->state_event);
511+
}
512+
513+
int mhi_download_amss_image(struct mhi_controller *mhi_cntrl)
514+
{
515+
struct image_info *image_info = mhi_cntrl->fbc_image;
516+
struct device *dev = &mhi_cntrl->mhi_dev->dev;
517+
int ret;
518+
519+
if (!image_info)
520+
return -EIO;
521+
516522
ret = mhi_fw_load_bhie(mhi_cntrl,
517523
/* Vector table is the last entry */
518524
&image_info->mhi_buf[image_info->entries - 1]);
519525
if (ret) {
520-
dev_err(dev, "MHI did not load image over BHIe, ret: %d\n",
521-
ret);
522-
goto error_fw_load;
526+
dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret);
527+
mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
528+
wake_up_all(&mhi_cntrl->state_event);
523529
}
524530

525-
return;
526-
527-
error_ready_state:
528-
mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
529-
mhi_cntrl->fbc_image = NULL;
530-
531-
error_fw_load:
532-
mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
533-
wake_up_all(&mhi_cntrl->state_event);
531+
return ret;
534532
}

drivers/bus/mhi/core/debugfs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ static struct dentry *mhi_debugfs_root;
377377
void mhi_create_debugfs(struct mhi_controller *mhi_cntrl)
378378
{
379379
mhi_cntrl->debugfs_dentry =
380-
debugfs_create_dir(dev_name(mhi_cntrl->cntrl_dev),
380+
debugfs_create_dir(dev_name(&mhi_cntrl->mhi_dev->dev),
381381
mhi_debugfs_root);
382382

383383
debugfs_create_file("states", 0444, mhi_cntrl->debugfs_dentry,

drivers/bus/mhi/core/init.c

+43-29
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222
static DEFINE_IDA(mhi_controller_ida);
2323

2424
const char * const mhi_ee_str[MHI_EE_MAX] = {
25-
[MHI_EE_PBL] = "PBL",
26-
[MHI_EE_SBL] = "SBL",
27-
[MHI_EE_AMSS] = "AMSS",
28-
[MHI_EE_RDDM] = "RDDM",
29-
[MHI_EE_WFW] = "WFW",
30-
[MHI_EE_PTHRU] = "PASS THRU",
31-
[MHI_EE_EDL] = "EDL",
25+
[MHI_EE_PBL] = "PRIMARY BOOTLOADER",
26+
[MHI_EE_SBL] = "SECONDARY BOOTLOADER",
27+
[MHI_EE_AMSS] = "MISSION MODE",
28+
[MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE",
29+
[MHI_EE_WFW] = "WLAN FIRMWARE",
30+
[MHI_EE_PTHRU] = "PASS THROUGH",
31+
[MHI_EE_EDL] = "EMERGENCY DOWNLOAD",
32+
[MHI_EE_FP] = "FLASH PROGRAMMER",
3233
[MHI_EE_DISABLE_TRANSITION] = "DISABLE",
3334
[MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED",
3435
};
@@ -37,8 +38,9 @@ const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = {
3738
[DEV_ST_TRANSITION_PBL] = "PBL",
3839
[DEV_ST_TRANSITION_READY] = "READY",
3940
[DEV_ST_TRANSITION_SBL] = "SBL",
40-
[DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE",
41-
[DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR",
41+
[DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE",
42+
[DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER",
43+
[DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR",
4244
[DEV_ST_TRANSITION_DISABLE] = "DISABLE",
4345
};
4446

@@ -49,24 +51,30 @@ const char * const mhi_state_str[MHI_STATE_MAX] = {
4951
[MHI_STATE_M1] = "M1",
5052
[MHI_STATE_M2] = "M2",
5153
[MHI_STATE_M3] = "M3",
52-
[MHI_STATE_M3_FAST] = "M3_FAST",
54+
[MHI_STATE_M3_FAST] = "M3 FAST",
5355
[MHI_STATE_BHI] = "BHI",
54-
[MHI_STATE_SYS_ERR] = "SYS_ERR",
56+
[MHI_STATE_SYS_ERR] = "SYS ERROR",
57+
};
58+
59+
const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = {
60+
[MHI_CH_STATE_TYPE_RESET] = "RESET",
61+
[MHI_CH_STATE_TYPE_STOP] = "STOP",
62+
[MHI_CH_STATE_TYPE_START] = "START",
5563
};
5664

5765
static const char * const mhi_pm_state_str[] = {
5866
[MHI_PM_STATE_DISABLE] = "DISABLE",
59-
[MHI_PM_STATE_POR] = "POR",
67+
[MHI_PM_STATE_POR] = "POWER ON RESET",
6068
[MHI_PM_STATE_M0] = "M0",
6169
[MHI_PM_STATE_M2] = "M2",
6270
[MHI_PM_STATE_M3_ENTER] = "M?->M3",
6371
[MHI_PM_STATE_M3] = "M3",
6472
[MHI_PM_STATE_M3_EXIT] = "M3->M0",
65-
[MHI_PM_STATE_FW_DL_ERR] = "FW DL Error",
66-
[MHI_PM_STATE_SYS_ERR_DETECT] = "SYS_ERR Detect",
67-
[MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS_ERR Process",
73+
[MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error",
74+
[MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect",
75+
[MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process",
6876
[MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process",
69-
[MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "LD or Error Fatal Detect",
77+
[MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
7078
};
7179

7280
const char *to_mhi_pm_state_str(enum mhi_pm_state state)
@@ -508,8 +516,6 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
508516

509517
/* Setup wake db */
510518
mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB);
511-
mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 4, 0);
512-
mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
513519
mhi_cntrl->wake_set = false;
514520

515521
/* Setup channel db address for each channel in tre_ring */
@@ -552,6 +558,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
552558
struct mhi_ring *buf_ring;
553559
struct mhi_ring *tre_ring;
554560
struct mhi_chan_ctxt *chan_ctxt;
561+
u32 tmp;
555562

556563
buf_ring = &mhi_chan->buf_ring;
557564
tre_ring = &mhi_chan->tre_ring;
@@ -565,7 +572,19 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
565572
vfree(buf_ring->base);
566573

567574
buf_ring->base = tre_ring->base = NULL;
575+
tre_ring->ctxt_wp = NULL;
568576
chan_ctxt->rbase = 0;
577+
chan_ctxt->rlen = 0;
578+
chan_ctxt->rp = 0;
579+
chan_ctxt->wp = 0;
580+
581+
tmp = chan_ctxt->chcfg;
582+
tmp &= ~CHAN_CTX_CHSTATE_MASK;
583+
tmp |= (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT);
584+
chan_ctxt->chcfg = tmp;
585+
586+
/* Update to all cores */
587+
smp_wmb();
569588
}
570589

571590
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
@@ -863,12 +882,10 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
863882
u32 soc_info;
864883
int ret, i;
865884

866-
if (!mhi_cntrl)
867-
return -EINVAL;
868-
869-
if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
885+
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs ||
886+
!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
870887
!mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
871-
!mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs)
888+
!mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq)
872889
return -EINVAL;
873890

874891
ret = parse_config(mhi_cntrl, config);
@@ -890,8 +907,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
890907
INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker);
891908
init_waitqueue_head(&mhi_cntrl->state_event);
892909

893-
mhi_cntrl->hiprio_wq = alloc_ordered_workqueue
894-
("mhi_hiprio_wq", WQ_MEM_RECLAIM | WQ_HIGHPRI);
910+
mhi_cntrl->hiprio_wq = alloc_ordered_workqueue("mhi_hiprio_wq", WQ_HIGHPRI);
895911
if (!mhi_cntrl->hiprio_wq) {
896912
dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate workqueue\n");
897913
ret = -ENOMEM;
@@ -1083,8 +1099,6 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
10831099
mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image);
10841100
}
10851101

1086-
mhi_cntrl->pre_init = true;
1087-
10881102
mutex_unlock(&mhi_cntrl->pm_mutex);
10891103

10901104
return 0;
@@ -1115,7 +1129,6 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl)
11151129
}
11161130

11171131
mhi_deinit_dev_ctxt(mhi_cntrl);
1118-
mhi_cntrl->pre_init = false;
11191132
}
11201133
EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down);
11211134

@@ -1296,7 +1309,8 @@ static int mhi_driver_remove(struct device *dev)
12961309

12971310
mutex_lock(&mhi_chan->mutex);
12981311

1299-
if (ch_state[dir] == MHI_CH_STATE_ENABLED &&
1312+
if ((ch_state[dir] == MHI_CH_STATE_ENABLED ||
1313+
ch_state[dir] == MHI_CH_STATE_STOP) &&
13001314
!mhi_chan->offload_ch)
13011315
mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan);
13021316

drivers/bus/mhi/core/internal.h

+19-1
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,18 @@ enum mhi_ch_state {
369369
MHI_CH_STATE_ERROR = 0x5,
370370
};
371371

372+
enum mhi_ch_state_type {
373+
MHI_CH_STATE_TYPE_RESET,
374+
MHI_CH_STATE_TYPE_STOP,
375+
MHI_CH_STATE_TYPE_START,
376+
MHI_CH_STATE_TYPE_MAX,
377+
};
378+
379+
extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX];
380+
#define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \
381+
"INVALID_STATE" : \
382+
mhi_ch_state_type_str[(state)])
383+
372384
#define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \
373385
mode != MHI_DB_BRST_ENABLE)
374386

@@ -379,13 +391,15 @@ extern const char * const mhi_ee_str[MHI_EE_MAX];
379391
#define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \
380392
ee == MHI_EE_EDL)
381393

382-
#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW)
394+
#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW || \
395+
ee == MHI_EE_FP)
383396

384397
enum dev_st_transition {
385398
DEV_ST_TRANSITION_PBL,
386399
DEV_ST_TRANSITION_READY,
387400
DEV_ST_TRANSITION_SBL,
388401
DEV_ST_TRANSITION_MISSION_MODE,
402+
DEV_ST_TRANSITION_FP,
389403
DEV_ST_TRANSITION_SYS_ERR,
390404
DEV_ST_TRANSITION_DISABLE,
391405
DEV_ST_TRANSITION_MAX,
@@ -619,6 +633,7 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl);
619633
int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl);
620634
int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
621635
enum mhi_cmd_type cmd);
636+
int mhi_download_amss_image(struct mhi_controller *mhi_cntrl);
622637
static inline bool mhi_is_active(struct mhi_controller *mhi_cntrl)
623638
{
624639
return (mhi_cntrl->dev_state >= MHI_STATE_M0 &&
@@ -643,6 +658,9 @@ int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
643658
int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
644659
void __iomem *base, u32 offset, u32 mask,
645660
u32 shift, u32 *out);
661+
int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
662+
void __iomem *base, u32 offset, u32 mask,
663+
u32 shift, u32 val, u32 delayus);
646664
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
647665
u32 offset, u32 val);
648666
void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,

0 commit comments

Comments
 (0)