Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2 203 lines 4.4 kB view raw
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 14struct vexpress_config_bridge { 15 struct vexpress_config_bridge_ops *ops; 16 void *context; 17}; 18 19 20static DEFINE_MUTEX(vexpress_config_mutex); 21static struct class *vexpress_config_class; 22static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER; 23 24 25void vexpress_config_set_master(u32 site) 26{ 27 vexpress_config_site_master = site; 28} 29 30u32 vexpress_config_get_master(void) 31{ 32 return vexpress_config_site_master; 33} 34 35void vexpress_config_lock(void *arg) 36{ 37 mutex_lock(&vexpress_config_mutex); 38} 39 40void vexpress_config_unlock(void *arg) 41{ 42 mutex_unlock(&vexpress_config_mutex); 43} 44 45 46static 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 62int 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 77static 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 85struct 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} 114EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config); 115 116struct 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 153static 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 163static 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 186static 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} 202postcore_initcall(vexpress_config_init); 203