diff --git a/arch/arm64/boot/dts/qcom/qcs6490-radxa-cm-q64.dtsi b/arch/arm64/boot/dts/qcom/qcs6490-radxa-cm-q64.dtsi index a4d9082bd20d6..b97efb18afce8 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-radxa-cm-q64.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs6490-radxa-cm-q64.dtsi @@ -845,22 +845,6 @@ "AMIC2", "MIC BIAS2", "TX SWR_ADC1", "ADC2_OUTPUT"; - dp0-dai-link { - link-name = "DP0 Playback"; - - codec { - sound-dai = <&mdss_dp>; - }; - - cpu { - sound-dai = <&q6apmbedai DISPLAY_PORT_RX_0>; - }; - - platform { - sound-dai = <&q6apm>; - }; - }; - wcd-playback-dai-link { link-name = "WCD Playback"; @@ -1142,6 +1126,7 @@ /* For uart_dbg */ &qup_uart5_tx { bias-disable; + output-high; drive-strength = <16>; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 0f4921b1a8922..89da3797d928e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1415,8 +1415,15 @@ static struct msm_display_topology dpu_crtc_get_topology( else topology.num_lm = 1; - if (crtc_state->ctm || crtc_state->gamma_lut) - topology.num_dspp = topology.num_lm; + if (crtc_state->ctm || crtc_state->gamma_lut) { + if (topology.num_lm <= (int)dpu_kms->catalog->dspp_count) { + topology.num_dspp = topology.num_lm; + } else { + DRM_WARN("CTM/gamma on %d LM(s) with %d DSPP(s), " + "color management skipped\n", + topology.num_lm, dpu_kms->catalog->dspp_count); + } + } return topology; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index dc49f50c519ec..75d56a35c6978 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -986,17 +986,21 @@ static irqreturn_t msm_dp_display_irq_thread(int irq, void *dev_id) unsigned long flags; u32 hpd_isr_status; int rc; + bool was_plugged; spin_lock_irqsave(&dp->irq_thread_lock, flags); hpd_isr_status = dp->hpd_isr_status; dp->hpd_isr_status = 0; spin_unlock_irqrestore(&dp->irq_thread_lock, flags); - if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) + was_plugged = dp->plugged; + + /* notify only on actual state transitions */ + if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK && was_plugged) drm_bridge_hpd_notify(dp->msm_dp_display.bridge, connector_status_disconnected); - if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK) + if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK && !was_plugged) drm_bridge_hpd_notify(dp->msm_dp_display.bridge, connector_status_connected); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index ae37c7a2682ba..62b30a7520c60 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -88,6 +88,7 @@ struct qcom_pas { int crash_reason_smem; unsigned int smem_host_id; bool decrypt_shutdown; + bool preloaded; const char *info_name; const struct firmware *firmware; @@ -225,6 +226,11 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw) struct qcom_pas *pas = rproc->priv; int ret; + if (pas->preloaded) { + dev_err(pas->dev, "remoteproc is externally managed\n"); + return -EPERM; + } + /* Store firmware handle to be used in qcom_pas_start() */ pas->firmware = fw; @@ -407,17 +413,23 @@ static int qcom_pas_stop(struct rproc *rproc) if (ret == -ETIMEDOUT) dev_err(pas->dev, "timed out on wait\n"); - ret = qcom_scm_pas_shutdown(pas->pas_id); - if (ret && pas->decrypt_shutdown) - ret = qcom_pas_shutdown_poll_decrypt(pas); + if (pas->preloaded) { + ret = 0; + } else { + ret = qcom_scm_pas_shutdown(pas->pas_id); + if (ret && pas->decrypt_shutdown) + ret = qcom_pas_shutdown_poll_decrypt(pas); - if (ret) - dev_err(pas->dev, "failed to shutdown: %d\n", ret); + if (ret) + dev_err(pas->dev, "failed to shutdown: %d\n", ret); + } if (pas->dtb_pas_id) { - ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); - if (ret) - dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); + if (!pas->preloaded) { + ret = qcom_scm_pas_shutdown(pas->dtb_pas_id); + if (ret) + dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret); + } qcom_pas_unmap_carveout(rproc, pas->dtb_mem_phys, pas->dtb_mem_size); } @@ -517,16 +529,65 @@ static unsigned long qcom_pas_panic(struct rproc *rproc) return qcom_q6v5_panic(&pas->q6v5); } +static int qcom_pas_get_boot_state_from_smp2p(struct qcom_pas *pas, + bool *ready_state, + bool *crash_state) +{ + bool handover = false; + bool ready = false; + bool fatal = false; + bool stop = false; + int ret; + + ret = irq_get_irqchip_state(pas->q6v5.handover_irq, + IRQCHIP_STATE_LINE_LEVEL, &handover); + if (ret) + return ret; + + ret = irq_get_irqchip_state(pas->q6v5.ready_irq, + IRQCHIP_STATE_LINE_LEVEL, &ready); + if (ret) + return ret; + + ret = irq_get_irqchip_state(pas->q6v5.fatal_irq, + IRQCHIP_STATE_LINE_LEVEL, &fatal); + if (ret) + return ret; + + ret = irq_get_irqchip_state(pas->q6v5.stop_irq, + IRQCHIP_STATE_LINE_LEVEL, &stop); + if (ret) + return ret; + + *crash_state = fatal; + *ready_state = ready && handover && !stop && !fatal; + + return 0; +} + static int qcom_pas_attach(struct rproc *rproc) { int ret; struct qcom_pas *pas = rproc->priv; - bool ready_state; - bool crash_state; + bool ready_state = false; + bool crash_state = false; pas->q6v5.running = true; - ret = irq_get_irqchip_state(pas->q6v5.fatal_irq, - IRQCHIP_STATE_LINE_LEVEL, &crash_state); + + if (pas->preloaded) { + ret = qcom_pas_get_boot_state_from_smp2p(pas, + &ready_state, + &crash_state); + } else { + ret = irq_get_irqchip_state(pas->q6v5.fatal_irq, + IRQCHIP_STATE_LINE_LEVEL, + &crash_state); + + if (!ret && !crash_state) + ret = irq_get_irqchip_state(pas->q6v5.ready_irq, + IRQCHIP_STATE_LINE_LEVEL, + &ready_state); + } if (ret) goto disable_running; @@ -538,30 +599,28 @@ static int qcom_pas_attach(struct rproc *rproc) goto disable_running; } - ret = irq_get_irqchip_state(pas->q6v5.ready_irq, - IRQCHIP_STATE_LINE_LEVEL, &ready_state); - - if (ret) - goto disable_running; - if (unlikely(!ready_state)) { /* * The bootloader may not support early boot, mark the state as * RPROC_OFFLINE so that the PAS driver can load the firmware and * start the remoteproc. */ - dev_err(pas->dev, "Failed to get subsystem ready interrupt\n"); + dev_err(pas->dev, pas->preloaded ? + "Failed to detect already running subsystem\n" : + "Failed to get subsystem ready interrupt\n"); pas->rproc->state = RPROC_OFFLINE; ret = -EINVAL; goto disable_running; } - ret = qcom_q6v5_ping_subsystem(&pas->q6v5); + if (!pas->preloaded) { + ret = qcom_q6v5_ping_subsystem(&pas->q6v5); - if (ret) { - dev_err(pas->dev, "Failed to ping subsystem, assuming device crashed\n"); - rproc_report_crash(rproc, RPROC_FATAL_ERROR); - goto disable_running; + if (ret) { + dev_err(pas->dev, "Failed to ping subsystem, assuming device crashed\n"); + rproc_report_crash(rproc, RPROC_FATAL_ERROR); + goto disable_running; + } } pas->q6v5.handover_issued = true; @@ -805,6 +864,8 @@ static int qcom_pas_probe(struct platform_device *pdev) struct rproc *rproc; const char *fw_name, *dtb_fw_name = NULL; const struct rproc_ops *ops = &qcom_pas_ops; + bool ready_state; + bool crash_state; int ret; desc = of_device_get_match_data(&pdev->dev); @@ -852,6 +913,7 @@ static int qcom_pas_probe(struct platform_device *pdev) pas->info_name = desc->sysmon_name; pas->smem_host_id = desc->smem_host_id; pas->decrypt_shutdown = desc->decrypt_shutdown; + pas->preloaded = false; pas->region_assign_idx = desc->region_assign_idx; pas->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count); pas->region_assign_vmid = desc->region_assign_vmid; @@ -927,6 +989,17 @@ static int qcom_pas_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "Falling back to firmware load\n"); else pas->rproc->state = RPROC_DETACHED; + } else { + ret = qcom_pas_get_boot_state_from_smp2p(pas, + &ready_state, + &crash_state); + if (ret) { + dev_warn(&pdev->dev, "Failed to read SMP2P state; falling back to firmware load\n"); + } else if (ready_state) { + pas->preloaded = true; + pas->rproc->state = RPROC_DETACHED; + rproc_set_feature(pas->rproc, RPROC_FEAT_ATTACH_ON_RECOVERY); + } } ret = rproc_add(rproc);