Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge patch series "ufs: ufs-qcom: Add support firmware managed platforms"

Ram Kumar Dwivedi <ram.dwivedi@oss.qualcomm.com> says:

On Qualcomm automotive SoC SA8255P, platform resource like clocks,
interconnect, resets, regulators and PHY are configured remotely by
firmware.

Logical power domain is used to abstract these resources in firmware
and SCMI power protocol is used to request resource operations by
using runtime PM framework APIs such as pm_runtime_get/put_sync to
invoke power_on/_off calls from kernel respectively.

Link: https://patch.msgid.link/20260113080046.284089-1-ram.dwivedi@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

+216 -3
+56
Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/ufs/qcom,sa8255p-ufshc.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm SA8255P UFS Host Controller 8 + 9 + maintainers: 10 + - Ram Kumar Dwivedi <ram.dwivedi@oss.qualcomm.com> 11 + 12 + properties: 13 + compatible: 14 + const: qcom,sa8255p-ufshc 15 + 16 + reg: 17 + maxItems: 1 18 + 19 + interrupts: 20 + maxItems: 1 21 + 22 + iommus: 23 + maxItems: 1 24 + 25 + dma-coherent: true 26 + 27 + power-domains: 28 + maxItems: 1 29 + 30 + required: 31 + - compatible 32 + - reg 33 + - interrupts 34 + - power-domains 35 + - iommus 36 + - dma-coherent 37 + 38 + allOf: 39 + - $ref: ufs-common.yaml 40 + 41 + unevaluatedProperties: false 42 + 43 + examples: 44 + - | 45 + #include <dt-bindings/interrupt-controller/arm-gic.h> 46 + 47 + ufshc@1d84000 { 48 + compatible = "qcom,sa8255p-ufshc"; 49 + reg = <0x01d84000 0x3000>; 50 + interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>; 51 + lanes-per-direction = <2>; 52 + 53 + iommus = <&apps_smmu 0x100 0x0>; 54 + power-domains = <&scmi3_pd 0>; 55 + dma-coherent; 56 + };
+1 -1
MAINTAINERS
··· 26803 26803 L: linux-arm-msm@vger.kernel.org 26804 26804 L: linux-scsi@vger.kernel.org 26805 26805 S: Maintained 26806 - F: Documentation/devicetree/bindings/ufs/qcom,ufs.yaml 26806 + F: Documentation/devicetree/bindings/ufs/qcom* 26807 26807 F: drivers/ufs/host/ufs-qcom* 26808 26808 26809 26809 UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER RENESAS HOOKS
+1 -1
drivers/ufs/core/ufs-sysfs.c
··· 141 141 if (kstrtoul(buf, 0, &value)) 142 142 return -EINVAL; 143 143 144 - if (value >= UFS_PM_LVL_MAX) 144 + if (value >= UFS_PM_LVL_MAX || value < hba->pm_lvl_min) 145 145 return -EINVAL; 146 146 147 147 if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE &&
+155 -1
drivers/ufs/host/ufs-qcom.c
··· 14 14 #include <linux/of.h> 15 15 #include <linux/phy/phy.h> 16 16 #include <linux/platform_device.h> 17 + #include <linux/pm_domain.h> 17 18 #include <linux/reset-controller.h> 18 19 #include <linux/time.h> 19 20 #include <linux/unaligned.h> ··· 620 619 return err; 621 620 } 622 621 622 + static int ufs_qcom_fw_managed_hce_enable_notify(struct ufs_hba *hba, 623 + enum ufs_notify_change_status status) 624 + { 625 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 626 + 627 + switch (status) { 628 + case PRE_CHANGE: 629 + ufs_qcom_select_unipro_mode(host); 630 + break; 631 + case POST_CHANGE: 632 + ufs_qcom_enable_hw_clk_gating(hba); 633 + ufs_qcom_ice_enable(host); 634 + break; 635 + default: 636 + dev_err(hba->dev, "Invalid status %d\n", status); 637 + return -EINVAL; 638 + } 639 + 640 + return 0; 641 + } 642 + 623 643 /** 624 644 * ufs_qcom_cfg_timers - Configure ufs qcom cfg timers 625 645 * ··· 806 784 usleep_range(50, 100); 807 785 ufshcd_writel(hba, reg_val, UFS_MEM_ICE_CFG); 808 786 ufshcd_readl(hba, UFS_MEM_ICE_CFG); 787 + } 788 + 789 + return ufs_qcom_ice_resume(host); 790 + } 791 + 792 + static int ufs_qcom_fw_managed_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, 793 + enum ufs_notify_change_status status) 794 + { 795 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 796 + 797 + if (status == PRE_CHANGE) 798 + return 0; 799 + 800 + pm_runtime_put_sync(hba->dev); 801 + 802 + return ufs_qcom_ice_suspend(host); 803 + } 804 + 805 + static int ufs_qcom_fw_managed_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) 806 + { 807 + struct ufs_qcom_host *host = ufshcd_get_variant(hba); 808 + int err; 809 + 810 + err = pm_runtime_resume_and_get(hba->dev); 811 + if (err) { 812 + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); 813 + return err; 809 814 } 810 815 811 816 return ufs_qcom_ice_resume(host); ··· 1470 1421 phy_exit(host->generic_phy); 1471 1422 } 1472 1423 1424 + static int ufs_qcom_fw_managed_init(struct ufs_hba *hba) 1425 + { 1426 + struct device *dev = hba->dev; 1427 + struct ufs_qcom_host *host; 1428 + int err; 1429 + 1430 + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); 1431 + if (!host) 1432 + return -ENOMEM; 1433 + 1434 + host->hba = hba; 1435 + ufshcd_set_variant(hba, host); 1436 + 1437 + ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, 1438 + &host->hw_ver.minor, &host->hw_ver.step); 1439 + 1440 + err = ufs_qcom_ice_init(host); 1441 + if (err) 1442 + goto out_variant_clear; 1443 + 1444 + ufs_qcom_get_default_testbus_cfg(host); 1445 + err = ufs_qcom_testbus_config(host); 1446 + if (err) 1447 + /* Failure is non-fatal */ 1448 + dev_warn(dev, "Failed to configure the testbus %d\n", err); 1449 + 1450 + hba->caps |= UFSHCD_CAP_WB_EN; 1451 + 1452 + ufs_qcom_advertise_quirks(hba); 1453 + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; 1454 + 1455 + hba->spm_lvl = hba->rpm_lvl = hba->pm_lvl_min = UFS_PM_LVL_5; 1456 + 1457 + ufs_qcom_set_host_params(hba); 1458 + ufs_qcom_parse_gear_limits(hba); 1459 + 1460 + return 0; 1461 + 1462 + out_variant_clear: 1463 + ufshcd_set_variant(hba, NULL); 1464 + return err; 1465 + } 1466 + 1467 + static void ufs_qcom_fw_managed_exit(struct ufs_hba *hba) 1468 + { 1469 + pm_runtime_put_sync(hba->dev); 1470 + } 1471 + 1473 1472 /** 1474 1473 * ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles 1475 1474 * ··· 2047 1950 return 0; 2048 1951 } 2049 1952 1953 + /** 1954 + * ufs_qcom_fw_managed_device_reset - Reset UFS device under FW-managed design 1955 + * @hba: pointer to UFS host bus adapter 1956 + * 1957 + * In the firmware-managed reset model, the power domain is powered on by genpd 1958 + * before the UFS controller driver probes. For subsequent resets (such as 1959 + * suspend/resume or recovery), the UFS driver must explicitly invoke PM runtime 1960 + * 1961 + * Return: 0 on success or a negative error code on failure. 1962 + */ 1963 + static int ufs_qcom_fw_managed_device_reset(struct ufs_hba *hba) 1964 + { 1965 + static bool is_boot = true; 1966 + int err; 1967 + 1968 + /* Skip reset on cold boot; perform it on subsequent calls */ 1969 + if (is_boot) { 1970 + is_boot = false; 1971 + return 0; 1972 + } 1973 + 1974 + pm_runtime_put_sync(hba->dev); 1975 + err = pm_runtime_resume_and_get(hba->dev); 1976 + if (err < 0) { 1977 + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); 1978 + return err; 1979 + } 1980 + 1981 + return 0; 1982 + } 1983 + 2050 1984 static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, 2051 1985 struct devfreq_dev_profile *p, 2052 1986 struct devfreq_simple_ondemand_data *d) ··· 2357 2229 .freq_to_gear_speed = ufs_qcom_freq_to_gear_speed, 2358 2230 }; 2359 2231 2232 + static const struct ufs_hba_variant_ops ufs_hba_qcom_sa8255p_vops = { 2233 + .name = "qcom-sa8255p", 2234 + .init = ufs_qcom_fw_managed_init, 2235 + .exit = ufs_qcom_fw_managed_exit, 2236 + .hce_enable_notify = ufs_qcom_fw_managed_hce_enable_notify, 2237 + .pwr_change_notify = ufs_qcom_pwr_change_notify, 2238 + .apply_dev_quirks = ufs_qcom_apply_dev_quirks, 2239 + .fixup_dev_quirks = ufs_qcom_fixup_dev_quirks, 2240 + .suspend = ufs_qcom_fw_managed_suspend, 2241 + .resume = ufs_qcom_fw_managed_resume, 2242 + .dbg_register_dump = ufs_qcom_dump_dbg_regs, 2243 + .device_reset = ufs_qcom_fw_managed_device_reset, 2244 + }; 2245 + 2360 2246 /** 2361 2247 * ufs_qcom_probe - probe routine of the driver 2362 2248 * @pdev: pointer to Platform device handle ··· 2381 2239 { 2382 2240 int err; 2383 2241 struct device *dev = &pdev->dev; 2242 + const struct ufs_hba_variant_ops *vops; 2243 + const struct ufs_qcom_drvdata *drvdata = device_get_match_data(dev); 2244 + 2245 + if (drvdata && drvdata->vops) 2246 + vops = drvdata->vops; 2247 + else 2248 + vops = &ufs_hba_qcom_vops; 2384 2249 2385 2250 /* Perform generic probe */ 2386 - err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); 2251 + err = ufshcd_pltfrm_init(pdev, vops); 2387 2252 if (err) 2388 2253 return dev_err_probe(dev, err, "ufshcd_pltfrm_init() failed\n"); 2389 2254 ··· 2418 2269 .no_phy_retention = true, 2419 2270 }; 2420 2271 2272 + static const struct ufs_qcom_drvdata ufs_qcom_sa8255p_drvdata = { 2273 + .vops = &ufs_hba_qcom_sa8255p_vops 2274 + }; 2275 + 2421 2276 static const struct of_device_id ufs_qcom_of_match[] __maybe_unused = { 2422 2277 { .compatible = "qcom,ufshc" }, 2423 2278 { .compatible = "qcom,sm8550-ufshc", .data = &ufs_qcom_sm8550_drvdata }, 2424 2279 { .compatible = "qcom,sm8650-ufshc", .data = &ufs_qcom_sm8550_drvdata }, 2280 + { .compatible = "qcom,sa8255p-ufshc", .data = &ufs_qcom_sa8255p_drvdata }, 2425 2281 {}, 2426 2282 }; 2427 2283 MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
+1
drivers/ufs/host/ufs-qcom.h
··· 313 313 struct ufs_qcom_drvdata { 314 314 enum ufshcd_quirks quirks; 315 315 bool no_phy_retention; 316 + const struct ufs_hba_variant_ops *vops; 316 317 }; 317 318 318 319 static inline u32
+2
include/ufs/ufshcd.h
··· 834 834 * @uic_link_state: active state of the link to the UFS device. 835 835 * @rpm_lvl: desired UFS power management level during runtime PM. 836 836 * @spm_lvl: desired UFS power management level during system PM. 837 + * @pm_lvl_min: minimum supported power management level. 837 838 * @pm_op_in_progress: whether or not a PM operation is in progress. 838 839 * @ahit: value of Auto-Hibernate Idle Timer register. 839 840 * @outstanding_tasks: Bits representing outstanding task requests ··· 973 972 enum ufs_pm_level rpm_lvl; 974 973 /* Desired UFS power management level during system PM */ 975 974 enum ufs_pm_level spm_lvl; 975 + enum ufs_pm_level pm_lvl_min; 976 976 int pm_op_in_progress; 977 977 978 978 /* Auto-Hibernate Idle Timer register value */