1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2014 ARM Limited 5 */ 6 7 #include <linux/err.h> 8 #include <linux/init.h> 9 #include <linux/of.h> 10 #include <linux/of_device.h> 11 #include <linux/vexpress.h> 12 13 14 struct vexpress_config_bridge { 15 struct vexpress_config_bridge_ops *ops; 16 void *context; 17 }; 18 19 20 static DEFINE_MUTEX(vexpress_config_mutex); 21 static struct class *vexpress_config_class; 22 static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER; 23 24 25 void vexpress_config_set_master(u32 site) 26 { 27 vexpress_config_site_master = site; 28 } 29 30 u32 vexpress_config_get_master(void) 31 { 32 return vexpress_config_site_master; 33 } 34 35 void vexpress_config_lock(void *arg) 36 { 37 mutex_lock(&vexpress_config_mutex); 38 } 39 40 void vexpress_config_unlock(void *arg) 41 { 42 mutex_unlock(&vexpress_config_mutex); 43 } 44 45 46 static void vexpress_config_find_prop(struct device_node *node, 47 const char *name, u32 *val) 48 { 49 /* Default value */ 50 *val = 0; 51 52 of_node_get(node); 53 while (node) { 54 if (of_property_read_u32(node, name, val) == 0) { 55 of_node_put(node); 56 return; 57 } 58 node = of_get_next_parent(node); 59 } 60 } 61 62 int vexpress_config_get_topo(struct device_node *node, u32 *site, 63 u32 *position, u32 *dcc) 64 { 65 vexpress_config_find_prop(node, "arm,vexpress,site", site); 66 if (*site == VEXPRESS_SITE_MASTER) 67 *site = vexpress_config_site_master; 68 if (WARN_ON(vexpress_config_site_master == VEXPRESS_SITE_MASTER)) 69 return -EINVAL; 70 vexpress_config_find_prop(node, "arm,vexpress,position", position); 71 vexpress_config_find_prop(node, "arm,vexpress,dcc", dcc); 72 73 return 0; 74 } 75 76 77 static void vexpress_config_devres_release(struct device *dev, void *res) 78 { 79 struct vexpress_config_bridge *bridge = dev_get_drvdata(dev->parent); 80 struct regmap *regmap = res; 81 82 bridge->ops->regmap_exit(regmap, bridge->context); 83 } 84 85 struct regmap *devm_regmap_init_vexpress_config(struct device *dev) 86 { 87 struct vexpress_config_bridge *bridge; 88 struct regmap *regmap; 89 struct regmap **res; 90 91 if (WARN_ON(dev->parent->class != vexpress_config_class)) 92 return ERR_PTR(-ENODEV); 93 94 bridge = dev_get_drvdata(dev->parent); 95 if (WARN_ON(!bridge)) 96 return ERR_PTR(-EINVAL); 97 98 res = devres_alloc(vexpress_config_devres_release, sizeof(*res), 99 GFP_KERNEL); 100 if (!res) 101 return ERR_PTR(-ENOMEM); 102 103 regmap = (bridge->ops->regmap_init)(dev, bridge->context); 104 if (IS_ERR(regmap)) { 105 devres_free(res); 106 return regmap; 107 } 108 109 *res = regmap; 110 devres_add(dev, res); 111 112 return regmap; 113 } 114 EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config); 115 116 struct device *vexpress_config_bridge_register(struct device *parent, 117 struct vexpress_config_bridge_ops *ops, void *context) 118 { 119 struct device *dev; 120 struct vexpress_config_bridge *bridge; 121 122 if (!vexpress_config_class) { 123 vexpress_config_class = class_create(THIS_MODULE, 124 "vexpress-config"); 125 if (IS_ERR(vexpress_config_class)) 126 return (void *)vexpress_config_class; 127 } 128 129 dev = device_create(vexpress_config_class, parent, 0, 130 NULL, "%s.bridge", dev_name(parent)); 131 132 if (IS_ERR(dev)) 133 return dev; 134 135 bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL); 136 if (!bridge) { 137 put_device(dev); 138 device_unregister(dev); 139 return ERR_PTR(-ENOMEM); 140 } 141 bridge->ops = ops; 142 bridge->context = context; 143 144 dev_set_drvdata(dev, bridge); 145 146 dev_dbg(parent, "Registered bridge '%s', parent node %p\n", 147 dev_name(dev), parent->of_node); 148 149 return dev; 150 } 151 152 153 static int vexpress_config_node_match(struct device *dev, const void *data) 154 { 155 const struct device_node *node = data; 156 157 dev_dbg(dev, "Parent node %p, looking for %p\n", 158 dev->parent->of_node, node); 159 160 return dev->parent->of_node == node; 161 } 162 163 static int vexpress_config_populate(struct device_node *node) 164 { 165 struct device_node *bridge; 166 struct device *parent; 167 int ret; 168 169 bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0); 170 if (!bridge) 171 return -EINVAL; 172 173 parent = class_find_device(vexpress_config_class, NULL, bridge, 174 vexpress_config_node_match); 175 of_node_put(bridge); 176 if (WARN_ON(!parent)) 177 return -ENODEV; 178 179 ret = of_platform_populate(node, NULL, NULL, parent); 180 181 put_device(parent); 182 183 return ret; 184 } 185 186 static int __init vexpress_config_init(void) 187 { 188 int err = 0; 189 struct device_node *node; 190 191 /* Need the config devices early, before the "normal" devices... */ 192 for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") { 193 err = vexpress_config_populate(node); 194 if (err) { 195 of_node_put(node); 196 break; 197 } 198 } 199 200 return err; 201 } 202 postcore_initcall(vexpress_config_init); 203 204