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