vexpress-config.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License version 2 as
  4. * published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. * GNU General Public License for more details.
  10. *
  11. * Copyright (C) 2014 ARM Limited
  12. */
  13. #include <linux/err.h>
  14. #include <linux/init.h>
  15. #include <linux/of.h>
  16. #include <linux/of_device.h>
  17. #include <linux/vexpress.h>
  18. struct vexpress_config_bridge {
  19. struct vexpress_config_bridge_ops *ops;
  20. void *context;
  21. };
  22. static DEFINE_MUTEX(vexpress_config_mutex);
  23. static struct class *vexpress_config_class;
  24. static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER;
  25. void vexpress_config_set_master(u32 site)
  26. {
  27. vexpress_config_site_master = site;
  28. }
  29. u32 vexpress_config_get_master(void)
  30. {
  31. return vexpress_config_site_master;
  32. }
  33. void vexpress_config_lock(void *arg)
  34. {
  35. mutex_lock(&vexpress_config_mutex);
  36. }
  37. void vexpress_config_unlock(void *arg)
  38. {
  39. mutex_unlock(&vexpress_config_mutex);
  40. }
  41. static void vexpress_config_find_prop(struct device_node *node,
  42. const char *name, u32 *val)
  43. {
  44. /* Default value */
  45. *val = 0;
  46. of_node_get(node);
  47. while (node) {
  48. if (of_property_read_u32(node, name, val) == 0) {
  49. of_node_put(node);
  50. return;
  51. }
  52. node = of_get_next_parent(node);
  53. }
  54. }
  55. int vexpress_config_get_topo(struct device_node *node, u32 *site,
  56. u32 *position, u32 *dcc)
  57. {
  58. vexpress_config_find_prop(node, "arm,vexpress,site", site);
  59. if (*site == VEXPRESS_SITE_MASTER)
  60. *site = vexpress_config_site_master;
  61. if (WARN_ON(vexpress_config_site_master == VEXPRESS_SITE_MASTER))
  62. return -EINVAL;
  63. vexpress_config_find_prop(node, "arm,vexpress,position", position);
  64. vexpress_config_find_prop(node, "arm,vexpress,dcc", dcc);
  65. return 0;
  66. }
  67. static void vexpress_config_devres_release(struct device *dev, void *res)
  68. {
  69. struct vexpress_config_bridge *bridge = dev_get_drvdata(dev->parent);
  70. struct regmap *regmap = res;
  71. bridge->ops->regmap_exit(regmap, bridge->context);
  72. }
  73. struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
  74. {
  75. struct vexpress_config_bridge *bridge;
  76. struct regmap *regmap;
  77. struct regmap **res;
  78. if (WARN_ON(dev->parent->class != vexpress_config_class))
  79. return ERR_PTR(-ENODEV);
  80. bridge = dev_get_drvdata(dev->parent);
  81. if (WARN_ON(!bridge))
  82. return ERR_PTR(-EINVAL);
  83. res = devres_alloc(vexpress_config_devres_release, sizeof(*res),
  84. GFP_KERNEL);
  85. if (!res)
  86. return ERR_PTR(-ENOMEM);
  87. regmap = (bridge->ops->regmap_init)(dev, bridge->context);
  88. if (IS_ERR(regmap)) {
  89. devres_free(res);
  90. return regmap;
  91. }
  92. *res = regmap;
  93. devres_add(dev, res);
  94. return regmap;
  95. }
  96. EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config);
  97. struct device *vexpress_config_bridge_register(struct device *parent,
  98. struct vexpress_config_bridge_ops *ops, void *context)
  99. {
  100. struct device *dev;
  101. struct vexpress_config_bridge *bridge;
  102. if (!vexpress_config_class) {
  103. vexpress_config_class = class_create(THIS_MODULE,
  104. "vexpress-config");
  105. if (IS_ERR(vexpress_config_class))
  106. return (void *)vexpress_config_class;
  107. }
  108. dev = device_create(vexpress_config_class, parent, 0,
  109. NULL, "%s.bridge", dev_name(parent));
  110. if (IS_ERR(dev))
  111. return dev;
  112. bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL);
  113. if (!bridge) {
  114. put_device(dev);
  115. device_unregister(dev);
  116. return ERR_PTR(-ENOMEM);
  117. }
  118. bridge->ops = ops;
  119. bridge->context = context;
  120. dev_set_drvdata(dev, bridge);
  121. dev_dbg(parent, "Registered bridge '%s', parent node %p\n",
  122. dev_name(dev), parent->of_node);
  123. return dev;
  124. }
  125. static int vexpress_config_node_match(struct device *dev, const void *data)
  126. {
  127. const struct device_node *node = data;
  128. dev_dbg(dev, "Parent node %p, looking for %p\n",
  129. dev->parent->of_node, node);
  130. return dev->parent->of_node == node;
  131. }
  132. static int vexpress_config_populate(struct device_node *node)
  133. {
  134. struct device_node *bridge;
  135. struct device *parent;
  136. int ret;
  137. bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
  138. if (!bridge)
  139. return -EINVAL;
  140. parent = class_find_device(vexpress_config_class, NULL, bridge,
  141. vexpress_config_node_match);
  142. of_node_put(bridge);
  143. if (WARN_ON(!parent))
  144. return -ENODEV;
  145. ret = of_platform_populate(node, NULL, NULL, parent);
  146. put_device(parent);
  147. return ret;
  148. }
  149. static int __init vexpress_config_init(void)
  150. {
  151. int err = 0;
  152. struct device_node *node;
  153. /* Need the config devices early, before the "normal" devices... */
  154. for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
  155. err = vexpress_config_populate(node);
  156. if (err) {
  157. of_node_put(node);
  158. break;
  159. }
  160. }
  161. return err;
  162. }
  163. postcore_initcall(vexpress_config_init);