1473f01f7SAlan Tull // SPDX-License-Identifier: GPL-2.0 2ef3acdd8SAlan Tull /* 3ef3acdd8SAlan Tull * FPGA Region - Device Tree support for FPGA programming under Linux 4ef3acdd8SAlan Tull * 5ef3acdd8SAlan Tull * Copyright (C) 2013-2016 Altera Corporation 6ef3acdd8SAlan Tull * Copyright (C) 2017 Intel Corporation 7ef3acdd8SAlan Tull */ 8ef3acdd8SAlan Tull #include <linux/fpga/fpga-bridge.h> 9ef3acdd8SAlan Tull #include <linux/fpga/fpga-mgr.h> 10ef3acdd8SAlan Tull #include <linux/fpga/fpga-region.h> 11ef3acdd8SAlan Tull #include <linux/idr.h> 12ef3acdd8SAlan Tull #include <linux/kernel.h> 13ef3acdd8SAlan Tull #include <linux/list.h> 14ef3acdd8SAlan Tull #include <linux/module.h> 15ef3acdd8SAlan Tull #include <linux/of_platform.h> 16ef3acdd8SAlan Tull #include <linux/slab.h> 17ef3acdd8SAlan Tull #include <linux/spinlock.h> 18ef3acdd8SAlan Tull 19ef3acdd8SAlan Tull static const struct of_device_id fpga_region_of_match[] = { 20ef3acdd8SAlan Tull { .compatible = "fpga-region", }, 21ef3acdd8SAlan Tull {}, 22ef3acdd8SAlan Tull }; 23ef3acdd8SAlan Tull MODULE_DEVICE_TABLE(of, fpga_region_of_match); 24ef3acdd8SAlan Tull 25ef3acdd8SAlan Tull static int fpga_region_of_node_match(struct device *dev, const void *data) 26ef3acdd8SAlan Tull { 27ef3acdd8SAlan Tull return dev->of_node == data; 28ef3acdd8SAlan Tull } 29ef3acdd8SAlan Tull 30ef3acdd8SAlan Tull /** 31ef3acdd8SAlan Tull * of_fpga_region_find - find FPGA region 32ef3acdd8SAlan Tull * @np: device node of FPGA Region 33ef3acdd8SAlan Tull * 34ef3acdd8SAlan Tull * Caller will need to put_device(®ion->dev) when done. 35ef3acdd8SAlan Tull * 36ef3acdd8SAlan Tull * Returns FPGA Region struct or NULL 37ef3acdd8SAlan Tull */ 38ef3acdd8SAlan Tull static struct fpga_region *of_fpga_region_find(struct device_node *np) 39ef3acdd8SAlan Tull { 40ef3acdd8SAlan Tull return fpga_region_class_find(NULL, np, fpga_region_of_node_match); 41ef3acdd8SAlan Tull } 42ef3acdd8SAlan Tull 43ef3acdd8SAlan Tull /** 44ef3acdd8SAlan Tull * of_fpga_region_get_mgr - get reference for FPGA manager 45ef3acdd8SAlan Tull * @np: device node of FPGA region 46ef3acdd8SAlan Tull * 47ef3acdd8SAlan Tull * Get FPGA Manager from "fpga-mgr" property or from ancestor region. 48ef3acdd8SAlan Tull * 49ef3acdd8SAlan Tull * Caller should call fpga_mgr_put() when done with manager. 50ef3acdd8SAlan Tull * 51ef3acdd8SAlan Tull * Return: fpga manager struct or IS_ERR() condition containing error code. 52ef3acdd8SAlan Tull */ 53ef3acdd8SAlan Tull static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) 54ef3acdd8SAlan Tull { 55ef3acdd8SAlan Tull struct device_node *mgr_node; 56ef3acdd8SAlan Tull struct fpga_manager *mgr; 57ef3acdd8SAlan Tull 58ef3acdd8SAlan Tull of_node_get(np); 59ef3acdd8SAlan Tull while (np) { 60ef3acdd8SAlan Tull if (of_device_is_compatible(np, "fpga-region")) { 61ef3acdd8SAlan Tull mgr_node = of_parse_phandle(np, "fpga-mgr", 0); 62ef3acdd8SAlan Tull if (mgr_node) { 63ef3acdd8SAlan Tull mgr = of_fpga_mgr_get(mgr_node); 640f5eb154SIan Abbott of_node_put(mgr_node); 65ef3acdd8SAlan Tull of_node_put(np); 66ef3acdd8SAlan Tull return mgr; 67ef3acdd8SAlan Tull } 68ef3acdd8SAlan Tull } 69ef3acdd8SAlan Tull np = of_get_next_parent(np); 70ef3acdd8SAlan Tull } 71ef3acdd8SAlan Tull of_node_put(np); 72ef3acdd8SAlan Tull 73ef3acdd8SAlan Tull return ERR_PTR(-EINVAL); 74ef3acdd8SAlan Tull } 75ef3acdd8SAlan Tull 76ef3acdd8SAlan Tull /** 77ef3acdd8SAlan Tull * of_fpga_region_get_bridges - create a list of bridges 78ef3acdd8SAlan Tull * @region: FPGA region 79ef3acdd8SAlan Tull * 80ef3acdd8SAlan Tull * Create a list of bridges including the parent bridge and the bridges 81ef3acdd8SAlan Tull * specified by "fpga-bridges" property. Note that the 82ef3acdd8SAlan Tull * fpga_bridges_enable/disable/put functions are all fine with an empty list 83ef3acdd8SAlan Tull * if that happens. 84ef3acdd8SAlan Tull * 85ef3acdd8SAlan Tull * Caller should call fpga_bridges_put(®ion->bridge_list) when 86ef3acdd8SAlan Tull * done with the bridges. 87ef3acdd8SAlan Tull * 88ef3acdd8SAlan Tull * Return 0 for success (even if there are no bridges specified) 89ef3acdd8SAlan Tull * or -EBUSY if any of the bridges are in use. 90ef3acdd8SAlan Tull */ 91ef3acdd8SAlan Tull static int of_fpga_region_get_bridges(struct fpga_region *region) 92ef3acdd8SAlan Tull { 93ef3acdd8SAlan Tull struct device *dev = ®ion->dev; 94ef3acdd8SAlan Tull struct device_node *region_np = dev->of_node; 95ef3acdd8SAlan Tull struct fpga_image_info *info = region->info; 96ef3acdd8SAlan Tull struct device_node *br, *np, *parent_br = NULL; 97ef3acdd8SAlan Tull int i, ret; 98ef3acdd8SAlan Tull 99ef3acdd8SAlan Tull /* If parent is a bridge, add to list */ 100ef3acdd8SAlan Tull ret = of_fpga_bridge_get_to_list(region_np->parent, info, 101ef3acdd8SAlan Tull ®ion->bridge_list); 102ef3acdd8SAlan Tull 103ef3acdd8SAlan Tull /* -EBUSY means parent is a bridge that is under use. Give up. */ 104ef3acdd8SAlan Tull if (ret == -EBUSY) 105ef3acdd8SAlan Tull return ret; 106ef3acdd8SAlan Tull 107ef3acdd8SAlan Tull /* Zero return code means parent was a bridge and was added to list. */ 108ef3acdd8SAlan Tull if (!ret) 109ef3acdd8SAlan Tull parent_br = region_np->parent; 110ef3acdd8SAlan Tull 111ef3acdd8SAlan Tull /* If overlay has a list of bridges, use it. */ 1120f5eb154SIan Abbott br = of_parse_phandle(info->overlay, "fpga-bridges", 0); 1130f5eb154SIan Abbott if (br) { 1140f5eb154SIan Abbott of_node_put(br); 115ef3acdd8SAlan Tull np = info->overlay; 1160f5eb154SIan Abbott } else { 117ef3acdd8SAlan Tull np = region_np; 1180f5eb154SIan Abbott } 119ef3acdd8SAlan Tull 120ef3acdd8SAlan Tull for (i = 0; ; i++) { 121ef3acdd8SAlan Tull br = of_parse_phandle(np, "fpga-bridges", i); 122ef3acdd8SAlan Tull if (!br) 123ef3acdd8SAlan Tull break; 124ef3acdd8SAlan Tull 125ef3acdd8SAlan Tull /* If parent bridge is in list, skip it. */ 1260f5eb154SIan Abbott if (br == parent_br) { 1270f5eb154SIan Abbott of_node_put(br); 128ef3acdd8SAlan Tull continue; 1290f5eb154SIan Abbott } 130ef3acdd8SAlan Tull 131ef3acdd8SAlan Tull /* If node is a bridge, get it and add to list */ 132ef3acdd8SAlan Tull ret = of_fpga_bridge_get_to_list(br, info, 133ef3acdd8SAlan Tull ®ion->bridge_list); 1340f5eb154SIan Abbott of_node_put(br); 135ef3acdd8SAlan Tull 136ef3acdd8SAlan Tull /* If any of the bridges are in use, give up */ 137ef3acdd8SAlan Tull if (ret == -EBUSY) { 138ef3acdd8SAlan Tull fpga_bridges_put(®ion->bridge_list); 139ef3acdd8SAlan Tull return -EBUSY; 140ef3acdd8SAlan Tull } 141ef3acdd8SAlan Tull } 142ef3acdd8SAlan Tull 143ef3acdd8SAlan Tull return 0; 144ef3acdd8SAlan Tull } 145ef3acdd8SAlan Tull 146ef3acdd8SAlan Tull /** 147ef3acdd8SAlan Tull * child_regions_with_firmware 148ef3acdd8SAlan Tull * @overlay: device node of the overlay 149ef3acdd8SAlan Tull * 150ef3acdd8SAlan Tull * If the overlay adds child FPGA regions, they are not allowed to have 151ef3acdd8SAlan Tull * firmware-name property. 152ef3acdd8SAlan Tull * 153ef3acdd8SAlan Tull * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. 154ef3acdd8SAlan Tull */ 155ef3acdd8SAlan Tull static int child_regions_with_firmware(struct device_node *overlay) 156ef3acdd8SAlan Tull { 157ef3acdd8SAlan Tull struct device_node *child_region; 158ef3acdd8SAlan Tull const char *child_firmware_name; 159ef3acdd8SAlan Tull int ret = 0; 160ef3acdd8SAlan Tull 161ef3acdd8SAlan Tull of_node_get(overlay); 162ef3acdd8SAlan Tull 163ef3acdd8SAlan Tull child_region = of_find_matching_node(overlay, fpga_region_of_match); 164ef3acdd8SAlan Tull while (child_region) { 165ef3acdd8SAlan Tull if (!of_property_read_string(child_region, "firmware-name", 166ef3acdd8SAlan Tull &child_firmware_name)) { 167ef3acdd8SAlan Tull ret = -EINVAL; 168ef3acdd8SAlan Tull break; 169ef3acdd8SAlan Tull } 170ef3acdd8SAlan Tull child_region = of_find_matching_node(child_region, 171ef3acdd8SAlan Tull fpga_region_of_match); 172ef3acdd8SAlan Tull } 173ef3acdd8SAlan Tull 174ef3acdd8SAlan Tull of_node_put(child_region); 175ef3acdd8SAlan Tull 176ef3acdd8SAlan Tull if (ret) 177ef3acdd8SAlan Tull pr_err("firmware-name not allowed in child FPGA region: %pOF", 178ef3acdd8SAlan Tull child_region); 179ef3acdd8SAlan Tull 180ef3acdd8SAlan Tull return ret; 181ef3acdd8SAlan Tull } 182ef3acdd8SAlan Tull 183ef3acdd8SAlan Tull /** 184ef3acdd8SAlan Tull * of_fpga_region_parse_ov - parse and check overlay applied to region 185ef3acdd8SAlan Tull * 186ef3acdd8SAlan Tull * @region: FPGA region 187ef3acdd8SAlan Tull * @overlay: overlay applied to the FPGA region 188ef3acdd8SAlan Tull * 189ef3acdd8SAlan Tull * Given an overlay applied to a FPGA region, parse the FPGA image specific 190ef3acdd8SAlan Tull * info in the overlay and do some checking. 191ef3acdd8SAlan Tull * 192ef3acdd8SAlan Tull * Returns: 193ef3acdd8SAlan Tull * NULL if overlay doesn't direct us to program the FPGA. 194ef3acdd8SAlan Tull * fpga_image_info struct if there is an image to program. 195ef3acdd8SAlan Tull * error code for invalid overlay. 196ef3acdd8SAlan Tull */ 197ef3acdd8SAlan Tull static struct fpga_image_info *of_fpga_region_parse_ov( 198ef3acdd8SAlan Tull struct fpga_region *region, 199ef3acdd8SAlan Tull struct device_node *overlay) 200ef3acdd8SAlan Tull { 201ef3acdd8SAlan Tull struct device *dev = ®ion->dev; 202ef3acdd8SAlan Tull struct fpga_image_info *info; 203ef3acdd8SAlan Tull const char *firmware_name; 204ef3acdd8SAlan Tull int ret; 205ef3acdd8SAlan Tull 206ef3acdd8SAlan Tull if (region->info) { 207ef3acdd8SAlan Tull dev_err(dev, "Region already has overlay applied.\n"); 208ef3acdd8SAlan Tull return ERR_PTR(-EINVAL); 209ef3acdd8SAlan Tull } 210ef3acdd8SAlan Tull 211ef3acdd8SAlan Tull /* 212ef3acdd8SAlan Tull * Reject overlay if child FPGA Regions added in the overlay have 213ef3acdd8SAlan Tull * firmware-name property (would mean that an FPGA region that has 214ef3acdd8SAlan Tull * not been added to the live tree yet is doing FPGA programming). 215ef3acdd8SAlan Tull */ 216ef3acdd8SAlan Tull ret = child_regions_with_firmware(overlay); 217ef3acdd8SAlan Tull if (ret) 218ef3acdd8SAlan Tull return ERR_PTR(ret); 219ef3acdd8SAlan Tull 220ef3acdd8SAlan Tull info = fpga_image_info_alloc(dev); 221ef3acdd8SAlan Tull if (!info) 222ef3acdd8SAlan Tull return ERR_PTR(-ENOMEM); 223ef3acdd8SAlan Tull 224ef3acdd8SAlan Tull info->overlay = overlay; 225ef3acdd8SAlan Tull 226ef3acdd8SAlan Tull /* Read FPGA region properties from the overlay */ 227ef3acdd8SAlan Tull if (of_property_read_bool(overlay, "partial-fpga-config")) 228ef3acdd8SAlan Tull info->flags |= FPGA_MGR_PARTIAL_RECONFIG; 229ef3acdd8SAlan Tull 230ef3acdd8SAlan Tull if (of_property_read_bool(overlay, "external-fpga-config")) 231ef3acdd8SAlan Tull info->flags |= FPGA_MGR_EXTERNAL_CONFIG; 232ef3acdd8SAlan Tull 233ef3acdd8SAlan Tull if (of_property_read_bool(overlay, "encrypted-fpga-config")) 234ef3acdd8SAlan Tull info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; 235ef3acdd8SAlan Tull 236ef3acdd8SAlan Tull if (!of_property_read_string(overlay, "firmware-name", 237ef3acdd8SAlan Tull &firmware_name)) { 238ef3acdd8SAlan Tull info->firmware_name = devm_kstrdup(dev, firmware_name, 239ef3acdd8SAlan Tull GFP_KERNEL); 240ef3acdd8SAlan Tull if (!info->firmware_name) 241ef3acdd8SAlan Tull return ERR_PTR(-ENOMEM); 242ef3acdd8SAlan Tull } 243ef3acdd8SAlan Tull 244ef3acdd8SAlan Tull of_property_read_u32(overlay, "region-unfreeze-timeout-us", 245ef3acdd8SAlan Tull &info->enable_timeout_us); 246ef3acdd8SAlan Tull 247ef3acdd8SAlan Tull of_property_read_u32(overlay, "region-freeze-timeout-us", 248ef3acdd8SAlan Tull &info->disable_timeout_us); 249ef3acdd8SAlan Tull 250ef3acdd8SAlan Tull of_property_read_u32(overlay, "config-complete-timeout-us", 251ef3acdd8SAlan Tull &info->config_complete_timeout_us); 252ef3acdd8SAlan Tull 253ef3acdd8SAlan Tull /* If overlay is not programming the FPGA, don't need FPGA image info */ 254ef3acdd8SAlan Tull if (!info->firmware_name) { 255ef3acdd8SAlan Tull ret = 0; 256ef3acdd8SAlan Tull goto ret_no_info; 257ef3acdd8SAlan Tull } 258ef3acdd8SAlan Tull 259ef3acdd8SAlan Tull /* 260ef3acdd8SAlan Tull * If overlay informs us FPGA was externally programmed, specifying 261ef3acdd8SAlan Tull * firmware here would be ambiguous. 262ef3acdd8SAlan Tull */ 263ef3acdd8SAlan Tull if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) { 264ef3acdd8SAlan Tull dev_err(dev, "error: specified firmware and external-fpga-config"); 265ef3acdd8SAlan Tull ret = -EINVAL; 266ef3acdd8SAlan Tull goto ret_no_info; 267ef3acdd8SAlan Tull } 268ef3acdd8SAlan Tull 269ef3acdd8SAlan Tull return info; 270ef3acdd8SAlan Tull ret_no_info: 271ef3acdd8SAlan Tull fpga_image_info_free(info); 272ef3acdd8SAlan Tull return ERR_PTR(ret); 273ef3acdd8SAlan Tull } 274ef3acdd8SAlan Tull 275ef3acdd8SAlan Tull /** 276ef3acdd8SAlan Tull * of_fpga_region_notify_pre_apply - pre-apply overlay notification 277ef3acdd8SAlan Tull * 278ef3acdd8SAlan Tull * @region: FPGA region that the overlay was applied to 279ef3acdd8SAlan Tull * @nd: overlay notification data 280ef3acdd8SAlan Tull * 281ef3acdd8SAlan Tull * Called when an overlay targeted to a FPGA Region is about to be applied. 282ef3acdd8SAlan Tull * Parses the overlay for properties that influence how the FPGA will be 283ef3acdd8SAlan Tull * programmed and does some checking. If the checks pass, programs the FPGA. 284ef3acdd8SAlan Tull * If the checks fail, overlay is rejected and does not get added to the 285ef3acdd8SAlan Tull * live tree. 286ef3acdd8SAlan Tull * 287ef3acdd8SAlan Tull * Returns 0 for success or negative error code for failure. 288ef3acdd8SAlan Tull */ 289ef3acdd8SAlan Tull static int of_fpga_region_notify_pre_apply(struct fpga_region *region, 290ef3acdd8SAlan Tull struct of_overlay_notify_data *nd) 291ef3acdd8SAlan Tull { 292ef3acdd8SAlan Tull struct device *dev = ®ion->dev; 293ef3acdd8SAlan Tull struct fpga_image_info *info; 294ef3acdd8SAlan Tull int ret; 295ef3acdd8SAlan Tull 296ef3acdd8SAlan Tull info = of_fpga_region_parse_ov(region, nd->overlay); 297ef3acdd8SAlan Tull if (IS_ERR(info)) 298ef3acdd8SAlan Tull return PTR_ERR(info); 299ef3acdd8SAlan Tull 3008a541679SAlan Tull /* If overlay doesn't program the FPGA, accept it anyway. */ 301ef3acdd8SAlan Tull if (!info) 302ef3acdd8SAlan Tull return 0; 303ef3acdd8SAlan Tull 3048a541679SAlan Tull if (region->info) { 3058a541679SAlan Tull dev_err(dev, "Region already has overlay applied.\n"); 3068a541679SAlan Tull return -EINVAL; 3078a541679SAlan Tull } 3088a541679SAlan Tull 309ef3acdd8SAlan Tull region->info = info; 310ef3acdd8SAlan Tull ret = fpga_region_program_fpga(region); 311ef3acdd8SAlan Tull if (ret) { 312ef3acdd8SAlan Tull /* error; reject overlay */ 313ef3acdd8SAlan Tull fpga_image_info_free(info); 314ef3acdd8SAlan Tull region->info = NULL; 315ef3acdd8SAlan Tull } 316ef3acdd8SAlan Tull 317ef3acdd8SAlan Tull return ret; 318ef3acdd8SAlan Tull } 319ef3acdd8SAlan Tull 320ef3acdd8SAlan Tull /** 321ef3acdd8SAlan Tull * of_fpga_region_notify_post_remove - post-remove overlay notification 322ef3acdd8SAlan Tull * 323ef3acdd8SAlan Tull * @region: FPGA region that was targeted by the overlay that was removed 324ef3acdd8SAlan Tull * @nd: overlay notification data 325ef3acdd8SAlan Tull * 326ef3acdd8SAlan Tull * Called after an overlay has been removed if the overlay's target was a 327ef3acdd8SAlan Tull * FPGA region. 328ef3acdd8SAlan Tull */ 329ef3acdd8SAlan Tull static void of_fpga_region_notify_post_remove(struct fpga_region *region, 330ef3acdd8SAlan Tull struct of_overlay_notify_data *nd) 331ef3acdd8SAlan Tull { 332ef3acdd8SAlan Tull fpga_bridges_disable(®ion->bridge_list); 333ef3acdd8SAlan Tull fpga_bridges_put(®ion->bridge_list); 334ef3acdd8SAlan Tull fpga_image_info_free(region->info); 335ef3acdd8SAlan Tull region->info = NULL; 336ef3acdd8SAlan Tull } 337ef3acdd8SAlan Tull 338ef3acdd8SAlan Tull /** 339ef3acdd8SAlan Tull * of_fpga_region_notify - reconfig notifier for dynamic DT changes 340ef3acdd8SAlan Tull * @nb: notifier block 341ef3acdd8SAlan Tull * @action: notifier action 342ef3acdd8SAlan Tull * @arg: reconfig data 343ef3acdd8SAlan Tull * 344ef3acdd8SAlan Tull * This notifier handles programming a FPGA when a "firmware-name" property is 345ef3acdd8SAlan Tull * added to a fpga-region. 346ef3acdd8SAlan Tull * 347ef3acdd8SAlan Tull * Returns NOTIFY_OK or error if FPGA programming fails. 348ef3acdd8SAlan Tull */ 349ef3acdd8SAlan Tull static int of_fpga_region_notify(struct notifier_block *nb, 350ef3acdd8SAlan Tull unsigned long action, void *arg) 351ef3acdd8SAlan Tull { 352ef3acdd8SAlan Tull struct of_overlay_notify_data *nd = arg; 353ef3acdd8SAlan Tull struct fpga_region *region; 354ef3acdd8SAlan Tull int ret; 355ef3acdd8SAlan Tull 356ef3acdd8SAlan Tull switch (action) { 357ef3acdd8SAlan Tull case OF_OVERLAY_PRE_APPLY: 358ef3acdd8SAlan Tull pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); 359ef3acdd8SAlan Tull break; 360ef3acdd8SAlan Tull case OF_OVERLAY_POST_APPLY: 361ef3acdd8SAlan Tull pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); 362ef3acdd8SAlan Tull return NOTIFY_OK; /* not for us */ 363ef3acdd8SAlan Tull case OF_OVERLAY_PRE_REMOVE: 364ef3acdd8SAlan Tull pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); 365ef3acdd8SAlan Tull return NOTIFY_OK; /* not for us */ 366ef3acdd8SAlan Tull case OF_OVERLAY_POST_REMOVE: 367ef3acdd8SAlan Tull pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); 368ef3acdd8SAlan Tull break; 369ef3acdd8SAlan Tull default: /* should not happen */ 370ef3acdd8SAlan Tull return NOTIFY_OK; 371ef3acdd8SAlan Tull } 372ef3acdd8SAlan Tull 373ef3acdd8SAlan Tull region = of_fpga_region_find(nd->target); 374ef3acdd8SAlan Tull if (!region) 375ef3acdd8SAlan Tull return NOTIFY_OK; 376ef3acdd8SAlan Tull 377ef3acdd8SAlan Tull ret = 0; 378ef3acdd8SAlan Tull switch (action) { 379ef3acdd8SAlan Tull case OF_OVERLAY_PRE_APPLY: 380ef3acdd8SAlan Tull ret = of_fpga_region_notify_pre_apply(region, nd); 381ef3acdd8SAlan Tull break; 382ef3acdd8SAlan Tull 383ef3acdd8SAlan Tull case OF_OVERLAY_POST_REMOVE: 384ef3acdd8SAlan Tull of_fpga_region_notify_post_remove(region, nd); 385ef3acdd8SAlan Tull break; 386ef3acdd8SAlan Tull } 387ef3acdd8SAlan Tull 388ef3acdd8SAlan Tull put_device(®ion->dev); 389ef3acdd8SAlan Tull 390ef3acdd8SAlan Tull if (ret) 391ef3acdd8SAlan Tull return notifier_from_errno(ret); 392ef3acdd8SAlan Tull 393ef3acdd8SAlan Tull return NOTIFY_OK; 394ef3acdd8SAlan Tull } 395ef3acdd8SAlan Tull 396ef3acdd8SAlan Tull static struct notifier_block fpga_region_of_nb = { 397ef3acdd8SAlan Tull .notifier_call = of_fpga_region_notify, 398ef3acdd8SAlan Tull }; 399ef3acdd8SAlan Tull 400ef3acdd8SAlan Tull static int of_fpga_region_probe(struct platform_device *pdev) 401ef3acdd8SAlan Tull { 402ef3acdd8SAlan Tull struct device *dev = &pdev->dev; 403ef3acdd8SAlan Tull struct device_node *np = dev->of_node; 404ef3acdd8SAlan Tull struct fpga_region *region; 405ef3acdd8SAlan Tull struct fpga_manager *mgr; 406ef3acdd8SAlan Tull int ret; 407ef3acdd8SAlan Tull 408ef3acdd8SAlan Tull /* Find the FPGA mgr specified by region or parent region. */ 409ef3acdd8SAlan Tull mgr = of_fpga_region_get_mgr(np); 410ef3acdd8SAlan Tull if (IS_ERR(mgr)) 411ef3acdd8SAlan Tull return -EPROBE_DEFER; 412ef3acdd8SAlan Tull 413fea82b7fSAlan Tull region = devm_fpga_region_create(dev, mgr, of_fpga_region_get_bridges); 414ef3acdd8SAlan Tull if (!region) { 415ef3acdd8SAlan Tull ret = -ENOMEM; 416ef3acdd8SAlan Tull goto eprobe_mgr_put; 417ef3acdd8SAlan Tull } 418ef3acdd8SAlan Tull 4199f368977SAlan Tull ret = fpga_region_register(region); 420ef3acdd8SAlan Tull if (ret) 421fea82b7fSAlan Tull goto eprobe_mgr_put; 422ef3acdd8SAlan Tull 423ef3acdd8SAlan Tull of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); 424488d040eSMoritz Fischer platform_set_drvdata(pdev, region); 425ef3acdd8SAlan Tull 426ef3acdd8SAlan Tull dev_info(dev, "FPGA Region probed\n"); 427ef3acdd8SAlan Tull 428ef3acdd8SAlan Tull return 0; 429ef3acdd8SAlan Tull 430ef3acdd8SAlan Tull eprobe_mgr_put: 431ef3acdd8SAlan Tull fpga_mgr_put(mgr); 432ef3acdd8SAlan Tull return ret; 433ef3acdd8SAlan Tull } 434ef3acdd8SAlan Tull 435ef3acdd8SAlan Tull static int of_fpga_region_remove(struct platform_device *pdev) 436ef3acdd8SAlan Tull { 437ef3acdd8SAlan Tull struct fpga_region *region = platform_get_drvdata(pdev); 43834bd2833SAlan Tull struct fpga_manager *mgr = region->mgr; 439ef3acdd8SAlan Tull 440ef3acdd8SAlan Tull fpga_region_unregister(region); 44134bd2833SAlan Tull fpga_mgr_put(mgr); 442ef3acdd8SAlan Tull 443ef3acdd8SAlan Tull return 0; 444ef3acdd8SAlan Tull } 445ef3acdd8SAlan Tull 446ef3acdd8SAlan Tull static struct platform_driver of_fpga_region_driver = { 447ef3acdd8SAlan Tull .probe = of_fpga_region_probe, 448ef3acdd8SAlan Tull .remove = of_fpga_region_remove, 449ef3acdd8SAlan Tull .driver = { 450ef3acdd8SAlan Tull .name = "of-fpga-region", 451ef3acdd8SAlan Tull .of_match_table = of_match_ptr(fpga_region_of_match), 452ef3acdd8SAlan Tull }, 453ef3acdd8SAlan Tull }; 454ef3acdd8SAlan Tull 455ef3acdd8SAlan Tull /** 456ef3acdd8SAlan Tull * fpga_region_init - init function for fpga_region class 457ef3acdd8SAlan Tull * Creates the fpga_region class and registers a reconfig notifier. 458ef3acdd8SAlan Tull */ 459ef3acdd8SAlan Tull static int __init of_fpga_region_init(void) 460ef3acdd8SAlan Tull { 461ef3acdd8SAlan Tull int ret; 462ef3acdd8SAlan Tull 463ef3acdd8SAlan Tull ret = of_overlay_notifier_register(&fpga_region_of_nb); 464ef3acdd8SAlan Tull if (ret) 465ef3acdd8SAlan Tull return ret; 466ef3acdd8SAlan Tull 467ef3acdd8SAlan Tull ret = platform_driver_register(&of_fpga_region_driver); 468ef3acdd8SAlan Tull if (ret) 469ef3acdd8SAlan Tull goto err_plat; 470ef3acdd8SAlan Tull 471ef3acdd8SAlan Tull return 0; 472ef3acdd8SAlan Tull 473ef3acdd8SAlan Tull err_plat: 474ef3acdd8SAlan Tull of_overlay_notifier_unregister(&fpga_region_of_nb); 475ef3acdd8SAlan Tull return ret; 476ef3acdd8SAlan Tull } 477ef3acdd8SAlan Tull 478ef3acdd8SAlan Tull static void __exit of_fpga_region_exit(void) 479ef3acdd8SAlan Tull { 480ef3acdd8SAlan Tull platform_driver_unregister(&of_fpga_region_driver); 481ef3acdd8SAlan Tull of_overlay_notifier_unregister(&fpga_region_of_nb); 482ef3acdd8SAlan Tull } 483ef3acdd8SAlan Tull 484ef3acdd8SAlan Tull subsys_initcall(of_fpga_region_init); 485ef3acdd8SAlan Tull module_exit(of_fpga_region_exit); 486ef3acdd8SAlan Tull 487ef3acdd8SAlan Tull MODULE_DESCRIPTION("FPGA Region"); 488ef3acdd8SAlan Tull MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); 489ef3acdd8SAlan Tull MODULE_LICENSE("GPL v2"); 490