int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) { struct a6xx_gmu *gmu = &a6xx_gpu->gmu; struct msm_gpu *gpu = &a6xx_gpu->base.base; if (!pm_runtime_active(gmu->dev)) return 0; /* * Force the GMU off if we detected a hang, otherwise try to shut it * down gracefully */ if (gmu->hung) a6xx_gmu_force_off(gmu); else a6xx_gmu_shutdown(gmu); /* Remove the bus vote */ icc_set_bw(gpu->icc_path, 0, 0); /* * Make sure the GX domain is off before turning off the GMU (CX) * domain. Usually the GMU does this but only if the shutdown sequence * was successful */ if (!IS_ERR_OR_NULL(gmu->gxpd)) pm_runtime_put_sync(gmu->gxpd); clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); pm_runtime_put_sync(gmu->dev); return 0; }
static int adsp_start(struct rproc *rproc) { struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int ret; unsigned int val; qcom_q6v5_prepare(&adsp->q6v5); ret = clk_prepare_enable(adsp->xo); if (ret) goto disable_irqs; dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX); ret = pm_runtime_get_sync(adsp->dev); if (ret) goto disable_xo_clk; ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks); if (ret) { dev_err(adsp->dev, "adsp clk_enable failed\n"); goto disable_power_domain; } /* Program boot address */ writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG); /* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */ writel(0x1, adsp->qdsp6ss_base + CORE_START_REG); /* Trigger boot FSM to start QDSP6 */ writel(0x1, adsp->qdsp6ss_base + BOOT_CMD_REG); /* Wait for core to come out of reset */ ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG, val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT); if (ret) { dev_err(adsp->dev, "failed to bootup adsp\n"); goto disable_adsp_clks; } ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5 * HZ)); if (ret == -ETIMEDOUT) { dev_err(adsp->dev, "start timed out\n"); goto disable_adsp_clks; } return 0; disable_adsp_clks: clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); disable_power_domain: dev_pm_genpd_set_performance_state(adsp->dev, 0); pm_runtime_put(adsp->dev); disable_xo_clk: clk_disable_unprepare(adsp->xo); disable_irqs: qcom_q6v5_unprepare(&adsp->q6v5); return ret; }
int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu) { struct a6xx_gmu *gmu = &a6xx_gpu->gmu; int ret; u32 val; /* Flush all the queues */ a6xx_hfi_stop(gmu); /* Stop the interrupts */ a6xx_gmu_irq_disable(gmu); /* Force off SPTP in case the GMU is managing it */ a6xx_sptprac_disable(gmu); /* Make sure there are no outstanding RPMh votes */ gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val, (val & 1), 100, 10000); gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val, (val & 1), 100, 10000); gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val, (val & 1), 100, 10000); gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val, (val & 1), 100, 1000); /* Force off the GX GSDC */ regulator_force_disable(gmu->gx); /* Disable the resources */ clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); pm_runtime_put_sync(gmu->dev); /* Re-enable the resources */ pm_runtime_get_sync(gmu->dev); /* Use a known rate to bring up the GMU */ clk_set_rate(gmu->core_clk, 200000000); ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); if (ret) goto out; a6xx_gmu_irq_enable(gmu); ret = a6xx_gmu_fw_start(gmu, GMU_RESET); if (!ret) ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT); /* Set the GPU back to the highest power frequency */ a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); out: if (ret) a6xx_gmu_clear_oob(gmu, GMU_OOB_BOOT_SLUMBER); return ret; }
int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) { struct a6xx_gmu *gmu = &a6xx_gpu->gmu; u32 val; /* * The GMU may still be in slumber unless the GPU started so check and * skip putting it back into slumber if so */ val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE); if (val != 0xf) { int ret = a6xx_gmu_wait_for_idle(a6xx_gpu); /* Temporary until we can recover safely */ BUG_ON(ret); /* tell the GMU we want to slumber */ a6xx_gmu_notify_slumber(gmu); ret = gmu_poll_timeout(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, val, !(val & A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS_GPUBUSYIGNAHB), 100, 10000); /* * Let the user know we failed to slumber but don't worry too * much because we are powering down anyway */ if (ret) dev_err(gmu->dev, "Unable to slumber GMU: status = 0%x/0%x\n", gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS), gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2)); } /* Turn off HFI */ a6xx_hfi_stop(gmu); /* Stop the interrupts and mask the hardware */ a6xx_gmu_irq_disable(gmu); /* Tell RPMh to power off the GPU */ a6xx_rpmh_stop(gmu); clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); pm_runtime_put_sync(gmu->dev); return 0; }
static int sdhci_msm_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); return 0; }
static int sdhci_msm_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); sdhci_pltfm_free(pdev); return 0; }
static int dwc3_of_simple_remove(struct platform_device *pdev) { struct dwc3_of_simple *simple = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; of_platform_depopulate(dev); clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); clk_bulk_put_all(simple->num_clocks, simple->clks); simple->num_clocks = 0; if (!simple->pulse_resets) reset_control_assert(simple->resets); reset_control_put(simple->resets); pm_runtime_disable(dev); pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); return 0; }
static int qcom_adsp_shutdown(struct qcom_adsp *adsp) { unsigned long timeout; unsigned int val; int ret; /* Reset the retention logic */ val = readl(adsp->qdsp6ss_base + RET_CFG_REG); val |= 0x1; writel(val, adsp->qdsp6ss_base + RET_CFG_REG); clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); /* QDSP6 master port needs to be explicitly halted */ ret = regmap_read(adsp->halt_map, adsp->halt_lpass + LPASS_PWR_ON_REG, &val); if (ret || !val) goto reset; ret = regmap_read(adsp->halt_map, adsp->halt_lpass + LPASS_MASTER_IDLE_REG, &val); if (ret || val) goto reset; regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 1); /* Wait for halt ACK from QDSP6 */ timeout = jiffies + msecs_to_jiffies(ACK_TIMEOUT); for (;;) { ret = regmap_read(adsp->halt_map, adsp->halt_lpass + LPASS_HALTACK_REG, &val); if (ret || val || time_after(jiffies, timeout)) break; usleep_range(1000, 1100); } ret = regmap_read(adsp->halt_map, adsp->halt_lpass + LPASS_MASTER_IDLE_REG, &val); if (ret || !val) dev_err(adsp->dev, "port failed halt\n"); reset: /* Assert the LPASS PDC Reset */ reset_control_assert(adsp->pdc_sync_reset); /* Place the LPASS processor into reset */ reset_control_assert(adsp->cc_lpass_restart); /* wait after asserting subsystem restart from AOSS */ usleep_range(200, 300); /* Clear the halt request for the AXIM and AHBM for Q6 */ regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0); /* De-assert the LPASS PDC Reset */ reset_control_deassert(adsp->pdc_sync_reset); /* Remove the LPASS reset */ reset_control_deassert(adsp->cc_lpass_restart); /* wait after de-asserting subsystem restart from AOSS */ usleep_range(200, 300); return 0; }
static int dwc3_of_simple_probe(struct platform_device *pdev) { struct dwc3_of_simple *simple; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; int ret; bool shared_resets = false; simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); if (!simple) return -ENOMEM; platform_set_drvdata(pdev, simple); simple->dev = dev; /* * Some controllers need to toggle the usb3-otg reset before trying to * initialize the PHY, otherwise the PHY times out. */ if (of_device_is_compatible(np, "rockchip,rk3399-dwc3")) simple->need_reset = true; if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") || of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) { shared_resets = true; simple->pulse_resets = true; } simple->resets = of_reset_control_array_get(np, shared_resets, true, true); if (IS_ERR(simple->resets)) { ret = PTR_ERR(simple->resets); dev_err(dev, "failed to get device resets, err=%d\n", ret); return ret; } if (simple->pulse_resets) { ret = reset_control_reset(simple->resets); if (ret) goto err_resetc_put; } else { ret = reset_control_deassert(simple->resets); if (ret) goto err_resetc_put; } ret = clk_bulk_get_all(simple->dev, &simple->clks); if (ret < 0) goto err_resetc_assert; simple->num_clocks = ret; ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); if (ret) goto err_resetc_assert; ret = of_platform_populate(np, NULL, NULL, dev); if (ret) goto err_clk_put; pm_runtime_set_active(dev); pm_runtime_enable(dev); pm_runtime_get_sync(dev); return 0; err_clk_put: clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); clk_bulk_put_all(simple->num_clocks, simple->clks); err_resetc_assert: if (!simple->pulse_resets) reset_control_assert(simple->resets); err_resetc_put: reset_control_put(simple->resets); return ret; }
static int sdhci_msm_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_msm_host *msm_host; struct resource *core_memres; struct clk *clk; int ret; u16 host_version, core_minor; u32 core_version, config; u8 core_major; host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host)); if (IS_ERR(host)) return PTR_ERR(host); host->sdma_boundary = 0; pltfm_host = sdhci_priv(host); msm_host = sdhci_pltfm_priv(pltfm_host); msm_host->mmc = host->mmc; msm_host->pdev = pdev; ret = mmc_of_parse(host->mmc); if (ret) goto pltfm_free; sdhci_get_of_property(pdev); msm_host->saved_tuning_phase = INVALID_TUNING_PHASE; /* Setup SDCC bus voter clock. */ msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus"); if (!IS_ERR(msm_host->bus_clk)) { /* Vote for max. clk rate for max. performance */ ret = clk_set_rate(msm_host->bus_clk, INT_MAX); if (ret) goto pltfm_free; ret = clk_prepare_enable(msm_host->bus_clk); if (ret) goto pltfm_free; } /* Setup main peripheral bus clock */ clk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret); goto bus_clk_disable; } msm_host->bulk_clks[1].clk = clk; /* Setup SDC MMC clock */ clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret); goto bus_clk_disable; } msm_host->bulk_clks[0].clk = clk; /* Vote for maximum clock rate for maximum performance */ ret = clk_set_rate(clk, INT_MAX); if (ret) dev_warn(&pdev->dev, "core clock boost failed\n"); clk = devm_clk_get(&pdev->dev, "cal"); if (IS_ERR(clk)) clk = NULL; msm_host->bulk_clks[2].clk = clk; clk = devm_clk_get(&pdev->dev, "sleep"); if (IS_ERR(clk)) clk = NULL; msm_host->bulk_clks[3].clk = clk; ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (ret) goto bus_clk_disable; /* * xo clock is needed for FLL feature of cm_dll. * In case if xo clock is not mentioned in DT, warn and proceed. */ msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo"); if (IS_ERR(msm_host->xo_clk)) { ret = PTR_ERR(msm_host->xo_clk); dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret); } core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1); msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres); if (IS_ERR(msm_host->core_mem)) { dev_err(&pdev->dev, "Failed to remap registers\n"); ret = PTR_ERR(msm_host->core_mem); goto clk_disable; } /* Reset the vendor spec register to power on reset state */ writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, host->ioaddr + CORE_VENDOR_SPEC); /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); config = readl_relaxed(msm_host->core_mem + CORE_HC_MODE); config |= FF_CLK_SW_RST_DIS; writel_relaxed(config, msm_host->core_mem + CORE_HC_MODE); host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT)); core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION); core_major = (core_version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT; core_minor = core_version & CORE_VERSION_MINOR_MASK; dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n", core_version, core_major, core_minor); if (core_major == 1 && core_minor >= 0x42) msm_host->use_14lpp_dll_reset = true; /* * SDCC 5 controller with major version 1, minor version 0x34 and later * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. */ if (core_major == 1 && core_minor < 0x34) msm_host->use_cdclp533 = true; /* * Support for some capabilities is not advertised by newer * controller versions and must be explicitly enabled. */ if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { config = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES); config |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0); } /* * Power on reset state may trigger power irq if previous status of * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq * interrupt in GIC, any pending power irq interrupt should be * acknowledged. Otherwise power irq interrupt handler would be * fired prematurely. */ sdhci_msm_handle_pwr_irq(host, 0); /* * Ensure that above writes are propogated before interrupt enablement * in GIC. */ mb(); /* Setup IRQ for handling power/voltage tasks with PMIC */ msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); if (msm_host->pwr_irq < 0) { dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n", msm_host->pwr_irq); ret = msm_host->pwr_irq; goto clk_disable; } sdhci_msm_init_pwr_irq_wait(msm_host); /* Enable pwr irq interrupts */ writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK); ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, sdhci_msm_pwr_irq, IRQF_ONESHOT, dev_name(&pdev->dev), host); if (ret) { dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret); goto clk_disable; } pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_MMC_AUTOSUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning; ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; pm_runtime_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); clk_disable: clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); pltfm_free: sdhci_pltfm_free(pdev); return ret; }