reboot-mode-uclass.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c), Vaisala Oyj
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <dm/device_compat.h>
  8. #include <dm/devres.h>
  9. #include <exports.h>
  10. #include <reboot-mode/reboot-mode.h>
  11. DECLARE_GLOBAL_DATA_PTR;
  12. int dm_reboot_mode_update(struct udevice *dev)
  13. {
  14. struct reboot_mode_ops *ops = reboot_mode_get_ops(dev);
  15. u32 rebootmode;
  16. int ret, i;
  17. assert(ops);
  18. if (!ops->get)
  19. return -ENOSYS;
  20. ret = ops->get(dev, &rebootmode);
  21. if (ret < 0) {
  22. dev_err(dev, "Failed to retrieve the reboot mode value\n");
  23. return ret;
  24. }
  25. const struct reboot_mode_uclass_platdata *plat_data =
  26. dev_get_uclass_plat(dev);
  27. for (i = 0; i < plat_data->count; i++) {
  28. if (plat_data->modes[i].mode_id == rebootmode) {
  29. ret = env_set(plat_data->env_variable,
  30. plat_data->modes[i].mode_name);
  31. if (ret) {
  32. dev_err(dev, "Failed to set env: %s\n",
  33. plat_data->env_variable);
  34. return ret;
  35. }
  36. }
  37. }
  38. if (ops->set) {
  39. /* Clear the value */
  40. rebootmode = 0;
  41. ret = ops->set(dev, rebootmode);
  42. if (ret) {
  43. dev_err(dev, "Failed to clear the reboot mode\n");
  44. return ret;
  45. }
  46. }
  47. return 0;
  48. }
  49. int dm_reboot_mode_pre_probe(struct udevice *dev)
  50. {
  51. struct reboot_mode_uclass_platdata *plat_data;
  52. plat_data = dev_get_uclass_plat(dev);
  53. if (!plat_data)
  54. return -EINVAL;
  55. #if CONFIG_IS_ENABLED(OF_CONTROL)
  56. const int node = dev_of_offset(dev);
  57. const char *mode_prefix = "mode-";
  58. const int mode_prefix_len = strlen(mode_prefix);
  59. int property;
  60. const u32 *propvalue;
  61. const char *propname;
  62. plat_data->env_variable = fdt_getprop(gd->fdt_blob,
  63. node,
  64. "u-boot,env-variable",
  65. NULL);
  66. if (!plat_data->env_variable)
  67. plat_data->env_variable = "reboot-mode";
  68. plat_data->count = 0;
  69. fdt_for_each_property_offset(property, gd->fdt_blob, node) {
  70. propvalue = fdt_getprop_by_offset(gd->fdt_blob,
  71. property, &propname, NULL);
  72. if (!propvalue) {
  73. dev_err(dev, "Could not get the value for property %s\n",
  74. propname);
  75. return -EINVAL;
  76. }
  77. if (!strncmp(propname, mode_prefix, mode_prefix_len))
  78. plat_data->count++;
  79. }
  80. plat_data->modes = devm_kcalloc(dev, plat_data->count,
  81. sizeof(struct reboot_mode_mode), 0);
  82. struct reboot_mode_mode *next = plat_data->modes;
  83. fdt_for_each_property_offset(property, gd->fdt_blob, node) {
  84. propvalue = fdt_getprop_by_offset(gd->fdt_blob,
  85. property, &propname, NULL);
  86. if (!propvalue) {
  87. dev_err(dev, "Could not get the value for property %s\n",
  88. propname);
  89. return -EINVAL;
  90. }
  91. if (!strncmp(propname, mode_prefix, mode_prefix_len)) {
  92. next->mode_name = &propname[mode_prefix_len];
  93. next->mode_id = fdt32_to_cpu(*propvalue);
  94. next++;
  95. }
  96. }
  97. #else
  98. if (!plat_data->env_variable)
  99. plat_data->env_variable = "reboot-mode";
  100. #endif
  101. return 0;
  102. }
  103. UCLASS_DRIVER(reboot_mode) = {
  104. .name = "reboot-mode",
  105. .id = UCLASS_REBOOT_MODE,
  106. .pre_probe = dm_reboot_mode_pre_probe,
  107. .per_device_plat_auto =
  108. sizeof(struct reboot_mode_uclass_platdata),
  109. };