uboot/arch/arm/mach-imx/imx8/fdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2019 NXP
   4 */
   5
   6#include <common.h>
   7#include <log.h>
   8#include <firmware/imx/sci/sci.h>
   9#include <asm/arch/sys_proto.h>
  10#include <asm/global_data.h>
  11#include <dm/ofnode.h>
  12#include <fdt_support.h>
  13#include <linux/libfdt.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17static bool check_owned_resource(sc_rsrc_t rsrc_id)
  18{
  19        bool owned;
  20
  21        owned = sc_rm_is_resource_owned(-1, rsrc_id);
  22
  23        return owned;
  24}
  25
  26static int disable_fdt_node(void *blob, int nodeoffset)
  27{
  28        int rc, ret;
  29        const char *status = "disabled";
  30
  31        do {
  32                rc = fdt_setprop(blob, nodeoffset, "status", status,
  33                                 strlen(status) + 1);
  34                if (rc) {
  35                        if (rc == -FDT_ERR_NOSPACE) {
  36                                ret = fdt_increase_size(blob, 512);
  37                                if (ret)
  38                                        return ret;
  39                        }
  40                }
  41        } while (rc == -FDT_ERR_NOSPACE);
  42
  43        return rc;
  44}
  45
  46static void update_fdt_with_owned_resources(void *blob)
  47{
  48        /*
  49         * Traverses the fdt nodes, check its power domain and use
  50         * the resource id in the power domain for checking whether
  51         * it is owned by current partition
  52         */
  53        struct fdtdec_phandle_args args;
  54        int offset = 0, depth = 0;
  55        u32 rsrc_id;
  56        int rc, i;
  57
  58        for (offset = fdt_next_node(blob, offset, &depth); offset > 0;
  59             offset = fdt_next_node(blob, offset, &depth)) {
  60                debug("Node name: %s, depth %d\n",
  61                      fdt_get_name(blob, offset, NULL), depth);
  62
  63                if (!fdt_get_property(blob, offset, "power-domains", NULL)) {
  64                        debug("   - ignoring node %s\n",
  65                              fdt_get_name(blob, offset, NULL));
  66                        continue;
  67                }
  68
  69                if (!fdtdec_get_is_enabled(blob, offset)) {
  70                        debug("   - ignoring node %s\n",
  71                              fdt_get_name(blob, offset, NULL));
  72                        continue;
  73                }
  74
  75                i = 0;
  76                while (true) {
  77                        rc = fdtdec_parse_phandle_with_args(blob, offset,
  78                                                            "power-domains",
  79                                                            "#power-domain-cells",
  80                                                            0, i++, &args);
  81                        if (rc == -ENOENT) {
  82                                break;
  83                        } else if (rc) {
  84                                printf("Parse power-domains of %s wrong: %d\n",
  85                                       fdt_get_name(blob, offset, NULL), rc);
  86                                continue;
  87                        }
  88
  89                        rsrc_id = args.args[0];
  90
  91                        if (!check_owned_resource(rsrc_id)) {
  92                                rc = disable_fdt_node(blob, offset);
  93                                if (!rc) {
  94                                        printf("Disable %s rsrc %u not owned\n",
  95                                               fdt_get_name(blob, offset, NULL),
  96                                               rsrc_id);
  97                                } else {
  98                                        printf("Unable to disable %s, err=%s\n",
  99                                               fdt_get_name(blob, offset, NULL),
 100                                               fdt_strerror(rc));
 101                                }
 102                        }
 103                }
 104        }
 105}
 106
 107static int config_smmu_resource_sid(int rsrc, int sid)
 108{
 109        int err;
 110
 111        err = sc_rm_set_master_sid(-1, rsrc, sid);
 112        debug("set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
 113        if (err != SC_ERR_NONE) {
 114                if (!check_owned_resource(rsrc)) {
 115                        printf("%s rsrc[%d] not owned\n", __func__, rsrc);
 116                        return -1;
 117                }
 118                pr_err("fail set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
 119                return -EINVAL;
 120        }
 121
 122        return 0;
 123}
 124
 125static int config_smmu_fdt_device_sid(void *blob, int device_offset, int sid)
 126{
 127        const char *name = fdt_get_name(blob, device_offset, NULL);
 128        struct fdtdec_phandle_args args;
 129        int rsrc, ret;
 130        int proplen;
 131        const fdt32_t *prop;
 132        int i;
 133
 134        prop = fdt_getprop(blob, device_offset, "fsl,sc_rsrc_id", &proplen);
 135        if (prop) {
 136                int i;
 137
 138                debug("configure node %s sid 0x%x for %d resources\n",
 139                      name, sid, (int)(proplen / sizeof(fdt32_t)));
 140                for (i = 0; i < proplen / sizeof(fdt32_t); ++i) {
 141                        ret = config_smmu_resource_sid(fdt32_to_cpu(prop[i]),
 142                                                       sid);
 143                        if (ret)
 144                                return ret;
 145                }
 146
 147                return 0;
 148        }
 149
 150        i = 0;
 151        while (true) {
 152                ret = fdtdec_parse_phandle_with_args(blob, device_offset,
 153                                                     "power-domains",
 154                                                     "#power-domain-cells",
 155                                                     0, i++, &args);
 156                if (ret == -ENOENT) {
 157                        break;
 158                } else if (ret) {
 159                        printf("Parse power-domains of node %s wrong: %d\n",
 160                               fdt_get_name(blob, device_offset, NULL), ret);
 161                        continue;
 162                }
 163
 164                debug("configure node %s sid 0x%x rsrc=%d\n",
 165                      name, sid, rsrc);
 166                rsrc = args.args[0];
 167
 168                ret = config_smmu_resource_sid(rsrc, sid);
 169                if (ret)
 170                        break;
 171        }
 172
 173        return ret;
 174}
 175
 176static int config_smmu_fdt(void *blob)
 177{
 178        int offset, proplen, i, ret;
 179        const fdt32_t *prop;
 180        const char *name;
 181
 182        /* Legacy smmu bindings, still used by xen. */
 183        offset = fdt_node_offset_by_compatible(blob, 0, "arm,mmu-500");
 184        prop = fdt_getprop(blob, offset, "mmu-masters", &proplen);
 185        if (offset > 0 && prop) {
 186                debug("found legacy mmu-masters property\n");
 187
 188                for (i = 0; i < proplen / 8; ++i) {
 189                        u32 phandle = fdt32_to_cpu(prop[2 * i]);
 190                        int sid = fdt32_to_cpu(prop[2 * i + 1]);
 191                        int device_offset;
 192
 193                        device_offset = fdt_node_offset_by_phandle(blob,
 194                                                                   phandle);
 195                        if (device_offset < 0) {
 196                                pr_err("Not find device from mmu_masters: %d",
 197                                       device_offset);
 198                                continue;
 199                        }
 200                        ret = config_smmu_fdt_device_sid(blob, device_offset,
 201                                                         sid);
 202                        if (ret)
 203                                return ret;
 204                }
 205
 206                /* Ignore new bindings if old bindings found, just like linux. */
 207                return 0;
 208        }
 209
 210        /* Generic smmu bindings */
 211        offset = 0;
 212        while ((offset = fdt_next_node(blob, offset, NULL)) > 0) {
 213                name = fdt_get_name(blob, offset, NULL);
 214                prop = fdt_getprop(blob, offset, "iommus", &proplen);
 215                if (!prop)
 216                        continue;
 217                debug("node %s iommus proplen %d\n", name, proplen);
 218
 219                if (proplen == 12) {
 220                        int sid = fdt32_to_cpu(prop[1]);
 221
 222                        config_smmu_fdt_device_sid(blob, offset, sid);
 223                } else if (proplen != 4) {
 224                        debug("node %s ignore unexpected iommus proplen=%d\n",
 225                              name, proplen);
 226                }
 227        }
 228
 229        return 0;
 230}
 231
 232static int ft_add_optee_node(void *fdt, struct bd_info *bd)
 233{
 234        const char *path, *subpath;
 235        int offs;
 236
 237        /*
 238         * No TEE space allocated indicating no TEE running, so no
 239         * need to add optee node in dts
 240         */
 241        if (!boot_pointer[1])
 242                return 0;
 243
 244        offs = fdt_increase_size(fdt, 512);
 245        if (offs) {
 246                printf("No Space for dtb\n");
 247                return 1;
 248        }
 249
 250        path = "/firmware";
 251        offs = fdt_path_offset(fdt, path);
 252        if (offs < 0) {
 253                path = "/";
 254                offs = fdt_path_offset(fdt, path);
 255
 256                if (offs < 0) {
 257                        printf("Could not find root node.\n");
 258                        return offs;
 259                }
 260
 261                subpath = "firmware";
 262                offs = fdt_add_subnode(fdt, offs, subpath);
 263                if (offs < 0) {
 264                        printf("Could not create %s node.\n", subpath);
 265                        return offs;
 266                }
 267        }
 268
 269        subpath = "optee";
 270        offs = fdt_add_subnode(fdt, offs, subpath);
 271        if (offs < 0) {
 272                printf("Could not create %s node.\n", subpath);
 273                return offs;
 274        }
 275
 276        fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz");
 277        fdt_setprop_string(fdt, offs, "method", "smc");
 278
 279        return 0;
 280}
 281
 282int ft_system_setup(void *blob, struct bd_info *bd)
 283{
 284        int ret;
 285        int off;
 286
 287        if (CONFIG_BOOTAUX_RESERVED_MEM_BASE) {
 288                off = fdt_add_mem_rsv(blob, CONFIG_BOOTAUX_RESERVED_MEM_BASE,
 289                                      CONFIG_BOOTAUX_RESERVED_MEM_SIZE);
 290                if (off < 0)
 291                        printf("Failed  to reserve memory for bootaux: %s\n",
 292                               fdt_strerror(off));
 293        }
 294
 295        update_fdt_with_owned_resources(blob);
 296
 297        if (is_imx8qm()) {
 298                ret = config_smmu_fdt(blob);
 299                if (ret)
 300                        return ret;
 301        }
 302
 303        return ft_add_optee_node(blob, bd);
 304}
 305