reset-microchip-sparx5.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /* Microchip Sparx5 Switch Reset driver
  3. *
  4. * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
  5. *
  6. * The Sparx5 Chip Register Model can be browsed at this location:
  7. * https://github.com/microchip-ung/sparx-5_reginfo
  8. */
  9. #include <linux/mfd/syscon.h>
  10. #include <linux/of.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/property.h>
  14. #include <linux/regmap.h>
  15. #include <linux/reset-controller.h>
  16. struct reset_props {
  17. u32 protect_reg;
  18. u32 protect_bit;
  19. u32 reset_reg;
  20. u32 reset_bit;
  21. };
  22. struct mchp_reset_context {
  23. struct regmap *cpu_ctrl;
  24. struct regmap *gcb_ctrl;
  25. struct reset_controller_dev rcdev;
  26. const struct reset_props *props;
  27. };
  28. static struct regmap_config sparx5_reset_regmap_config = {
  29. .reg_bits = 32,
  30. .val_bits = 32,
  31. .reg_stride = 4,
  32. };
  33. static int sparx5_switch_reset(struct mchp_reset_context *ctx)
  34. {
  35. u32 val;
  36. /* Make sure the core is PROTECTED from reset */
  37. regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
  38. ctx->props->protect_bit, ctx->props->protect_bit);
  39. /* Start soft reset */
  40. regmap_write(ctx->gcb_ctrl, ctx->props->reset_reg,
  41. ctx->props->reset_bit);
  42. /* Wait for soft reset done */
  43. return regmap_read_poll_timeout(ctx->gcb_ctrl, ctx->props->reset_reg, val,
  44. (val & ctx->props->reset_bit) == 0,
  45. 1, 100);
  46. }
  47. static int sparx5_reset_noop(struct reset_controller_dev *rcdev,
  48. unsigned long id)
  49. {
  50. return 0;
  51. }
  52. static const struct reset_control_ops sparx5_reset_ops = {
  53. .reset = sparx5_reset_noop,
  54. };
  55. static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name,
  56. struct regmap **target)
  57. {
  58. struct device_node *syscon_np;
  59. struct regmap *regmap;
  60. int err;
  61. syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0);
  62. if (!syscon_np)
  63. return -ENODEV;
  64. regmap = syscon_node_to_regmap(syscon_np);
  65. of_node_put(syscon_np);
  66. if (IS_ERR(regmap)) {
  67. err = PTR_ERR(regmap);
  68. dev_err(&pdev->dev, "No '%s' map: %d\n", name, err);
  69. return err;
  70. }
  71. *target = regmap;
  72. return 0;
  73. }
  74. static int mchp_sparx5_map_io(struct platform_device *pdev, int index,
  75. struct regmap **target)
  76. {
  77. struct resource *res;
  78. struct regmap *map;
  79. void __iomem *mem;
  80. mem = devm_platform_get_and_ioremap_resource(pdev, index, &res);
  81. if (IS_ERR(mem)) {
  82. dev_err(&pdev->dev, "Could not map resource %d\n", index);
  83. return PTR_ERR(mem);
  84. }
  85. sparx5_reset_regmap_config.name = res->name;
  86. map = devm_regmap_init_mmio(&pdev->dev, mem, &sparx5_reset_regmap_config);
  87. if (IS_ERR(map))
  88. return PTR_ERR(map);
  89. *target = map;
  90. return 0;
  91. }
  92. static int mchp_sparx5_reset_probe(struct platform_device *pdev)
  93. {
  94. struct device_node *dn = pdev->dev.of_node;
  95. struct mchp_reset_context *ctx;
  96. int err;
  97. ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
  98. if (!ctx)
  99. return -ENOMEM;
  100. err = mchp_sparx5_map_syscon(pdev, "cpu-syscon", &ctx->cpu_ctrl);
  101. if (err)
  102. return err;
  103. err = mchp_sparx5_map_io(pdev, 0, &ctx->gcb_ctrl);
  104. if (err)
  105. return err;
  106. ctx->rcdev.owner = THIS_MODULE;
  107. ctx->rcdev.nr_resets = 1;
  108. ctx->rcdev.ops = &sparx5_reset_ops;
  109. ctx->rcdev.of_node = dn;
  110. ctx->props = device_get_match_data(&pdev->dev);
  111. /* Issue the reset very early, our actual reset callback is a noop. */
  112. err = sparx5_switch_reset(ctx);
  113. if (err)
  114. return err;
  115. return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
  116. }
  117. static const struct reset_props reset_props_sparx5 = {
  118. .protect_reg = 0x84,
  119. .protect_bit = BIT(10),
  120. .reset_reg = 0x0,
  121. .reset_bit = BIT(1),
  122. };
  123. static const struct reset_props reset_props_lan966x = {
  124. .protect_reg = 0x88,
  125. .protect_bit = BIT(5),
  126. .reset_reg = 0x0,
  127. .reset_bit = BIT(1),
  128. };
  129. static const struct of_device_id mchp_sparx5_reset_of_match[] = {
  130. {
  131. .compatible = "microchip,sparx5-switch-reset",
  132. .data = &reset_props_sparx5,
  133. }, {
  134. .compatible = "microchip,lan966x-switch-reset",
  135. .data = &reset_props_lan966x,
  136. },
  137. { }
  138. };
  139. static struct platform_driver mchp_sparx5_reset_driver = {
  140. .probe = mchp_sparx5_reset_probe,
  141. .driver = {
  142. .name = "sparx5-switch-reset",
  143. .of_match_table = mchp_sparx5_reset_of_match,
  144. },
  145. };
  146. static int __init mchp_sparx5_reset_init(void)
  147. {
  148. return platform_driver_register(&mchp_sparx5_reset_driver);
  149. }
  150. /*
  151. * Because this is a global reset, keep this postcore_initcall() to issue the
  152. * reset as early as possible during the kernel startup.
  153. */
  154. postcore_initcall(mchp_sparx5_reset_init);
  155. MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver");
  156. MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");