diff options
Diffstat (limited to 'drivers/net/wwan/t7xx/t7xx_state_monitor.c')
-rw-r--r-- | drivers/net/wwan/t7xx/t7xx_state_monitor.c | 132 |
1 files changed, 112 insertions, 20 deletions
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c index 0bc974302..9889ca462 100644 --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c @@ -47,6 +47,13 @@ #define FSM_MD_EX_PASS_TIMEOUT_MS 45000 #define FSM_CMD_TIMEOUT_MS 2000 +#define wait_for_expected_dev_stage(status) \ + read_poll_timeout(ioread32, status, \ + ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LINUX) || \ + ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LK), 100000, \ + 20000000, false, IREG_BASE(md->t7xx_dev) + \ + T7XX_PCIE_MISC_DEV_STATUS) + void t7xx_fsm_notifier_register(struct t7xx_modem *md, struct t7xx_fsm_notifier *notifier) { struct t7xx_fsm_ctl *ctl = md->fsm_ctl; @@ -206,6 +213,55 @@ static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm fsm_finish_command(ctl, cmd, 0); } +static void t7xx_host_event_notify(struct t7xx_modem *md, unsigned int event_id) +{ + u32 value; + + value = ioread32(IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); + value &= ~HOST_EVENT_MASK; + value |= FIELD_PREP(HOST_EVENT_MASK, event_id); + iowrite32(value, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); +} + +static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int status) +{ + struct t7xx_modem *md = ctl->md; + struct cldma_ctrl *md_ctrl; + enum lk_event_id lk_event; + struct device *dev; + struct t7xx_port *port; + + dev = &md->t7xx_dev->pdev->dev; + lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status); + switch (lk_event) { + case LK_EVENT_NORMAL: + case LK_EVENT_RESET: + break; + + case LK_EVENT_CREATE_PD_PORT: + case LK_EVENT_CREATE_POST_DL_PORT: + md_ctrl = md->md_ctrl[CLDMA_ID_AP]; + t7xx_cldma_hif_hw_init(md_ctrl); + t7xx_cldma_stop(md_ctrl); + t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG); + + port = &ctl->md->port_prox->ports[0]; + port->port_conf->ops->enable_chl(port); + + t7xx_cldma_start(md_ctrl); + + if (lk_event == LK_EVENT_CREATE_POST_DL_PORT) + t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DOWNLOAD); + else + t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DUMP); + break; + + default: + dev_err(dev, "Invalid LK event %d\n", lk_event); + break; + } +} + static int fsm_stopped_handler(struct t7xx_fsm_ctl *ctl) { ctl->curr_state = FSM_STATE_STOPPED; @@ -226,8 +282,9 @@ static void fsm_routine_stopped(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comman static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd) { - struct t7xx_pci_dev *t7xx_dev; - struct cldma_ctrl *md_ctrl; + struct cldma_ctrl *md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD]; + struct t7xx_pci_dev *t7xx_dev = ctl->md->t7xx_dev; + enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode); int err; if (ctl->curr_state == FSM_STATE_STOPPED || ctl->curr_state == FSM_STATE_STOPPING) { @@ -235,18 +292,20 @@ static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comma return; } - md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD]; - t7xx_dev = ctl->md->t7xx_dev; - ctl->curr_state = FSM_STATE_STOPPING; t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_TO_STOP); t7xx_cldma_stop(md_ctrl); - if (!ctl->md->rgu_irq_asserted) { - t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP); - /* Wait for the DRM disable to take effect */ - msleep(FSM_DRM_DISABLE_DELAY_MS); + if (mode == T7XX_FASTBOOT_SWITCHING) + t7xx_host_event_notify(ctl->md, FASTBOOT_DL_NOTIFY); + + t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP); + /* Wait for the DRM disable to take effect */ + msleep(FSM_DRM_DISABLE_DELAY_MS); + if (mode == T7XX_FASTBOOT_SWITCHING) { + t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET); + } else { err = t7xx_acpi_fldr_func(t7xx_dev); if (err) t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET); @@ -272,6 +331,7 @@ static void fsm_routine_ready(struct t7xx_fsm_ctl *ctl) ctl->curr_state = FSM_STATE_READY; t7xx_fsm_broadcast_ready_state(ctl); + t7xx_mode_update(md->t7xx_dev, T7XX_READY); t7xx_md_event_notify(md, FSM_READY); } @@ -317,7 +377,8 @@ static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl) static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd) { struct t7xx_modem *md = ctl->md; - u32 dev_status; + struct device *dev; + u32 status; int ret; if (!md) @@ -329,23 +390,53 @@ static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command return; } + dev = &md->t7xx_dev->pdev->dev; ctl->curr_state = FSM_STATE_PRE_START; t7xx_md_event_notify(md, FSM_PRE_START); - ret = read_poll_timeout(ioread32, dev_status, - (dev_status & MISC_STAGE_MASK) == LINUX_STAGE, 20000, 2000000, - false, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS); + ret = wait_for_expected_dev_stage(status); + if (ret) { - struct device *dev = &md->t7xx_dev->pdev->dev; + dev_err(dev, "read poll timeout %d\n", ret); + goto finish_command; + } - fsm_finish_command(ctl, cmd, -ETIMEDOUT); - dev_err(dev, "Invalid device status 0x%lx\n", dev_status & MISC_STAGE_MASK); - return; + if (status != ctl->status || cmd->flag != 0) { + u32 stage = FIELD_GET(MISC_STAGE_MASK, status); + + switch (stage) { + case T7XX_DEV_STAGE_INIT: + case T7XX_DEV_STAGE_BROM_PRE: + case T7XX_DEV_STAGE_BROM_POST: + dev_dbg(dev, "BROM_STAGE Entered\n"); + ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0); + break; + + case T7XX_DEV_STAGE_LK: + dev_dbg(dev, "LK_STAGE Entered\n"); + t7xx_lk_stage_event_handling(ctl, status); + break; + + case T7XX_DEV_STAGE_LINUX: + dev_dbg(dev, "LINUX_STAGE Entered\n"); + t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM | + D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK); + if (cmd->flag == 0) + break; + t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]); + t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]); + t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL); + ret = fsm_routine_starting(ctl); + break; + + default: + break; + } + ctl->status = status; } - t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]); - t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]); - fsm_finish_command(ctl, cmd, fsm_routine_starting(ctl)); +finish_command: + fsm_finish_command(ctl, cmd, ret); } static int fsm_main_thread(void *data) @@ -517,6 +608,7 @@ void t7xx_fsm_reset(struct t7xx_modem *md) fsm_flush_event_cmd_qs(ctl); ctl->curr_state = FSM_STATE_STOPPED; ctl->exp_flg = false; + ctl->status = T7XX_DEV_STAGE_INIT; } int t7xx_fsm_init(struct t7xx_modem *md) |