• Home
  • Raw
  • Download

Lines Matching +full:sdm845 +full:- +full:cpu +full:- +full:bwmon

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2021-2022 Linaro Ltd
6 * previous work of Thara Gopinath and msm-4.9 downstream sources.
22 * The BWMON samples data throughput within 'sample_ms' time. With three
46 * Starting with SDM845, the BWMON4 register space has changed a bit:
51 * implementations to work, offset the global registers by -0x100 to avoid
55 #define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET)
56 #define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET)
129 /* Quirks for specific BWMON types */
193 /* BWMON v4 */
256 * Fill the cache for non-readable registers only as rest does not really
273 * No concurrent access expected - driver has one interrupt handler,
274 * regmap is not shared, no driver or user-space API.
282 * Cache is necessary for using regmap fields with non-readable
293 * No concurrent access expected - driver has one interrupt handler,
294 * regmap is not shared, no driver or user-space API.
301 * Cache is necessary for using regmap fields with non-readable
346 * Fill the cache for non-readable registers only as rest does not really
360 * No concurrent access expected - driver has one interrupt handler,
361 * regmap is not shared, no driver or user-space API.
369 * Cache is necessary for using regmap fields with non-readable
375 /* BWMON v5 */
424 * Fill the cache for non-readable registers only as rest does not really
437 * No concurrent access expected - driver has one interrupt handler,
438 * regmap is not shared, no driver or user-space API.
446 * Cache is necessary for using regmap fields with non-readable
452 static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all) in bwmon_clear_counters() argument
460 * important. Quoting downstream Qualcomm msm-4.9 tree: in bwmon_clear_counters()
466 regmap_field_force_write(bwmon->regs[F_CLEAR], val); in bwmon_clear_counters()
467 if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) in bwmon_clear_counters()
468 regmap_field_force_write(bwmon->regs[F_CLEAR], 0); in bwmon_clear_counters()
471 static void bwmon_clear_irq(struct icc_bwmon *bwmon) in bwmon_clear_irq() argument
475 if (bwmon->data->global_regmap_fields) in bwmon_clear_irq()
476 global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR]; in bwmon_clear_irq()
478 global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR]; in bwmon_clear_irq()
482 * important. Quoting downstream Qualcomm msm-4.9 tree: in bwmon_clear_irq()
485 * with the global interrupt clear here. Otherwise, the CPU in bwmon_clear_irq()
496 regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK); in bwmon_clear_irq()
497 if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) in bwmon_clear_irq()
498 regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0); in bwmon_clear_irq()
499 if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) in bwmon_clear_irq()
504 static void bwmon_disable(struct icc_bwmon *bwmon) in bwmon_disable() argument
508 if (bwmon->data->global_regmap_fields) in bwmon_disable()
509 global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; in bwmon_disable()
511 global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; in bwmon_disable()
514 if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) in bwmon_disable()
516 regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0); in bwmon_disable()
519 * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious in bwmon_disable()
522 regmap_field_write(bwmon->regs[F_ENABLE], 0x0); in bwmon_disable()
525 static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable) in bwmon_enable() argument
529 if (bwmon->data->global_regmap_fields) in bwmon_enable()
530 global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; in bwmon_enable()
532 global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; in bwmon_enable()
535 if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) in bwmon_enable()
539 regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable); in bwmon_enable()
541 /* Enable bwmon */ in bwmon_enable()
542 regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE); in bwmon_enable()
545 static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon, in bwmon_kbps_to_count() argument
548 return kbps / bwmon->data->count_unit_kb; in bwmon_kbps_to_count()
551 static void bwmon_set_threshold(struct icc_bwmon *bwmon, in bwmon_set_threshold() argument
556 thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps), in bwmon_set_threshold()
557 bwmon->data->sample_ms, MSEC_PER_SEC); in bwmon_set_threshold()
561 static void bwmon_start(struct icc_bwmon *bwmon) in bwmon_start() argument
563 const struct icc_bwmon_data *data = bwmon->data; in bwmon_start()
568 dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0); in bwmon_start()
570 bwmon_clear_counters(bwmon, true); in bwmon_start()
572 window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC); in bwmon_start()
574 regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window); in bwmon_start()
576 bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], bw_low); in bwmon_start()
577 bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], bw_low); in bwmon_start()
578 bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 0); in bwmon_start()
580 regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0], in bwmon_start()
582 regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1], in bwmon_start()
583 data->zone1_thres_count); in bwmon_start()
584 regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2], in bwmon_start()
586 regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3], in bwmon_start()
587 data->zone3_thres_count); in bwmon_start()
589 regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0], in bwmon_start()
591 regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1], in bwmon_start()
593 regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2], in bwmon_start()
595 regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3], in bwmon_start()
598 bwmon_clear_irq(bwmon); in bwmon_start()
599 bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK); in bwmon_start()
604 struct icc_bwmon *bwmon = dev_id; in bwmon_intr() local
608 if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status)) in bwmon_intr()
625 bwmon_disable(bwmon); in bwmon_intr()
627 zone = get_bitmask_order(status) - 1; in bwmon_intr()
630 * window. Downstream kernel for BWMONv4 (called BWMON type 2 in in bwmon_intr()
633 if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max)) in bwmon_intr()
637 max *= bwmon->data->count_unit_kb; in bwmon_intr()
638 bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms); in bwmon_intr()
645 struct icc_bwmon *bwmon = dev_id; in bwmon_intr_thread() local
650 bw_kbps = bwmon->target_kbps; in bwmon_intr_thread()
652 target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0); in bwmon_intr_thread()
653 if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) in bwmon_intr_thread()
654 target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); in bwmon_intr_thread()
656 bwmon->target_kbps = bw_kbps; in bwmon_intr_thread()
658 bw_kbps--; in bwmon_intr_thread()
659 opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); in bwmon_intr_thread()
660 if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE) in bwmon_intr_thread()
661 down_kbps = bwmon->target_kbps; in bwmon_intr_thread()
665 up_kbps = bwmon->target_kbps + 1; in bwmon_intr_thread()
667 if (bwmon->target_kbps >= bwmon->max_bw_kbps) in bwmon_intr_thread()
669 else if (bwmon->target_kbps <= bwmon->min_bw_kbps) in bwmon_intr_thread()
674 bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], in bwmon_intr_thread()
676 bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], in bwmon_intr_thread()
678 bwmon_clear_counters(bwmon, false); in bwmon_intr_thread()
679 bwmon_clear_irq(bwmon); in bwmon_intr_thread()
680 bwmon_enable(bwmon, irq_enable); in bwmon_intr_thread()
682 if (bwmon->target_kbps == bwmon->current_kbps) in bwmon_intr_thread()
685 dev_pm_opp_set_opp(bwmon->dev, target_opp); in bwmon_intr_thread()
686 bwmon->current_kbps = bwmon->target_kbps; in bwmon_intr_thread()
697 struct icc_bwmon *bwmon) in bwmon_init_regmap() argument
699 struct device *dev = &pdev->dev; in bwmon_init_regmap()
708 "failed to map bwmon registers\n"); in bwmon_init_regmap()
710 map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg); in bwmon_init_regmap()
720 ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs, in bwmon_init_regmap()
721 bwmon->data->regmap_fields, in bwmon_init_regmap()
726 if (bwmon->data->global_regmap_cfg) { in bwmon_init_regmap()
731 "failed to map bwmon global registers\n"); in bwmon_init_regmap()
733 map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg); in bwmon_init_regmap()
738 ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs, in bwmon_init_regmap()
739 bwmon->data->global_regmap_fields, in bwmon_init_regmap()
748 struct device *dev = &pdev->dev; in bwmon_probe()
750 struct icc_bwmon *bwmon; in bwmon_probe() local
753 bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL); in bwmon_probe()
754 if (!bwmon) in bwmon_probe()
755 return -ENOMEM; in bwmon_probe()
757 bwmon->data = of_device_get_match_data(dev); in bwmon_probe()
759 ret = bwmon_init_regmap(pdev, bwmon); in bwmon_probe()
763 bwmon->irq = platform_get_irq(pdev, 0); in bwmon_probe()
764 if (bwmon->irq < 0) in bwmon_probe()
765 return bwmon->irq; in bwmon_probe()
771 bwmon->max_bw_kbps = UINT_MAX; in bwmon_probe()
772 opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0); in bwmon_probe()
776 bwmon->min_bw_kbps = 0; in bwmon_probe()
777 opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0); in bwmon_probe()
781 bwmon->dev = dev; in bwmon_probe()
783 bwmon_disable(bwmon); in bwmon_probe()
784 ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr, in bwmon_probe()
786 IRQF_ONESHOT, dev_name(dev), bwmon); in bwmon_probe()
790 platform_set_drvdata(pdev, bwmon); in bwmon_probe()
791 bwmon_start(bwmon); in bwmon_probe()
798 struct icc_bwmon *bwmon = platform_get_drvdata(pdev); in bwmon_remove() local
800 bwmon_disable(bwmon); in bwmon_remove()
848 { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
850 { .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data },
852 { .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data },
853 { .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data },
856 { .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
857 { .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
858 { .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
867 .name = "qcom-bwmon",
874 MODULE_DESCRIPTION("QCOM BWMON driver");