boot_stats.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2013-2019, 2021 The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/err.h>
  8. #include <linux/io.h>
  9. #include <linux/init.h>
  10. #include <linux/delay.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/clk.h>
  14. #include <linux/cpu.h>
  15. #include <linux/sched.h>
  16. #include <linux/of.h>
  17. #include <linux/of_address.h>
  18. struct boot_stats {
  19. uint32_t bootloader_start;
  20. uint32_t bootloader_end;
  21. uint32_t bootloader_load_boot_start;
  22. uint32_t bootloader_load_boot_end;
  23. uint32_t bootloader_load_vendor_boot_start;
  24. uint32_t bootloader_load_vendor_boot_end;
  25. uint32_t bootloader_load_init_boot_start;
  26. uint32_t bootloader_load_init_boot_end;
  27. } __packed;
  28. static void __iomem *mpm_counter_base;
  29. static uint32_t mpm_counter_freq;
  30. static struct boot_stats __iomem *boot_stats;
  31. static int mpm_parse_dt(void)
  32. {
  33. struct device_node *np_imem, *np_mpm2;
  34. np_imem = of_find_compatible_node(NULL, NULL,
  35. "qcom,msm-imem-boot_stats");
  36. if (!np_imem) {
  37. pr_err("can't find qcom,msm-imem node\n");
  38. return -ENODEV;
  39. }
  40. boot_stats = of_iomap(np_imem, 0);
  41. if (!boot_stats) {
  42. pr_err("boot_stats: Can't map imem\n");
  43. goto err1;
  44. }
  45. np_mpm2 = of_find_compatible_node(NULL, NULL,
  46. "qcom,mpm2-sleep-counter");
  47. if (!np_mpm2) {
  48. pr_err("mpm_counter: can't find DT node\n");
  49. goto err1;
  50. }
  51. if (of_property_read_u32(np_mpm2, "clock-frequency", &mpm_counter_freq))
  52. goto err2;
  53. if (of_get_address(np_mpm2, 0, NULL, NULL)) {
  54. mpm_counter_base = of_iomap(np_mpm2, 0);
  55. if (!mpm_counter_base) {
  56. pr_err("mpm_counter: cant map counter base\n");
  57. goto err2;
  58. }
  59. } else
  60. goto err2;
  61. return 0;
  62. err2:
  63. of_node_put(np_mpm2);
  64. err1:
  65. of_node_put(np_imem);
  66. return -ENODEV;
  67. }
  68. static void print_boot_stats(void)
  69. {
  70. pr_info("KPI: Bootloader start count = %u\n",
  71. readl_relaxed(&boot_stats->bootloader_start));
  72. pr_info("KPI: Bootloader end count = %u\n",
  73. readl_relaxed(&boot_stats->bootloader_end));
  74. pr_info("KPI: Bootloader load kernel count = %u\n",
  75. readl_relaxed(&boot_stats->bootloader_load_boot_end) -
  76. readl_relaxed(&boot_stats->bootloader_load_boot_start));
  77. pr_info("KPI: Kernel MPM timestamp = %u\n",
  78. readl_relaxed(mpm_counter_base));
  79. pr_info("KPI: Kernel MPM Clock frequency = %u\n",
  80. mpm_counter_freq);
  81. }
  82. static int __init boot_stats_init(void)
  83. {
  84. int ret;
  85. ret = mpm_parse_dt();
  86. if (ret < 0)
  87. return -ENODEV;
  88. print_boot_stats();
  89. iounmap(boot_stats);
  90. iounmap(mpm_counter_base);
  91. return 0;
  92. }
  93. module_init(boot_stats_init);
  94. static void __exit boot_stats_exit(void)
  95. {
  96. }
  97. module_exit(boot_stats_exit)
  98. MODULE_DESCRIPTION("MSM boot stats info driver");
  99. MODULE_LICENSE("GPL v2");