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