pm.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/arm/mach-socfpga/pm.c
  4. *
  5. * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
  6. *
  7. * with code from pm-imx6.c
  8. * Copyright 2011-2014 Freescale Semiconductor, Inc.
  9. * Copyright 2011 Linaro Ltd.
  10. */
  11. #include <linux/bitops.h>
  12. #include <linux/genalloc.h>
  13. #include <linux/init.h>
  14. #include <linux/io.h>
  15. #include <linux/of_platform.h>
  16. #include <linux/suspend.h>
  17. #include <asm/suspend.h>
  18. #include <asm/fncpy.h>
  19. #include "core.h"
  20. /* Pointer to function copied to ocram */
  21. static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);
  22. static int socfpga_setup_ocram_self_refresh(void)
  23. {
  24. struct platform_device *pdev;
  25. phys_addr_t ocram_pbase;
  26. struct device_node *np;
  27. struct gen_pool *ocram_pool;
  28. unsigned long ocram_base;
  29. void __iomem *suspend_ocram_base;
  30. int ret = 0;
  31. np = of_find_compatible_node(NULL, NULL, "mmio-sram");
  32. if (!np) {
  33. pr_err("%s: Unable to find mmio-sram in dtb\n", __func__);
  34. return -ENODEV;
  35. }
  36. pdev = of_find_device_by_node(np);
  37. if (!pdev) {
  38. pr_warn("%s: failed to find ocram device!\n", __func__);
  39. ret = -ENODEV;
  40. goto put_node;
  41. }
  42. ocram_pool = gen_pool_get(&pdev->dev, NULL);
  43. if (!ocram_pool) {
  44. pr_warn("%s: ocram pool unavailable!\n", __func__);
  45. ret = -ENODEV;
  46. goto put_device;
  47. }
  48. ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz);
  49. if (!ocram_base) {
  50. pr_warn("%s: unable to alloc ocram!\n", __func__);
  51. ret = -ENOMEM;
  52. goto put_device;
  53. }
  54. ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
  55. suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
  56. socfpga_sdram_self_refresh_sz,
  57. false);
  58. if (!suspend_ocram_base) {
  59. pr_warn("%s: __arm_ioremap_exec failed!\n", __func__);
  60. ret = -ENOMEM;
  61. goto put_device;
  62. }
  63. /* Copy the code that puts DDR in self refresh to ocram */
  64. socfpga_sdram_self_refresh_in_ocram =
  65. (void *)fncpy(suspend_ocram_base,
  66. &socfpga_sdram_self_refresh,
  67. socfpga_sdram_self_refresh_sz);
  68. WARN(!socfpga_sdram_self_refresh_in_ocram,
  69. "could not copy function to ocram");
  70. if (!socfpga_sdram_self_refresh_in_ocram)
  71. ret = -EFAULT;
  72. put_device:
  73. put_device(&pdev->dev);
  74. put_node:
  75. of_node_put(np);
  76. return ret;
  77. }
  78. static int socfpga_pm_suspend(unsigned long arg)
  79. {
  80. u32 ret;
  81. if (!sdr_ctl_base_addr)
  82. return -EFAULT;
  83. ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr);
  84. pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__,
  85. ret & 0xffff, (ret >> 16) & 0xffff);
  86. return 0;
  87. }
  88. static int socfpga_pm_enter(suspend_state_t state)
  89. {
  90. switch (state) {
  91. case PM_SUSPEND_MEM:
  92. outer_disable();
  93. cpu_suspend(0, socfpga_pm_suspend);
  94. outer_resume();
  95. break;
  96. default:
  97. return -EINVAL;
  98. }
  99. return 0;
  100. }
  101. static const struct platform_suspend_ops socfpga_pm_ops = {
  102. .valid = suspend_valid_only_mem,
  103. .enter = socfpga_pm_enter,
  104. };
  105. static int __init socfpga_pm_init(void)
  106. {
  107. int ret;
  108. ret = socfpga_setup_ocram_self_refresh();
  109. if (ret)
  110. return ret;
  111. suspend_set_ops(&socfpga_pm_ops);
  112. pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");
  113. return 0;
  114. }
  115. arch_initcall(socfpga_pm_init);