Commit 3bf2f15351e9533c9c99ebbdd93cafca30558b0d
Committed by
Simon Glass
1 parent
089ff8eb66
Exists in
smarc_8mq_lf_v2020.04
and in
12 other branches
fdtdec: Remove fdt_{addr,size}_unpack()
U-Boot already defines the {upper,lower}_32_bits() macros that have the
same purpose. Use the existing macros instead of defining new APIs.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Showing 3 changed files with 12 additions and 28 deletions Inline Diff
include/fdtdec.h
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2011 The Chromium OS Authors. | 3 | * Copyright (c) 2011 The Chromium OS Authors. |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #ifndef __fdtdec_h | 6 | #ifndef __fdtdec_h |
| 7 | #define __fdtdec_h | 7 | #define __fdtdec_h |
| 8 | 8 | ||
| 9 | /* | 9 | /* |
| 10 | * This file contains convenience functions for decoding useful and | 10 | * This file contains convenience functions for decoding useful and |
| 11 | * enlightening information from FDTs. It is intended to be used by device | 11 | * enlightening information from FDTs. It is intended to be used by device |
| 12 | * drivers and board-specific code within U-Boot. It aims to reduce the | 12 | * drivers and board-specific code within U-Boot. It aims to reduce the |
| 13 | * amount of FDT munging required within U-Boot itself, so that driver code | 13 | * amount of FDT munging required within U-Boot itself, so that driver code |
| 14 | * changes to support FDT are minimized. | 14 | * changes to support FDT are minimized. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/libfdt.h> | 17 | #include <linux/libfdt.h> |
| 18 | #include <pci.h> | 18 | #include <pci.h> |
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| 21 | * A typedef for a physical address. Note that fdt data is always big | 21 | * A typedef for a physical address. Note that fdt data is always big |
| 22 | * endian even on a litle endian machine. | 22 | * endian even on a litle endian machine. |
| 23 | */ | 23 | */ |
| 24 | typedef phys_addr_t fdt_addr_t; | 24 | typedef phys_addr_t fdt_addr_t; |
| 25 | typedef phys_size_t fdt_size_t; | 25 | typedef phys_size_t fdt_size_t; |
| 26 | 26 | ||
| 27 | static inline fdt32_t fdt_addr_unpack(fdt_addr_t addr, fdt32_t *upper) | ||
| 28 | { | ||
| 29 | if (upper) | ||
| 30 | #ifdef CONFIG_PHYS_64BIT | ||
| 31 | *upper = addr >> 32; | ||
| 32 | #else | ||
| 33 | *upper = 0; | ||
| 34 | #endif | ||
| 35 | |||
| 36 | return addr; | ||
| 37 | } | ||
| 38 | |||
| 39 | static inline fdt32_t fdt_size_unpack(fdt_size_t size, fdt32_t *upper) | ||
| 40 | { | ||
| 41 | if (upper) | ||
| 42 | #ifdef CONFIG_PHYS_64BIT | ||
| 43 | *upper = size >> 32; | ||
| 44 | #else | ||
| 45 | *upper = 0; | ||
| 46 | #endif | ||
| 47 | |||
| 48 | return size; | ||
| 49 | } | ||
| 50 | |||
| 51 | #ifdef CONFIG_PHYS_64BIT | 27 | #ifdef CONFIG_PHYS_64BIT |
| 52 | #define FDT_ADDR_T_NONE (-1U) | 28 | #define FDT_ADDR_T_NONE (-1U) |
| 53 | #define fdt_addr_to_cpu(reg) be64_to_cpu(reg) | 29 | #define fdt_addr_to_cpu(reg) be64_to_cpu(reg) |
| 54 | #define fdt_size_to_cpu(reg) be64_to_cpu(reg) | 30 | #define fdt_size_to_cpu(reg) be64_to_cpu(reg) |
| 55 | #define cpu_to_fdt_addr(reg) cpu_to_be64(reg) | 31 | #define cpu_to_fdt_addr(reg) cpu_to_be64(reg) |
| 56 | #define cpu_to_fdt_size(reg) cpu_to_be64(reg) | 32 | #define cpu_to_fdt_size(reg) cpu_to_be64(reg) |
| 57 | typedef fdt64_t fdt_val_t; | 33 | typedef fdt64_t fdt_val_t; |
| 58 | #else | 34 | #else |
| 59 | #define FDT_ADDR_T_NONE (-1U) | 35 | #define FDT_ADDR_T_NONE (-1U) |
| 60 | #define fdt_addr_to_cpu(reg) be32_to_cpu(reg) | 36 | #define fdt_addr_to_cpu(reg) be32_to_cpu(reg) |
| 61 | #define fdt_size_to_cpu(reg) be32_to_cpu(reg) | 37 | #define fdt_size_to_cpu(reg) be32_to_cpu(reg) |
| 62 | #define cpu_to_fdt_addr(reg) cpu_to_be32(reg) | 38 | #define cpu_to_fdt_addr(reg) cpu_to_be32(reg) |
| 63 | #define cpu_to_fdt_size(reg) cpu_to_be32(reg) | 39 | #define cpu_to_fdt_size(reg) cpu_to_be32(reg) |
| 64 | typedef fdt32_t fdt_val_t; | 40 | typedef fdt32_t fdt_val_t; |
| 65 | #endif | 41 | #endif |
| 66 | 42 | ||
| 67 | /* Information obtained about memory from the FDT */ | 43 | /* Information obtained about memory from the FDT */ |
| 68 | struct fdt_memory { | 44 | struct fdt_memory { |
| 69 | fdt_addr_t start; | 45 | fdt_addr_t start; |
| 70 | fdt_addr_t end; | 46 | fdt_addr_t end; |
| 71 | }; | 47 | }; |
| 72 | 48 | ||
| 73 | struct bd_info; | 49 | struct bd_info; |
| 74 | 50 | ||
| 75 | #ifdef CONFIG_SPL_BUILD | 51 | #ifdef CONFIG_SPL_BUILD |
| 76 | #define SPL_BUILD 1 | 52 | #define SPL_BUILD 1 |
| 77 | #else | 53 | #else |
| 78 | #define SPL_BUILD 0 | 54 | #define SPL_BUILD 0 |
| 79 | #endif | 55 | #endif |
| 80 | 56 | ||
| 81 | #if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) | 57 | #if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) |
| 82 | extern phys_addr_t prior_stage_fdt_address; | 58 | extern phys_addr_t prior_stage_fdt_address; |
| 83 | #endif | 59 | #endif |
| 84 | 60 | ||
| 85 | /* | 61 | /* |
| 86 | * Information about a resource. start is the first address of the resource | 62 | * Information about a resource. start is the first address of the resource |
| 87 | * and end is the last address (inclusive). The length of the resource will | 63 | * and end is the last address (inclusive). The length of the resource will |
| 88 | * be equal to: end - start + 1. | 64 | * be equal to: end - start + 1. |
| 89 | */ | 65 | */ |
| 90 | struct fdt_resource { | 66 | struct fdt_resource { |
| 91 | fdt_addr_t start; | 67 | fdt_addr_t start; |
| 92 | fdt_addr_t end; | 68 | fdt_addr_t end; |
| 93 | }; | 69 | }; |
| 94 | 70 | ||
| 95 | enum fdt_pci_space { | 71 | enum fdt_pci_space { |
| 96 | FDT_PCI_SPACE_CONFIG = 0, | 72 | FDT_PCI_SPACE_CONFIG = 0, |
| 97 | FDT_PCI_SPACE_IO = 0x01000000, | 73 | FDT_PCI_SPACE_IO = 0x01000000, |
| 98 | FDT_PCI_SPACE_MEM32 = 0x02000000, | 74 | FDT_PCI_SPACE_MEM32 = 0x02000000, |
| 99 | FDT_PCI_SPACE_MEM64 = 0x03000000, | 75 | FDT_PCI_SPACE_MEM64 = 0x03000000, |
| 100 | FDT_PCI_SPACE_MEM32_PREF = 0x42000000, | 76 | FDT_PCI_SPACE_MEM32_PREF = 0x42000000, |
| 101 | FDT_PCI_SPACE_MEM64_PREF = 0x43000000, | 77 | FDT_PCI_SPACE_MEM64_PREF = 0x43000000, |
| 102 | }; | 78 | }; |
| 103 | 79 | ||
| 104 | #define FDT_PCI_ADDR_CELLS 3 | 80 | #define FDT_PCI_ADDR_CELLS 3 |
| 105 | #define FDT_PCI_SIZE_CELLS 2 | 81 | #define FDT_PCI_SIZE_CELLS 2 |
| 106 | #define FDT_PCI_REG_SIZE \ | 82 | #define FDT_PCI_REG_SIZE \ |
| 107 | ((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32)) | 83 | ((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32)) |
| 108 | 84 | ||
| 109 | /* | 85 | /* |
| 110 | * The Open Firmware spec defines PCI physical address as follows: | 86 | * The Open Firmware spec defines PCI physical address as follows: |
| 111 | * | 87 | * |
| 112 | * bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00 | 88 | * bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00 |
| 113 | * | 89 | * |
| 114 | * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr | 90 | * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr |
| 115 | * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh | 91 | * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh |
| 116 | * phys.lo cell: llllllll llllllll llllllll llllllll | 92 | * phys.lo cell: llllllll llllllll llllllll llllllll |
| 117 | * | 93 | * |
| 118 | * where: | 94 | * where: |
| 119 | * | 95 | * |
| 120 | * n: is 0 if the address is relocatable, 1 otherwise | 96 | * n: is 0 if the address is relocatable, 1 otherwise |
| 121 | * p: is 1 if addressable region is prefetchable, 0 otherwise | 97 | * p: is 1 if addressable region is prefetchable, 0 otherwise |
| 122 | * t: is 1 if the address is aliased (for non-relocatable I/O) below 1MB | 98 | * t: is 1 if the address is aliased (for non-relocatable I/O) below 1MB |
| 123 | * (for Memory), or below 64KB (for relocatable I/O) | 99 | * (for Memory), or below 64KB (for relocatable I/O) |
| 124 | * ss: is the space code, denoting the address space | 100 | * ss: is the space code, denoting the address space |
| 125 | * bbbbbbbb: is the 8-bit Bus Number | 101 | * bbbbbbbb: is the 8-bit Bus Number |
| 126 | * ddddd: is the 5-bit Device Number | 102 | * ddddd: is the 5-bit Device Number |
| 127 | * fff: is the 3-bit Function Number | 103 | * fff: is the 3-bit Function Number |
| 128 | * rrrrrrrr: is the 8-bit Register Number | 104 | * rrrrrrrr: is the 8-bit Register Number |
| 129 | * hhhhhhhh: is a 32-bit unsigned number | 105 | * hhhhhhhh: is a 32-bit unsigned number |
| 130 | * llllllll: is a 32-bit unsigned number | 106 | * llllllll: is a 32-bit unsigned number |
| 131 | */ | 107 | */ |
| 132 | struct fdt_pci_addr { | 108 | struct fdt_pci_addr { |
| 133 | u32 phys_hi; | 109 | u32 phys_hi; |
| 134 | u32 phys_mid; | 110 | u32 phys_mid; |
| 135 | u32 phys_lo; | 111 | u32 phys_lo; |
| 136 | }; | 112 | }; |
| 137 | 113 | ||
| 138 | /** | 114 | /** |
| 139 | * Compute the size of a resource. | 115 | * Compute the size of a resource. |
| 140 | * | 116 | * |
| 141 | * @param res the resource to operate on | 117 | * @param res the resource to operate on |
| 142 | * @return the size of the resource | 118 | * @return the size of the resource |
| 143 | */ | 119 | */ |
| 144 | static inline fdt_size_t fdt_resource_size(const struct fdt_resource *res) | 120 | static inline fdt_size_t fdt_resource_size(const struct fdt_resource *res) |
| 145 | { | 121 | { |
| 146 | return res->end - res->start + 1; | 122 | return res->end - res->start + 1; |
| 147 | } | 123 | } |
| 148 | 124 | ||
| 149 | /** | 125 | /** |
| 150 | * Compat types that we know about and for which we might have drivers. | 126 | * Compat types that we know about and for which we might have drivers. |
| 151 | * Each is named COMPAT_<dir>_<filename> where <dir> is the directory | 127 | * Each is named COMPAT_<dir>_<filename> where <dir> is the directory |
| 152 | * within drivers. | 128 | * within drivers. |
| 153 | */ | 129 | */ |
| 154 | enum fdt_compat_id { | 130 | enum fdt_compat_id { |
| 155 | COMPAT_UNKNOWN, | 131 | COMPAT_UNKNOWN, |
| 156 | COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */ | 132 | COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */ |
| 157 | COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */ | 133 | COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */ |
| 158 | COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */ | 134 | COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */ |
| 159 | COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL, | 135 | COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL, |
| 160 | /* Tegra124 XUSB pad controller */ | 136 | /* Tegra124 XUSB pad controller */ |
| 161 | COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL, | 137 | COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL, |
| 162 | /* Tegra210 XUSB pad controller */ | 138 | /* Tegra210 XUSB pad controller */ |
| 163 | COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ | 139 | COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ |
| 164 | COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ | 140 | COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ |
| 165 | COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ | 141 | COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ |
| 166 | COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */ | 142 | COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */ |
| 167 | COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */ | 143 | COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */ |
| 168 | COMPAT_SAMSUNG_EXYNOS_MIPI_DSI, /* Exynos mipi dsi */ | 144 | COMPAT_SAMSUNG_EXYNOS_MIPI_DSI, /* Exynos mipi dsi */ |
| 169 | COMPAT_SAMSUNG_EXYNOS_DWMMC, /* Exynos DWMMC controller */ | 145 | COMPAT_SAMSUNG_EXYNOS_DWMMC, /* Exynos DWMMC controller */ |
| 170 | COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */ | 146 | COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */ |
| 171 | COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */ | 147 | COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */ |
| 172 | COMPAT_INTEL_MICROCODE, /* Intel microcode update */ | 148 | COMPAT_INTEL_MICROCODE, /* Intel microcode update */ |
| 173 | COMPAT_INTEL_QRK_MRC, /* Intel Quark MRC */ | 149 | COMPAT_INTEL_QRK_MRC, /* Intel Quark MRC */ |
| 174 | COMPAT_ALTERA_SOCFPGA_DWMAC, /* SoCFPGA Ethernet controller */ | 150 | COMPAT_ALTERA_SOCFPGA_DWMAC, /* SoCFPGA Ethernet controller */ |
| 175 | COMPAT_ALTERA_SOCFPGA_DWMMC, /* SoCFPGA DWMMC controller */ | 151 | COMPAT_ALTERA_SOCFPGA_DWMMC, /* SoCFPGA DWMMC controller */ |
| 176 | COMPAT_ALTERA_SOCFPGA_DWC2USB, /* SoCFPGA DWC2 USB controller */ | 152 | COMPAT_ALTERA_SOCFPGA_DWC2USB, /* SoCFPGA DWC2 USB controller */ |
| 177 | COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */ | 153 | COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */ |
| 178 | COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */ | 154 | COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */ |
| 179 | COMPAT_INTEL_IVYBRIDGE_FSP, /* Intel Ivy Bridge FSP */ | 155 | COMPAT_INTEL_IVYBRIDGE_FSP, /* Intel Ivy Bridge FSP */ |
| 180 | COMPAT_SUNXI_NAND, /* SUNXI NAND controller */ | 156 | COMPAT_SUNXI_NAND, /* SUNXI NAND controller */ |
| 181 | COMPAT_ALTERA_SOCFPGA_CLK, /* SoCFPGA Clock initialization */ | 157 | COMPAT_ALTERA_SOCFPGA_CLK, /* SoCFPGA Clock initialization */ |
| 182 | COMPAT_ALTERA_SOCFPGA_PINCTRL_SINGLE, /* SoCFPGA pinctrl-single */ | 158 | COMPAT_ALTERA_SOCFPGA_PINCTRL_SINGLE, /* SoCFPGA pinctrl-single */ |
| 183 | COMPAT_ALTERA_SOCFPGA_H2F_BRG, /* SoCFPGA hps2fpga bridge */ | 159 | COMPAT_ALTERA_SOCFPGA_H2F_BRG, /* SoCFPGA hps2fpga bridge */ |
| 184 | COMPAT_ALTERA_SOCFPGA_LWH2F_BRG, /* SoCFPGA lwhps2fpga bridge */ | 160 | COMPAT_ALTERA_SOCFPGA_LWH2F_BRG, /* SoCFPGA lwhps2fpga bridge */ |
| 185 | COMPAT_ALTERA_SOCFPGA_F2H_BRG, /* SoCFPGA fpga2hps bridge */ | 161 | COMPAT_ALTERA_SOCFPGA_F2H_BRG, /* SoCFPGA fpga2hps bridge */ |
| 186 | COMPAT_ALTERA_SOCFPGA_F2SDR0, /* SoCFPGA fpga2SDRAM0 bridge */ | 162 | COMPAT_ALTERA_SOCFPGA_F2SDR0, /* SoCFPGA fpga2SDRAM0 bridge */ |
| 187 | COMPAT_ALTERA_SOCFPGA_F2SDR1, /* SoCFPGA fpga2SDRAM1 bridge */ | 163 | COMPAT_ALTERA_SOCFPGA_F2SDR1, /* SoCFPGA fpga2SDRAM1 bridge */ |
| 188 | COMPAT_ALTERA_SOCFPGA_F2SDR2, /* SoCFPGA fpga2SDRAM2 bridge */ | 164 | COMPAT_ALTERA_SOCFPGA_F2SDR2, /* SoCFPGA fpga2SDRAM2 bridge */ |
| 189 | COMPAT_ALTERA_SOCFPGA_FPGA0, /* SOCFPGA FPGA manager */ | 165 | COMPAT_ALTERA_SOCFPGA_FPGA0, /* SOCFPGA FPGA manager */ |
| 190 | COMPAT_ALTERA_SOCFPGA_NOC, /* SOCFPGA Arria 10 NOC */ | 166 | COMPAT_ALTERA_SOCFPGA_NOC, /* SOCFPGA Arria 10 NOC */ |
| 191 | COMPAT_ALTERA_SOCFPGA_CLK_INIT, /* SOCFPGA Arria 10 clk init */ | 167 | COMPAT_ALTERA_SOCFPGA_CLK_INIT, /* SOCFPGA Arria 10 clk init */ |
| 192 | 168 | ||
| 193 | COMPAT_COUNT, | 169 | COMPAT_COUNT, |
| 194 | }; | 170 | }; |
| 195 | 171 | ||
| 196 | #define MAX_PHANDLE_ARGS 16 | 172 | #define MAX_PHANDLE_ARGS 16 |
| 197 | struct fdtdec_phandle_args { | 173 | struct fdtdec_phandle_args { |
| 198 | int node; | 174 | int node; |
| 199 | int args_count; | 175 | int args_count; |
| 200 | uint32_t args[MAX_PHANDLE_ARGS]; | 176 | uint32_t args[MAX_PHANDLE_ARGS]; |
| 201 | }; | 177 | }; |
| 202 | 178 | ||
| 203 | /** | 179 | /** |
| 204 | * fdtdec_parse_phandle_with_args() - Find a node pointed by phandle in a list | 180 | * fdtdec_parse_phandle_with_args() - Find a node pointed by phandle in a list |
| 205 | * | 181 | * |
| 206 | * This function is useful to parse lists of phandles and their arguments. | 182 | * This function is useful to parse lists of phandles and their arguments. |
| 207 | * | 183 | * |
| 208 | * Example: | 184 | * Example: |
| 209 | * | 185 | * |
| 210 | * phandle1: node1 { | 186 | * phandle1: node1 { |
| 211 | * #list-cells = <2>; | 187 | * #list-cells = <2>; |
| 212 | * } | 188 | * } |
| 213 | * | 189 | * |
| 214 | * phandle2: node2 { | 190 | * phandle2: node2 { |
| 215 | * #list-cells = <1>; | 191 | * #list-cells = <1>; |
| 216 | * } | 192 | * } |
| 217 | * | 193 | * |
| 218 | * node3 { | 194 | * node3 { |
| 219 | * list = <&phandle1 1 2 &phandle2 3>; | 195 | * list = <&phandle1 1 2 &phandle2 3>; |
| 220 | * } | 196 | * } |
| 221 | * | 197 | * |
| 222 | * To get a device_node of the `node2' node you may call this: | 198 | * To get a device_node of the `node2' node you may call this: |
| 223 | * fdtdec_parse_phandle_with_args(blob, node3, "list", "#list-cells", 0, 1, | 199 | * fdtdec_parse_phandle_with_args(blob, node3, "list", "#list-cells", 0, 1, |
| 224 | * &args); | 200 | * &args); |
| 225 | * | 201 | * |
| 226 | * (This function is a modified version of __of_parse_phandle_with_args() from | 202 | * (This function is a modified version of __of_parse_phandle_with_args() from |
| 227 | * Linux 3.18) | 203 | * Linux 3.18) |
| 228 | * | 204 | * |
| 229 | * @blob: Pointer to device tree | 205 | * @blob: Pointer to device tree |
| 230 | * @src_node: Offset of device tree node containing a list | 206 | * @src_node: Offset of device tree node containing a list |
| 231 | * @list_name: property name that contains a list | 207 | * @list_name: property name that contains a list |
| 232 | * @cells_name: property name that specifies the phandles' arguments count, | 208 | * @cells_name: property name that specifies the phandles' arguments count, |
| 233 | * or NULL to use @cells_count | 209 | * or NULL to use @cells_count |
| 234 | * @cells_count: Cell count to use if @cells_name is NULL | 210 | * @cells_count: Cell count to use if @cells_name is NULL |
| 235 | * @index: index of a phandle to parse out | 211 | * @index: index of a phandle to parse out |
| 236 | * @out_args: optional pointer to output arguments structure (will be filled) | 212 | * @out_args: optional pointer to output arguments structure (will be filled) |
| 237 | * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if | 213 | * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if |
| 238 | * @list_name does not exist, a phandle was not found, @cells_name | 214 | * @list_name does not exist, a phandle was not found, @cells_name |
| 239 | * could not be found, the arguments were truncated or there were too | 215 | * could not be found, the arguments were truncated or there were too |
| 240 | * many arguments. | 216 | * many arguments. |
| 241 | * | 217 | * |
| 242 | */ | 218 | */ |
| 243 | int fdtdec_parse_phandle_with_args(const void *blob, int src_node, | 219 | int fdtdec_parse_phandle_with_args(const void *blob, int src_node, |
| 244 | const char *list_name, | 220 | const char *list_name, |
| 245 | const char *cells_name, | 221 | const char *cells_name, |
| 246 | int cell_count, int index, | 222 | int cell_count, int index, |
| 247 | struct fdtdec_phandle_args *out_args); | 223 | struct fdtdec_phandle_args *out_args); |
| 248 | 224 | ||
| 249 | /** | 225 | /** |
| 250 | * Find the next numbered alias for a peripheral. This is used to enumerate | 226 | * Find the next numbered alias for a peripheral. This is used to enumerate |
| 251 | * all the peripherals of a certain type. | 227 | * all the peripherals of a certain type. |
| 252 | * | 228 | * |
| 253 | * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then | 229 | * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then |
| 254 | * this function will return a pointer to the node the alias points to, and | 230 | * this function will return a pointer to the node the alias points to, and |
| 255 | * then update *upto to 1. Next time you call this function, the next node | 231 | * then update *upto to 1. Next time you call this function, the next node |
| 256 | * will be returned. | 232 | * will be returned. |
| 257 | * | 233 | * |
| 258 | * All nodes returned will match the compatible ID, as it is assumed that | 234 | * All nodes returned will match the compatible ID, as it is assumed that |
| 259 | * all peripherals use the same driver. | 235 | * all peripherals use the same driver. |
| 260 | * | 236 | * |
| 261 | * @param blob FDT blob to use | 237 | * @param blob FDT blob to use |
| 262 | * @param name Root name of alias to search for | 238 | * @param name Root name of alias to search for |
| 263 | * @param id Compatible ID to look for | 239 | * @param id Compatible ID to look for |
| 264 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more | 240 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more |
| 265 | */ | 241 | */ |
| 266 | int fdtdec_next_alias(const void *blob, const char *name, | 242 | int fdtdec_next_alias(const void *blob, const char *name, |
| 267 | enum fdt_compat_id id, int *upto); | 243 | enum fdt_compat_id id, int *upto); |
| 268 | 244 | ||
| 269 | /** | 245 | /** |
| 270 | * Find the compatible ID for a given node. | 246 | * Find the compatible ID for a given node. |
| 271 | * | 247 | * |
| 272 | * Generally each node has at least one compatible string attached to it. | 248 | * Generally each node has at least one compatible string attached to it. |
| 273 | * This function looks through our list of known compatible strings and | 249 | * This function looks through our list of known compatible strings and |
| 274 | * returns the corresponding ID which matches the compatible string. | 250 | * returns the corresponding ID which matches the compatible string. |
| 275 | * | 251 | * |
| 276 | * @param blob FDT blob to use | 252 | * @param blob FDT blob to use |
| 277 | * @param node Node containing compatible string to find | 253 | * @param node Node containing compatible string to find |
| 278 | * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match | 254 | * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match |
| 279 | */ | 255 | */ |
| 280 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node); | 256 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node); |
| 281 | 257 | ||
| 282 | /** | 258 | /** |
| 283 | * Find the next compatible node for a peripheral. | 259 | * Find the next compatible node for a peripheral. |
| 284 | * | 260 | * |
| 285 | * Do the first call with node = 0. This function will return a pointer to | 261 | * Do the first call with node = 0. This function will return a pointer to |
| 286 | * the next compatible node. Next time you call this function, pass the | 262 | * the next compatible node. Next time you call this function, pass the |
| 287 | * value returned, and the next node will be provided. | 263 | * value returned, and the next node will be provided. |
| 288 | * | 264 | * |
| 289 | * @param blob FDT blob to use | 265 | * @param blob FDT blob to use |
| 290 | * @param node Start node for search | 266 | * @param node Start node for search |
| 291 | * @param id Compatible ID to look for (enum fdt_compat_id) | 267 | * @param id Compatible ID to look for (enum fdt_compat_id) |
| 292 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more | 268 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more |
| 293 | */ | 269 | */ |
| 294 | int fdtdec_next_compatible(const void *blob, int node, | 270 | int fdtdec_next_compatible(const void *blob, int node, |
| 295 | enum fdt_compat_id id); | 271 | enum fdt_compat_id id); |
| 296 | 272 | ||
| 297 | /** | 273 | /** |
| 298 | * Find the next compatible subnode for a peripheral. | 274 | * Find the next compatible subnode for a peripheral. |
| 299 | * | 275 | * |
| 300 | * Do the first call with node set to the parent and depth = 0. This | 276 | * Do the first call with node set to the parent and depth = 0. This |
| 301 | * function will return the offset of the next compatible node. Next time | 277 | * function will return the offset of the next compatible node. Next time |
| 302 | * you call this function, pass the node value returned last time, with | 278 | * you call this function, pass the node value returned last time, with |
| 303 | * depth unchanged, and the next node will be provided. | 279 | * depth unchanged, and the next node will be provided. |
| 304 | * | 280 | * |
| 305 | * @param blob FDT blob to use | 281 | * @param blob FDT blob to use |
| 306 | * @param node Start node for search | 282 | * @param node Start node for search |
| 307 | * @param id Compatible ID to look for (enum fdt_compat_id) | 283 | * @param id Compatible ID to look for (enum fdt_compat_id) |
| 308 | * @param depthp Current depth (set to 0 before first call) | 284 | * @param depthp Current depth (set to 0 before first call) |
| 309 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more | 285 | * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more |
| 310 | */ | 286 | */ |
| 311 | int fdtdec_next_compatible_subnode(const void *blob, int node, | 287 | int fdtdec_next_compatible_subnode(const void *blob, int node, |
| 312 | enum fdt_compat_id id, int *depthp); | 288 | enum fdt_compat_id id, int *depthp); |
| 313 | 289 | ||
| 314 | /* | 290 | /* |
| 315 | * Look up an address property in a node and return the parsed address, and | 291 | * Look up an address property in a node and return the parsed address, and |
| 316 | * optionally the parsed size. | 292 | * optionally the parsed size. |
| 317 | * | 293 | * |
| 318 | * This variant assumes a known and fixed number of cells are used to | 294 | * This variant assumes a known and fixed number of cells are used to |
| 319 | * represent the address and size. | 295 | * represent the address and size. |
| 320 | * | 296 | * |
| 321 | * You probably don't want to use this function directly except to parse | 297 | * You probably don't want to use this function directly except to parse |
| 322 | * non-standard properties, and never to parse the "reg" property. Instead, | 298 | * non-standard properties, and never to parse the "reg" property. Instead, |
| 323 | * use one of the "auto" variants below, which automatically honor the | 299 | * use one of the "auto" variants below, which automatically honor the |
| 324 | * #address-cells and #size-cells properties in the parent node. | 300 | * #address-cells and #size-cells properties in the parent node. |
| 325 | * | 301 | * |
| 326 | * @param blob FDT blob | 302 | * @param blob FDT blob |
| 327 | * @param node node to examine | 303 | * @param node node to examine |
| 328 | * @param prop_name name of property to find | 304 | * @param prop_name name of property to find |
| 329 | * @param index which address to retrieve from a list of addresses. Often 0. | 305 | * @param index which address to retrieve from a list of addresses. Often 0. |
| 330 | * @param na the number of cells used to represent an address | 306 | * @param na the number of cells used to represent an address |
| 331 | * @param ns the number of cells used to represent a size | 307 | * @param ns the number of cells used to represent a size |
| 332 | * @param sizep a pointer to store the size into. Use NULL if not required | 308 | * @param sizep a pointer to store the size into. Use NULL if not required |
| 333 | * @param translate Indicates whether to translate the returned value | 309 | * @param translate Indicates whether to translate the returned value |
| 334 | * using the parent node's ranges property. | 310 | * using the parent node's ranges property. |
| 335 | * @return address, if found, or FDT_ADDR_T_NONE if not | 311 | * @return address, if found, or FDT_ADDR_T_NONE if not |
| 336 | */ | 312 | */ |
| 337 | fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, | 313 | fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, |
| 338 | const char *prop_name, int index, int na, int ns, | 314 | const char *prop_name, int index, int na, int ns, |
| 339 | fdt_size_t *sizep, bool translate); | 315 | fdt_size_t *sizep, bool translate); |
| 340 | 316 | ||
| 341 | /* | 317 | /* |
| 342 | * Look up an address property in a node and return the parsed address, and | 318 | * Look up an address property in a node and return the parsed address, and |
| 343 | * optionally the parsed size. | 319 | * optionally the parsed size. |
| 344 | * | 320 | * |
| 345 | * This variant automatically determines the number of cells used to represent | 321 | * This variant automatically determines the number of cells used to represent |
| 346 | * the address and size by parsing the provided parent node's #address-cells | 322 | * the address and size by parsing the provided parent node's #address-cells |
| 347 | * and #size-cells properties. | 323 | * and #size-cells properties. |
| 348 | * | 324 | * |
| 349 | * @param blob FDT blob | 325 | * @param blob FDT blob |
| 350 | * @param parent parent node of @node | 326 | * @param parent parent node of @node |
| 351 | * @param node node to examine | 327 | * @param node node to examine |
| 352 | * @param prop_name name of property to find | 328 | * @param prop_name name of property to find |
| 353 | * @param index which address to retrieve from a list of addresses. Often 0. | 329 | * @param index which address to retrieve from a list of addresses. Often 0. |
| 354 | * @param sizep a pointer to store the size into. Use NULL if not required | 330 | * @param sizep a pointer to store the size into. Use NULL if not required |
| 355 | * @param translate Indicates whether to translate the returned value | 331 | * @param translate Indicates whether to translate the returned value |
| 356 | * using the parent node's ranges property. | 332 | * using the parent node's ranges property. |
| 357 | * @return address, if found, or FDT_ADDR_T_NONE if not | 333 | * @return address, if found, or FDT_ADDR_T_NONE if not |
| 358 | */ | 334 | */ |
| 359 | fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, | 335 | fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, |
| 360 | int node, const char *prop_name, int index, fdt_size_t *sizep, | 336 | int node, const char *prop_name, int index, fdt_size_t *sizep, |
| 361 | bool translate); | 337 | bool translate); |
| 362 | 338 | ||
| 363 | /* | 339 | /* |
| 364 | * Look up an address property in a node and return the parsed address, and | 340 | * Look up an address property in a node and return the parsed address, and |
| 365 | * optionally the parsed size. | 341 | * optionally the parsed size. |
| 366 | * | 342 | * |
| 367 | * This variant automatically determines the number of cells used to represent | 343 | * This variant automatically determines the number of cells used to represent |
| 368 | * the address and size by parsing the parent node's #address-cells | 344 | * the address and size by parsing the parent node's #address-cells |
| 369 | * and #size-cells properties. The parent node is automatically found. | 345 | * and #size-cells properties. The parent node is automatically found. |
| 370 | * | 346 | * |
| 371 | * The automatic parent lookup implemented by this function is slow. | 347 | * The automatic parent lookup implemented by this function is slow. |
| 372 | * Consequently, fdtdec_get_addr_size_auto_parent() should be used where | 348 | * Consequently, fdtdec_get_addr_size_auto_parent() should be used where |
| 373 | * possible. | 349 | * possible. |
| 374 | * | 350 | * |
| 375 | * @param blob FDT blob | 351 | * @param blob FDT blob |
| 376 | * @param parent parent node of @node | 352 | * @param parent parent node of @node |
| 377 | * @param node node to examine | 353 | * @param node node to examine |
| 378 | * @param prop_name name of property to find | 354 | * @param prop_name name of property to find |
| 379 | * @param index which address to retrieve from a list of addresses. Often 0. | 355 | * @param index which address to retrieve from a list of addresses. Often 0. |
| 380 | * @param sizep a pointer to store the size into. Use NULL if not required | 356 | * @param sizep a pointer to store the size into. Use NULL if not required |
| 381 | * @param translate Indicates whether to translate the returned value | 357 | * @param translate Indicates whether to translate the returned value |
| 382 | * using the parent node's ranges property. | 358 | * using the parent node's ranges property. |
| 383 | * @return address, if found, or FDT_ADDR_T_NONE if not | 359 | * @return address, if found, or FDT_ADDR_T_NONE if not |
| 384 | */ | 360 | */ |
| 385 | fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, | 361 | fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, |
| 386 | const char *prop_name, int index, fdt_size_t *sizep, | 362 | const char *prop_name, int index, fdt_size_t *sizep, |
| 387 | bool translate); | 363 | bool translate); |
| 388 | 364 | ||
| 389 | /* | 365 | /* |
| 390 | * Look up an address property in a node and return the parsed address. | 366 | * Look up an address property in a node and return the parsed address. |
| 391 | * | 367 | * |
| 392 | * This variant hard-codes the number of cells used to represent the address | 368 | * This variant hard-codes the number of cells used to represent the address |
| 393 | * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also | 369 | * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also |
| 394 | * always returns the first address value in the property (index 0). | 370 | * always returns the first address value in the property (index 0). |
| 395 | * | 371 | * |
| 396 | * Use of this function is not recommended due to the hard-coding of cell | 372 | * Use of this function is not recommended due to the hard-coding of cell |
| 397 | * counts. There is no programmatic validation that these hard-coded values | 373 | * counts. There is no programmatic validation that these hard-coded values |
| 398 | * actually match the device tree content in any way at all. This assumption | 374 | * actually match the device tree content in any way at all. This assumption |
| 399 | * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately | 375 | * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately |
| 400 | * set in the U-Boot build and exercising strict control over DT content to | 376 | * set in the U-Boot build and exercising strict control over DT content to |
| 401 | * ensure use of matching #address-cells/#size-cells properties. However, this | 377 | * ensure use of matching #address-cells/#size-cells properties. However, this |
| 402 | * approach is error-prone; those familiar with DT will not expect the | 378 | * approach is error-prone; those familiar with DT will not expect the |
| 403 | * assumption to exist, and could easily invalidate it. If the assumption is | 379 | * assumption to exist, and could easily invalidate it. If the assumption is |
| 404 | * invalidated, this function will not report the issue, and debugging will | 380 | * invalidated, this function will not report the issue, and debugging will |
| 405 | * be required. Instead, use fdtdec_get_addr_size_auto_parent(). | 381 | * be required. Instead, use fdtdec_get_addr_size_auto_parent(). |
| 406 | * | 382 | * |
| 407 | * @param blob FDT blob | 383 | * @param blob FDT blob |
| 408 | * @param node node to examine | 384 | * @param node node to examine |
| 409 | * @param prop_name name of property to find | 385 | * @param prop_name name of property to find |
| 410 | * @return address, if found, or FDT_ADDR_T_NONE if not | 386 | * @return address, if found, or FDT_ADDR_T_NONE if not |
| 411 | */ | 387 | */ |
| 412 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, | 388 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, |
| 413 | const char *prop_name); | 389 | const char *prop_name); |
| 414 | 390 | ||
| 415 | /* | 391 | /* |
| 416 | * Look up an address property in a node and return the parsed address, and | 392 | * Look up an address property in a node and return the parsed address, and |
| 417 | * optionally the parsed size. | 393 | * optionally the parsed size. |
| 418 | * | 394 | * |
| 419 | * This variant hard-codes the number of cells used to represent the address | 395 | * This variant hard-codes the number of cells used to represent the address |
| 420 | * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also | 396 | * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also |
| 421 | * always returns the first address value in the property (index 0). | 397 | * always returns the first address value in the property (index 0). |
| 422 | * | 398 | * |
| 423 | * Use of this function is not recommended due to the hard-coding of cell | 399 | * Use of this function is not recommended due to the hard-coding of cell |
| 424 | * counts. There is no programmatic validation that these hard-coded values | 400 | * counts. There is no programmatic validation that these hard-coded values |
| 425 | * actually match the device tree content in any way at all. This assumption | 401 | * actually match the device tree content in any way at all. This assumption |
| 426 | * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately | 402 | * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately |
| 427 | * set in the U-Boot build and exercising strict control over DT content to | 403 | * set in the U-Boot build and exercising strict control over DT content to |
| 428 | * ensure use of matching #address-cells/#size-cells properties. However, this | 404 | * ensure use of matching #address-cells/#size-cells properties. However, this |
| 429 | * approach is error-prone; those familiar with DT will not expect the | 405 | * approach is error-prone; those familiar with DT will not expect the |
| 430 | * assumption to exist, and could easily invalidate it. If the assumption is | 406 | * assumption to exist, and could easily invalidate it. If the assumption is |
| 431 | * invalidated, this function will not report the issue, and debugging will | 407 | * invalidated, this function will not report the issue, and debugging will |
| 432 | * be required. Instead, use fdtdec_get_addr_size_auto_parent(). | 408 | * be required. Instead, use fdtdec_get_addr_size_auto_parent(). |
| 433 | * | 409 | * |
| 434 | * @param blob FDT blob | 410 | * @param blob FDT blob |
| 435 | * @param node node to examine | 411 | * @param node node to examine |
| 436 | * @param prop_name name of property to find | 412 | * @param prop_name name of property to find |
| 437 | * @param sizep a pointer to store the size into. Use NULL if not required | 413 | * @param sizep a pointer to store the size into. Use NULL if not required |
| 438 | * @return address, if found, or FDT_ADDR_T_NONE if not | 414 | * @return address, if found, or FDT_ADDR_T_NONE if not |
| 439 | */ | 415 | */ |
| 440 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, | 416 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, |
| 441 | const char *prop_name, fdt_size_t *sizep); | 417 | const char *prop_name, fdt_size_t *sizep); |
| 442 | 418 | ||
| 443 | /** | 419 | /** |
| 444 | * Look at an address property in a node and return the pci address which | 420 | * Look at an address property in a node and return the pci address which |
| 445 | * corresponds to the given type in the form of fdt_pci_addr. | 421 | * corresponds to the given type in the form of fdt_pci_addr. |
| 446 | * The property must hold one fdt_pci_addr with a lengh. | 422 | * The property must hold one fdt_pci_addr with a lengh. |
| 447 | * | 423 | * |
| 448 | * @param blob FDT blob | 424 | * @param blob FDT blob |
| 449 | * @param node node to examine | 425 | * @param node node to examine |
| 450 | * @param type pci address type (FDT_PCI_SPACE_xxx) | 426 | * @param type pci address type (FDT_PCI_SPACE_xxx) |
| 451 | * @param prop_name name of property to find | 427 | * @param prop_name name of property to find |
| 452 | * @param addr returns pci address in the form of fdt_pci_addr | 428 | * @param addr returns pci address in the form of fdt_pci_addr |
| 453 | * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the | 429 | * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the |
| 454 | * format of the property was invalid, -ENXIO if the requested | 430 | * format of the property was invalid, -ENXIO if the requested |
| 455 | * address type was not found | 431 | * address type was not found |
| 456 | */ | 432 | */ |
| 457 | int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, | 433 | int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, |
| 458 | const char *prop_name, struct fdt_pci_addr *addr); | 434 | const char *prop_name, struct fdt_pci_addr *addr); |
| 459 | 435 | ||
| 460 | /** | 436 | /** |
| 461 | * Look at the compatible property of a device node that represents a PCI | 437 | * Look at the compatible property of a device node that represents a PCI |
| 462 | * device and extract pci vendor id and device id from it. | 438 | * device and extract pci vendor id and device id from it. |
| 463 | * | 439 | * |
| 464 | * @param blob FDT blob | 440 | * @param blob FDT blob |
| 465 | * @param node node to examine | 441 | * @param node node to examine |
| 466 | * @param vendor vendor id of the pci device | 442 | * @param vendor vendor id of the pci device |
| 467 | * @param device device id of the pci device | 443 | * @param device device id of the pci device |
| 468 | * @return 0 if ok, negative on error | 444 | * @return 0 if ok, negative on error |
| 469 | */ | 445 | */ |
| 470 | int fdtdec_get_pci_vendev(const void *blob, int node, | 446 | int fdtdec_get_pci_vendev(const void *blob, int node, |
| 471 | u16 *vendor, u16 *device); | 447 | u16 *vendor, u16 *device); |
| 472 | 448 | ||
| 473 | /** | 449 | /** |
| 474 | * Look at the pci address of a device node that represents a PCI device | 450 | * Look at the pci address of a device node that represents a PCI device |
| 475 | * and return base address of the pci device's registers. | 451 | * and return base address of the pci device's registers. |
| 476 | * | 452 | * |
| 477 | * @param dev device to examine | 453 | * @param dev device to examine |
| 478 | * @param addr pci address in the form of fdt_pci_addr | 454 | * @param addr pci address in the form of fdt_pci_addr |
| 479 | * @param bar returns base address of the pci device's registers | 455 | * @param bar returns base address of the pci device's registers |
| 480 | * @return 0 if ok, negative on error | 456 | * @return 0 if ok, negative on error |
| 481 | */ | 457 | */ |
| 482 | int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, | 458 | int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, |
| 483 | u32 *bar); | 459 | u32 *bar); |
| 484 | 460 | ||
| 485 | /** | 461 | /** |
| 486 | * Look up a 32-bit integer property in a node and return it. The property | 462 | * Look up a 32-bit integer property in a node and return it. The property |
| 487 | * must have at least 4 bytes of data. The value of the first cell is | 463 | * must have at least 4 bytes of data. The value of the first cell is |
| 488 | * returned. | 464 | * returned. |
| 489 | * | 465 | * |
| 490 | * @param blob FDT blob | 466 | * @param blob FDT blob |
| 491 | * @param node node to examine | 467 | * @param node node to examine |
| 492 | * @param prop_name name of property to find | 468 | * @param prop_name name of property to find |
| 493 | * @param default_val default value to return if the property is not found | 469 | * @param default_val default value to return if the property is not found |
| 494 | * @return integer value, if found, or default_val if not | 470 | * @return integer value, if found, or default_val if not |
| 495 | */ | 471 | */ |
| 496 | s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, | 472 | s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, |
| 497 | s32 default_val); | 473 | s32 default_val); |
| 498 | 474 | ||
| 499 | /** | 475 | /** |
| 500 | * Unsigned version of fdtdec_get_int. The property must have at least | 476 | * Unsigned version of fdtdec_get_int. The property must have at least |
| 501 | * 4 bytes of data. The value of the first cell is returned. | 477 | * 4 bytes of data. The value of the first cell is returned. |
| 502 | * | 478 | * |
| 503 | * @param blob FDT blob | 479 | * @param blob FDT blob |
| 504 | * @param node node to examine | 480 | * @param node node to examine |
| 505 | * @param prop_name name of property to find | 481 | * @param prop_name name of property to find |
| 506 | * @param default_val default value to return if the property is not found | 482 | * @param default_val default value to return if the property is not found |
| 507 | * @return unsigned integer value, if found, or default_val if not | 483 | * @return unsigned integer value, if found, or default_val if not |
| 508 | */ | 484 | */ |
| 509 | unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name, | 485 | unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name, |
| 510 | unsigned int default_val); | 486 | unsigned int default_val); |
| 511 | 487 | ||
| 512 | /** | 488 | /** |
| 513 | * Get a variable-sized number from a property | 489 | * Get a variable-sized number from a property |
| 514 | * | 490 | * |
| 515 | * This reads a number from one or more cells. | 491 | * This reads a number from one or more cells. |
| 516 | * | 492 | * |
| 517 | * @param ptr Pointer to property | 493 | * @param ptr Pointer to property |
| 518 | * @param cells Number of cells containing the number | 494 | * @param cells Number of cells containing the number |
| 519 | * @return the value in the cells | 495 | * @return the value in the cells |
| 520 | */ | 496 | */ |
| 521 | u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells); | 497 | u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells); |
| 522 | 498 | ||
| 523 | /** | 499 | /** |
| 524 | * Look up a 64-bit integer property in a node and return it. The property | 500 | * Look up a 64-bit integer property in a node and return it. The property |
| 525 | * must have at least 8 bytes of data (2 cells). The first two cells are | 501 | * must have at least 8 bytes of data (2 cells). The first two cells are |
| 526 | * concatenated to form a 8 bytes value, where the first cell is top half and | 502 | * concatenated to form a 8 bytes value, where the first cell is top half and |
| 527 | * the second cell is bottom half. | 503 | * the second cell is bottom half. |
| 528 | * | 504 | * |
| 529 | * @param blob FDT blob | 505 | * @param blob FDT blob |
| 530 | * @param node node to examine | 506 | * @param node node to examine |
| 531 | * @param prop_name name of property to find | 507 | * @param prop_name name of property to find |
| 532 | * @param default_val default value to return if the property is not found | 508 | * @param default_val default value to return if the property is not found |
| 533 | * @return integer value, if found, or default_val if not | 509 | * @return integer value, if found, or default_val if not |
| 534 | */ | 510 | */ |
| 535 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, | 511 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, |
| 536 | uint64_t default_val); | 512 | uint64_t default_val); |
| 537 | 513 | ||
| 538 | /** | 514 | /** |
| 539 | * Checks whether a node is enabled. | 515 | * Checks whether a node is enabled. |
| 540 | * This looks for a 'status' property. If this exists, then returns 1 if | 516 | * This looks for a 'status' property. If this exists, then returns 1 if |
| 541 | * the status is 'ok' and 0 otherwise. If there is no status property, | 517 | * the status is 'ok' and 0 otherwise. If there is no status property, |
| 542 | * it returns 1 on the assumption that anything mentioned should be enabled | 518 | * it returns 1 on the assumption that anything mentioned should be enabled |
| 543 | * by default. | 519 | * by default. |
| 544 | * | 520 | * |
| 545 | * @param blob FDT blob | 521 | * @param blob FDT blob |
| 546 | * @param node node to examine | 522 | * @param node node to examine |
| 547 | * @return integer value 0 (not enabled) or 1 (enabled) | 523 | * @return integer value 0 (not enabled) or 1 (enabled) |
| 548 | */ | 524 | */ |
| 549 | int fdtdec_get_is_enabled(const void *blob, int node); | 525 | int fdtdec_get_is_enabled(const void *blob, int node); |
| 550 | 526 | ||
| 551 | /** | 527 | /** |
| 552 | * Make sure we have a valid fdt available to control U-Boot. | 528 | * Make sure we have a valid fdt available to control U-Boot. |
| 553 | * | 529 | * |
| 554 | * If not, a message is printed to the console if the console is ready. | 530 | * If not, a message is printed to the console if the console is ready. |
| 555 | * | 531 | * |
| 556 | * @return 0 if all ok, -1 if not | 532 | * @return 0 if all ok, -1 if not |
| 557 | */ | 533 | */ |
| 558 | int fdtdec_prepare_fdt(void); | 534 | int fdtdec_prepare_fdt(void); |
| 559 | 535 | ||
| 560 | /** | 536 | /** |
| 561 | * Checks that we have a valid fdt available to control U-Boot. | 537 | * Checks that we have a valid fdt available to control U-Boot. |
| 562 | 538 | ||
| 563 | * However, if not then for the moment nothing is done, since this function | 539 | * However, if not then for the moment nothing is done, since this function |
| 564 | * is called too early to panic(). | 540 | * is called too early to panic(). |
| 565 | * | 541 | * |
| 566 | * @returns 0 | 542 | * @returns 0 |
| 567 | */ | 543 | */ |
| 568 | int fdtdec_check_fdt(void); | 544 | int fdtdec_check_fdt(void); |
| 569 | 545 | ||
| 570 | /** | 546 | /** |
| 571 | * Find the nodes for a peripheral and return a list of them in the correct | 547 | * Find the nodes for a peripheral and return a list of them in the correct |
| 572 | * order. This is used to enumerate all the peripherals of a certain type. | 548 | * order. This is used to enumerate all the peripherals of a certain type. |
| 573 | * | 549 | * |
| 574 | * To use this, optionally set up a /aliases node with alias properties for | 550 | * To use this, optionally set up a /aliases node with alias properties for |
| 575 | * a peripheral. For example, for usb you could have: | 551 | * a peripheral. For example, for usb you could have: |
| 576 | * | 552 | * |
| 577 | * aliases { | 553 | * aliases { |
| 578 | * usb0 = "/ehci@c5008000"; | 554 | * usb0 = "/ehci@c5008000"; |
| 579 | * usb1 = "/ehci@c5000000"; | 555 | * usb1 = "/ehci@c5000000"; |
| 580 | * }; | 556 | * }; |
| 581 | * | 557 | * |
| 582 | * Pass "usb" as the name to this function and will return a list of two | 558 | * Pass "usb" as the name to this function and will return a list of two |
| 583 | * nodes offsets: /ehci@c5008000 and ehci@c5000000. | 559 | * nodes offsets: /ehci@c5008000 and ehci@c5000000. |
| 584 | * | 560 | * |
| 585 | * All nodes returned will match the compatible ID, as it is assumed that | 561 | * All nodes returned will match the compatible ID, as it is assumed that |
| 586 | * all peripherals use the same driver. | 562 | * all peripherals use the same driver. |
| 587 | * | 563 | * |
| 588 | * If no alias node is found, then the node list will be returned in the | 564 | * If no alias node is found, then the node list will be returned in the |
| 589 | * order found in the fdt. If the aliases mention a node which doesn't | 565 | * order found in the fdt. If the aliases mention a node which doesn't |
| 590 | * exist, then this will be ignored. If nodes are found with no aliases, | 566 | * exist, then this will be ignored. If nodes are found with no aliases, |
| 591 | * they will be added in any order. | 567 | * they will be added in any order. |
| 592 | * | 568 | * |
| 593 | * If there is a gap in the aliases, then this function return a 0 node at | 569 | * If there is a gap in the aliases, then this function return a 0 node at |
| 594 | * that position. The return value will also count these gaps. | 570 | * that position. The return value will also count these gaps. |
| 595 | * | 571 | * |
| 596 | * This function checks node properties and will not return nodes which are | 572 | * This function checks node properties and will not return nodes which are |
| 597 | * marked disabled (status = "disabled"). | 573 | * marked disabled (status = "disabled"). |
| 598 | * | 574 | * |
| 599 | * @param blob FDT blob to use | 575 | * @param blob FDT blob to use |
| 600 | * @param name Root name of alias to search for | 576 | * @param name Root name of alias to search for |
| 601 | * @param id Compatible ID to look for | 577 | * @param id Compatible ID to look for |
| 602 | * @param node_list Place to put list of found nodes | 578 | * @param node_list Place to put list of found nodes |
| 603 | * @param maxcount Maximum number of nodes to find | 579 | * @param maxcount Maximum number of nodes to find |
| 604 | * @return number of nodes found on success, FDT_ERR_... on error | 580 | * @return number of nodes found on success, FDT_ERR_... on error |
| 605 | */ | 581 | */ |
| 606 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, | 582 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, |
| 607 | enum fdt_compat_id id, int *node_list, int maxcount); | 583 | enum fdt_compat_id id, int *node_list, int maxcount); |
| 608 | 584 | ||
| 609 | /* | 585 | /* |
| 610 | * This function is similar to fdtdec_find_aliases_for_id() except that it | 586 | * This function is similar to fdtdec_find_aliases_for_id() except that it |
| 611 | * adds to the node_list that is passed in. Any 0 elements are considered | 587 | * adds to the node_list that is passed in. Any 0 elements are considered |
| 612 | * available for allocation - others are considered already used and are | 588 | * available for allocation - others are considered already used and are |
| 613 | * skipped. | 589 | * skipped. |
| 614 | * | 590 | * |
| 615 | * You can use this by calling fdtdec_find_aliases_for_id() with an | 591 | * You can use this by calling fdtdec_find_aliases_for_id() with an |
| 616 | * uninitialised array, then setting the elements that are returned to -1, | 592 | * uninitialised array, then setting the elements that are returned to -1, |
| 617 | * say, then calling this function, perhaps with a different compat id. | 593 | * say, then calling this function, perhaps with a different compat id. |
| 618 | * Any elements you get back that are >0 are new nodes added by the call | 594 | * Any elements you get back that are >0 are new nodes added by the call |
| 619 | * to this function. | 595 | * to this function. |
| 620 | * | 596 | * |
| 621 | * Note that if you have some nodes with aliases and some without, you are | 597 | * Note that if you have some nodes with aliases and some without, you are |
| 622 | * sailing close to the wind. The call to fdtdec_find_aliases_for_id() with | 598 | * sailing close to the wind. The call to fdtdec_find_aliases_for_id() with |
| 623 | * one compat_id may fill in positions for which you have aliases defined | 599 | * one compat_id may fill in positions for which you have aliases defined |
| 624 | * for another compat_id. When you later call *this* function with the second | 600 | * for another compat_id. When you later call *this* function with the second |
| 625 | * compat_id, the alias positions may already be used. A debug warning may | 601 | * compat_id, the alias positions may already be used. A debug warning may |
| 626 | * be generated in this case, but it is safest to define aliases for all | 602 | * be generated in this case, but it is safest to define aliases for all |
| 627 | * nodes when you care about the ordering. | 603 | * nodes when you care about the ordering. |
| 628 | */ | 604 | */ |
| 629 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, | 605 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, |
| 630 | enum fdt_compat_id id, int *node_list, int maxcount); | 606 | enum fdt_compat_id id, int *node_list, int maxcount); |
| 631 | 607 | ||
| 632 | /** | 608 | /** |
| 633 | * Get the alias sequence number of a node | 609 | * Get the alias sequence number of a node |
| 634 | * | 610 | * |
| 635 | * This works out whether a node is pointed to by an alias, and if so, the | 611 | * This works out whether a node is pointed to by an alias, and if so, the |
| 636 | * sequence number of that alias. Aliases are of the form <base><num> where | 612 | * sequence number of that alias. Aliases are of the form <base><num> where |
| 637 | * <num> is the sequence number. For example spi2 would be sequence number | 613 | * <num> is the sequence number. For example spi2 would be sequence number |
| 638 | * 2. | 614 | * 2. |
| 639 | * | 615 | * |
| 640 | * @param blob Device tree blob (if NULL, then error is returned) | 616 | * @param blob Device tree blob (if NULL, then error is returned) |
| 641 | * @param base Base name for alias (before the underscore) | 617 | * @param base Base name for alias (before the underscore) |
| 642 | * @param node Node to look up | 618 | * @param node Node to look up |
| 643 | * @param seqp This is set to the sequence number if one is found, | 619 | * @param seqp This is set to the sequence number if one is found, |
| 644 | * but otherwise the value is left alone | 620 | * but otherwise the value is left alone |
| 645 | * @return 0 if a sequence was found, -ve if not | 621 | * @return 0 if a sequence was found, -ve if not |
| 646 | */ | 622 | */ |
| 647 | int fdtdec_get_alias_seq(const void *blob, const char *base, int node, | 623 | int fdtdec_get_alias_seq(const void *blob, const char *base, int node, |
| 648 | int *seqp); | 624 | int *seqp); |
| 649 | 625 | ||
| 650 | /** | 626 | /** |
| 651 | * Get the highest alias number for susbystem. | 627 | * Get the highest alias number for susbystem. |
| 652 | * | 628 | * |
| 653 | * It parses all aliases and find out highest recorded alias for subsystem. | 629 | * It parses all aliases and find out highest recorded alias for subsystem. |
| 654 | * Aliases are of the form <base><num> where <num> is the sequence number. | 630 | * Aliases are of the form <base><num> where <num> is the sequence number. |
| 655 | * | 631 | * |
| 656 | * @param blob Device tree blob (if NULL, then error is returned) | 632 | * @param blob Device tree blob (if NULL, then error is returned) |
| 657 | * @param base Base name for alias susbystem (before the number) | 633 | * @param base Base name for alias susbystem (before the number) |
| 658 | * | 634 | * |
| 659 | * @return 0 highest alias ID, -1 if not found | 635 | * @return 0 highest alias ID, -1 if not found |
| 660 | */ | 636 | */ |
| 661 | int fdtdec_get_alias_highest_id(const void *blob, const char *base); | 637 | int fdtdec_get_alias_highest_id(const void *blob, const char *base); |
| 662 | 638 | ||
| 663 | /** | 639 | /** |
| 664 | * Get a property from the /chosen node | 640 | * Get a property from the /chosen node |
| 665 | * | 641 | * |
| 666 | * @param blob Device tree blob (if NULL, then NULL is returned) | 642 | * @param blob Device tree blob (if NULL, then NULL is returned) |
| 667 | * @param name Property name to look up | 643 | * @param name Property name to look up |
| 668 | * @return Value of property, or NULL if it does not exist | 644 | * @return Value of property, or NULL if it does not exist |
| 669 | */ | 645 | */ |
| 670 | const char *fdtdec_get_chosen_prop(const void *blob, const char *name); | 646 | const char *fdtdec_get_chosen_prop(const void *blob, const char *name); |
| 671 | 647 | ||
| 672 | /** | 648 | /** |
| 673 | * Get the offset of the given /chosen node | 649 | * Get the offset of the given /chosen node |
| 674 | * | 650 | * |
| 675 | * This looks up a property in /chosen containing the path to another node, | 651 | * This looks up a property in /chosen containing the path to another node, |
| 676 | * then finds the offset of that node. | 652 | * then finds the offset of that node. |
| 677 | * | 653 | * |
| 678 | * @param blob Device tree blob (if NULL, then error is returned) | 654 | * @param blob Device tree blob (if NULL, then error is returned) |
| 679 | * @param name Property name, e.g. "stdout-path" | 655 | * @param name Property name, e.g. "stdout-path" |
| 680 | * @return Node offset referred to by that chosen node, or -ve FDT_ERR_... | 656 | * @return Node offset referred to by that chosen node, or -ve FDT_ERR_... |
| 681 | */ | 657 | */ |
| 682 | int fdtdec_get_chosen_node(const void *blob, const char *name); | 658 | int fdtdec_get_chosen_node(const void *blob, const char *name); |
| 683 | 659 | ||
| 684 | /* | 660 | /* |
| 685 | * Get the name for a compatible ID | 661 | * Get the name for a compatible ID |
| 686 | * | 662 | * |
| 687 | * @param id Compatible ID to look for | 663 | * @param id Compatible ID to look for |
| 688 | * @return compatible string for that id | 664 | * @return compatible string for that id |
| 689 | */ | 665 | */ |
| 690 | const char *fdtdec_get_compatible(enum fdt_compat_id id); | 666 | const char *fdtdec_get_compatible(enum fdt_compat_id id); |
| 691 | 667 | ||
| 692 | /* Look up a phandle and follow it to its node. Then return the offset | 668 | /* Look up a phandle and follow it to its node. Then return the offset |
| 693 | * of that node. | 669 | * of that node. |
| 694 | * | 670 | * |
| 695 | * @param blob FDT blob | 671 | * @param blob FDT blob |
| 696 | * @param node node to examine | 672 | * @param node node to examine |
| 697 | * @param prop_name name of property to find | 673 | * @param prop_name name of property to find |
| 698 | * @return node offset if found, -ve error code on error | 674 | * @return node offset if found, -ve error code on error |
| 699 | */ | 675 | */ |
| 700 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name); | 676 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name); |
| 701 | 677 | ||
| 702 | /** | 678 | /** |
| 703 | * Look up a property in a node and return its contents in an integer | 679 | * Look up a property in a node and return its contents in an integer |
| 704 | * array of given length. The property must have at least enough data for | 680 | * array of given length. The property must have at least enough data for |
| 705 | * the array (4*count bytes). It may have more, but this will be ignored. | 681 | * the array (4*count bytes). It may have more, but this will be ignored. |
| 706 | * | 682 | * |
| 707 | * @param blob FDT blob | 683 | * @param blob FDT blob |
| 708 | * @param node node to examine | 684 | * @param node node to examine |
| 709 | * @param prop_name name of property to find | 685 | * @param prop_name name of property to find |
| 710 | * @param array array to fill with data | 686 | * @param array array to fill with data |
| 711 | * @param count number of array elements | 687 | * @param count number of array elements |
| 712 | * @return 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found, | 688 | * @return 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found, |
| 713 | * or -FDT_ERR_BADLAYOUT if not enough data | 689 | * or -FDT_ERR_BADLAYOUT if not enough data |
| 714 | */ | 690 | */ |
| 715 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, | 691 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, |
| 716 | u32 *array, int count); | 692 | u32 *array, int count); |
| 717 | 693 | ||
| 718 | /** | 694 | /** |
| 719 | * Look up a property in a node and return its contents in an integer | 695 | * Look up a property in a node and return its contents in an integer |
| 720 | * array of given length. The property must exist but may have less data that | 696 | * array of given length. The property must exist but may have less data that |
| 721 | * expected (4*count bytes). It may have more, but this will be ignored. | 697 | * expected (4*count bytes). It may have more, but this will be ignored. |
| 722 | * | 698 | * |
| 723 | * @param blob FDT blob | 699 | * @param blob FDT blob |
| 724 | * @param node node to examine | 700 | * @param node node to examine |
| 725 | * @param prop_name name of property to find | 701 | * @param prop_name name of property to find |
| 726 | * @param array array to fill with data | 702 | * @param array array to fill with data |
| 727 | * @param count number of array elements | 703 | * @param count number of array elements |
| 728 | * @return number of array elements if ok, or -FDT_ERR_NOTFOUND if the | 704 | * @return number of array elements if ok, or -FDT_ERR_NOTFOUND if the |
| 729 | * property is not found | 705 | * property is not found |
| 730 | */ | 706 | */ |
| 731 | int fdtdec_get_int_array_count(const void *blob, int node, | 707 | int fdtdec_get_int_array_count(const void *blob, int node, |
| 732 | const char *prop_name, u32 *array, int count); | 708 | const char *prop_name, u32 *array, int count); |
| 733 | 709 | ||
| 734 | /** | 710 | /** |
| 735 | * Look up a property in a node and return a pointer to its contents as a | 711 | * Look up a property in a node and return a pointer to its contents as a |
| 736 | * unsigned int array of given length. The property must have at least enough | 712 | * unsigned int array of given length. The property must have at least enough |
| 737 | * data for the array ('count' cells). It may have more, but this will be | 713 | * data for the array ('count' cells). It may have more, but this will be |
| 738 | * ignored. The data is not copied. | 714 | * ignored. The data is not copied. |
| 739 | * | 715 | * |
| 740 | * Note that you must access elements of the array with fdt32_to_cpu(), | 716 | * Note that you must access elements of the array with fdt32_to_cpu(), |
| 741 | * since the elements will be big endian even on a little endian machine. | 717 | * since the elements will be big endian even on a little endian machine. |
| 742 | * | 718 | * |
| 743 | * @param blob FDT blob | 719 | * @param blob FDT blob |
| 744 | * @param node node to examine | 720 | * @param node node to examine |
| 745 | * @param prop_name name of property to find | 721 | * @param prop_name name of property to find |
| 746 | * @param count number of array elements | 722 | * @param count number of array elements |
| 747 | * @return pointer to array if found, or NULL if the property is not | 723 | * @return pointer to array if found, or NULL if the property is not |
| 748 | * found or there is not enough data | 724 | * found or there is not enough data |
| 749 | */ | 725 | */ |
| 750 | const u32 *fdtdec_locate_array(const void *blob, int node, | 726 | const u32 *fdtdec_locate_array(const void *blob, int node, |
| 751 | const char *prop_name, int count); | 727 | const char *prop_name, int count); |
| 752 | 728 | ||
| 753 | /** | 729 | /** |
| 754 | * Look up a boolean property in a node and return it. | 730 | * Look up a boolean property in a node and return it. |
| 755 | * | 731 | * |
| 756 | * A boolean properly is true if present in the device tree and false if not | 732 | * A boolean properly is true if present in the device tree and false if not |
| 757 | * present, regardless of its value. | 733 | * present, regardless of its value. |
| 758 | * | 734 | * |
| 759 | * @param blob FDT blob | 735 | * @param blob FDT blob |
| 760 | * @param node node to examine | 736 | * @param node node to examine |
| 761 | * @param prop_name name of property to find | 737 | * @param prop_name name of property to find |
| 762 | * @return 1 if the properly is present; 0 if it isn't present | 738 | * @return 1 if the properly is present; 0 if it isn't present |
| 763 | */ | 739 | */ |
| 764 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name); | 740 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name); |
| 765 | 741 | ||
| 766 | /* | 742 | /* |
| 767 | * Count child nodes of one parent node. | 743 | * Count child nodes of one parent node. |
| 768 | * | 744 | * |
| 769 | * @param blob FDT blob | 745 | * @param blob FDT blob |
| 770 | * @param node parent node | 746 | * @param node parent node |
| 771 | * @return number of child node; 0 if there is not child node | 747 | * @return number of child node; 0 if there is not child node |
| 772 | */ | 748 | */ |
| 773 | int fdtdec_get_child_count(const void *blob, int node); | 749 | int fdtdec_get_child_count(const void *blob, int node); |
| 774 | 750 | ||
| 775 | /** | 751 | /** |
| 776 | * Look in the FDT for a config item with the given name and return its value | 752 | * Look in the FDT for a config item with the given name and return its value |
| 777 | * as a 32-bit integer. The property must have at least 4 bytes of data. The | 753 | * as a 32-bit integer. The property must have at least 4 bytes of data. The |
| 778 | * value of the first cell is returned. | 754 | * value of the first cell is returned. |
| 779 | * | 755 | * |
| 780 | * @param blob FDT blob to use | 756 | * @param blob FDT blob to use |
| 781 | * @param prop_name Node property name | 757 | * @param prop_name Node property name |
| 782 | * @param default_val default value to return if the property is not found | 758 | * @param default_val default value to return if the property is not found |
| 783 | * @return integer value, if found, or default_val if not | 759 | * @return integer value, if found, or default_val if not |
| 784 | */ | 760 | */ |
| 785 | int fdtdec_get_config_int(const void *blob, const char *prop_name, | 761 | int fdtdec_get_config_int(const void *blob, const char *prop_name, |
| 786 | int default_val); | 762 | int default_val); |
| 787 | 763 | ||
| 788 | /** | 764 | /** |
| 789 | * Look in the FDT for a config item with the given name | 765 | * Look in the FDT for a config item with the given name |
| 790 | * and return whether it exists. | 766 | * and return whether it exists. |
| 791 | * | 767 | * |
| 792 | * @param blob FDT blob | 768 | * @param blob FDT blob |
| 793 | * @param prop_name property name to look up | 769 | * @param prop_name property name to look up |
| 794 | * @return 1, if it exists, or 0 if not | 770 | * @return 1, if it exists, or 0 if not |
| 795 | */ | 771 | */ |
| 796 | int fdtdec_get_config_bool(const void *blob, const char *prop_name); | 772 | int fdtdec_get_config_bool(const void *blob, const char *prop_name); |
| 797 | 773 | ||
| 798 | /** | 774 | /** |
| 799 | * Look in the FDT for a config item with the given name and return its value | 775 | * Look in the FDT for a config item with the given name and return its value |
| 800 | * as a string. | 776 | * as a string. |
| 801 | * | 777 | * |
| 802 | * @param blob FDT blob | 778 | * @param blob FDT blob |
| 803 | * @param prop_name property name to look up | 779 | * @param prop_name property name to look up |
| 804 | * @returns property string, NULL on error. | 780 | * @returns property string, NULL on error. |
| 805 | */ | 781 | */ |
| 806 | char *fdtdec_get_config_string(const void *blob, const char *prop_name); | 782 | char *fdtdec_get_config_string(const void *blob, const char *prop_name); |
| 807 | 783 | ||
| 808 | /* | 784 | /* |
| 809 | * Look up a property in a node and return its contents in a byte | 785 | * Look up a property in a node and return its contents in a byte |
| 810 | * array of given length. The property must have at least enough data for | 786 | * array of given length. The property must have at least enough data for |
| 811 | * the array (count bytes). It may have more, but this will be ignored. | 787 | * the array (count bytes). It may have more, but this will be ignored. |
| 812 | * | 788 | * |
| 813 | * @param blob FDT blob | 789 | * @param blob FDT blob |
| 814 | * @param node node to examine | 790 | * @param node node to examine |
| 815 | * @param prop_name name of property to find | 791 | * @param prop_name name of property to find |
| 816 | * @param array array to fill with data | 792 | * @param array array to fill with data |
| 817 | * @param count number of array elements | 793 | * @param count number of array elements |
| 818 | * @return 0 if ok, or -FDT_ERR_MISSING if the property is not found, | 794 | * @return 0 if ok, or -FDT_ERR_MISSING if the property is not found, |
| 819 | * or -FDT_ERR_BADLAYOUT if not enough data | 795 | * or -FDT_ERR_BADLAYOUT if not enough data |
| 820 | */ | 796 | */ |
| 821 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, | 797 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, |
| 822 | u8 *array, int count); | 798 | u8 *array, int count); |
| 823 | 799 | ||
| 824 | /** | 800 | /** |
| 825 | * Look up a property in a node and return a pointer to its contents as a | 801 | * Look up a property in a node and return a pointer to its contents as a |
| 826 | * byte array of given length. The property must have at least enough data | 802 | * byte array of given length. The property must have at least enough data |
| 827 | * for the array (count bytes). It may have more, but this will be ignored. | 803 | * for the array (count bytes). It may have more, but this will be ignored. |
| 828 | * The data is not copied. | 804 | * The data is not copied. |
| 829 | * | 805 | * |
| 830 | * @param blob FDT blob | 806 | * @param blob FDT blob |
| 831 | * @param node node to examine | 807 | * @param node node to examine |
| 832 | * @param prop_name name of property to find | 808 | * @param prop_name name of property to find |
| 833 | * @param count number of array elements | 809 | * @param count number of array elements |
| 834 | * @return pointer to byte array if found, or NULL if the property is not | 810 | * @return pointer to byte array if found, or NULL if the property is not |
| 835 | * found or there is not enough data | 811 | * found or there is not enough data |
| 836 | */ | 812 | */ |
| 837 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, | 813 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, |
| 838 | const char *prop_name, int count); | 814 | const char *prop_name, int count); |
| 839 | 815 | ||
| 840 | /** | 816 | /** |
| 841 | * Obtain an indexed resource from a device property. | 817 | * Obtain an indexed resource from a device property. |
| 842 | * | 818 | * |
| 843 | * @param fdt FDT blob | 819 | * @param fdt FDT blob |
| 844 | * @param node node to examine | 820 | * @param node node to examine |
| 845 | * @param property name of the property to parse | 821 | * @param property name of the property to parse |
| 846 | * @param index index of the resource to retrieve | 822 | * @param index index of the resource to retrieve |
| 847 | * @param res returns the resource | 823 | * @param res returns the resource |
| 848 | * @return 0 if ok, negative on error | 824 | * @return 0 if ok, negative on error |
| 849 | */ | 825 | */ |
| 850 | int fdt_get_resource(const void *fdt, int node, const char *property, | 826 | int fdt_get_resource(const void *fdt, int node, const char *property, |
| 851 | unsigned int index, struct fdt_resource *res); | 827 | unsigned int index, struct fdt_resource *res); |
| 852 | 828 | ||
| 853 | /** | 829 | /** |
| 854 | * Obtain a named resource from a device property. | 830 | * Obtain a named resource from a device property. |
| 855 | * | 831 | * |
| 856 | * Look up the index of the name in a list of strings and return the resource | 832 | * Look up the index of the name in a list of strings and return the resource |
| 857 | * at that index. | 833 | * at that index. |
| 858 | * | 834 | * |
| 859 | * @param fdt FDT blob | 835 | * @param fdt FDT blob |
| 860 | * @param node node to examine | 836 | * @param node node to examine |
| 861 | * @param property name of the property to parse | 837 | * @param property name of the property to parse |
| 862 | * @param prop_names name of the property containing the list of names | 838 | * @param prop_names name of the property containing the list of names |
| 863 | * @param name the name of the entry to look up | 839 | * @param name the name of the entry to look up |
| 864 | * @param res returns the resource | 840 | * @param res returns the resource |
| 865 | */ | 841 | */ |
| 866 | int fdt_get_named_resource(const void *fdt, int node, const char *property, | 842 | int fdt_get_named_resource(const void *fdt, int node, const char *property, |
| 867 | const char *prop_names, const char *name, | 843 | const char *prop_names, const char *name, |
| 868 | struct fdt_resource *res); | 844 | struct fdt_resource *res); |
| 869 | 845 | ||
| 870 | /* Display timings from linux include/video/display_timing.h */ | 846 | /* Display timings from linux include/video/display_timing.h */ |
| 871 | enum display_flags { | 847 | enum display_flags { |
| 872 | DISPLAY_FLAGS_HSYNC_LOW = 1 << 0, | 848 | DISPLAY_FLAGS_HSYNC_LOW = 1 << 0, |
| 873 | DISPLAY_FLAGS_HSYNC_HIGH = 1 << 1, | 849 | DISPLAY_FLAGS_HSYNC_HIGH = 1 << 1, |
| 874 | DISPLAY_FLAGS_VSYNC_LOW = 1 << 2, | 850 | DISPLAY_FLAGS_VSYNC_LOW = 1 << 2, |
| 875 | DISPLAY_FLAGS_VSYNC_HIGH = 1 << 3, | 851 | DISPLAY_FLAGS_VSYNC_HIGH = 1 << 3, |
| 876 | 852 | ||
| 877 | /* data enable flag */ | 853 | /* data enable flag */ |
| 878 | DISPLAY_FLAGS_DE_LOW = 1 << 4, | 854 | DISPLAY_FLAGS_DE_LOW = 1 << 4, |
| 879 | DISPLAY_FLAGS_DE_HIGH = 1 << 5, | 855 | DISPLAY_FLAGS_DE_HIGH = 1 << 5, |
| 880 | /* drive data on pos. edge */ | 856 | /* drive data on pos. edge */ |
| 881 | DISPLAY_FLAGS_PIXDATA_POSEDGE = 1 << 6, | 857 | DISPLAY_FLAGS_PIXDATA_POSEDGE = 1 << 6, |
| 882 | /* drive data on neg. edge */ | 858 | /* drive data on neg. edge */ |
| 883 | DISPLAY_FLAGS_PIXDATA_NEGEDGE = 1 << 7, | 859 | DISPLAY_FLAGS_PIXDATA_NEGEDGE = 1 << 7, |
| 884 | DISPLAY_FLAGS_INTERLACED = 1 << 8, | 860 | DISPLAY_FLAGS_INTERLACED = 1 << 8, |
| 885 | DISPLAY_FLAGS_DOUBLESCAN = 1 << 9, | 861 | DISPLAY_FLAGS_DOUBLESCAN = 1 << 9, |
| 886 | DISPLAY_FLAGS_DOUBLECLK = 1 << 10, | 862 | DISPLAY_FLAGS_DOUBLECLK = 1 << 10, |
| 887 | }; | 863 | }; |
| 888 | 864 | ||
| 889 | /* | 865 | /* |
| 890 | * A single signal can be specified via a range of minimal and maximal values | 866 | * A single signal can be specified via a range of minimal and maximal values |
| 891 | * with a typical value, that lies somewhere inbetween. | 867 | * with a typical value, that lies somewhere inbetween. |
| 892 | */ | 868 | */ |
| 893 | struct timing_entry { | 869 | struct timing_entry { |
| 894 | u32 min; | 870 | u32 min; |
| 895 | u32 typ; | 871 | u32 typ; |
| 896 | u32 max; | 872 | u32 max; |
| 897 | }; | 873 | }; |
| 898 | 874 | ||
| 899 | /* | 875 | /* |
| 900 | * Single "mode" entry. This describes one set of signal timings a display can | 876 | * Single "mode" entry. This describes one set of signal timings a display can |
| 901 | * have in one setting. This struct can later be converted to struct videomode | 877 | * have in one setting. This struct can later be converted to struct videomode |
| 902 | * (see include/video/videomode.h). As each timing_entry can be defined as a | 878 | * (see include/video/videomode.h). As each timing_entry can be defined as a |
| 903 | * range, one struct display_timing may become multiple struct videomodes. | 879 | * range, one struct display_timing may become multiple struct videomodes. |
| 904 | * | 880 | * |
| 905 | * Example: hsync active high, vsync active low | 881 | * Example: hsync active high, vsync active low |
| 906 | * | 882 | * |
| 907 | * Active Video | 883 | * Active Video |
| 908 | * Video ______________________XXXXXXXXXXXXXXXXXXXXXX_____________________ | 884 | * Video ______________________XXXXXXXXXXXXXXXXXXXXXX_____________________ |
| 909 | * |<- sync ->|<- back ->|<----- active ----->|<- front ->|<- sync.. | 885 | * |<- sync ->|<- back ->|<----- active ----->|<- front ->|<- sync.. |
| 910 | * | | porch | | porch | | 886 | * | | porch | | porch | |
| 911 | * | 887 | * |
| 912 | * HSync _|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|___________________________________________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏ | 888 | * HSync _|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|___________________________________________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏ |
| 913 | * | 889 | * |
| 914 | * VSync ยฏ|__________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|_________ | 890 | * VSync ยฏ|__________|ยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏยฏ|_________ |
| 915 | */ | 891 | */ |
| 916 | struct display_timing { | 892 | struct display_timing { |
| 917 | struct timing_entry pixelclock; | 893 | struct timing_entry pixelclock; |
| 918 | 894 | ||
| 919 | struct timing_entry hactive; /* hor. active video */ | 895 | struct timing_entry hactive; /* hor. active video */ |
| 920 | struct timing_entry hfront_porch; /* hor. front porch */ | 896 | struct timing_entry hfront_porch; /* hor. front porch */ |
| 921 | struct timing_entry hback_porch; /* hor. back porch */ | 897 | struct timing_entry hback_porch; /* hor. back porch */ |
| 922 | struct timing_entry hsync_len; /* hor. sync len */ | 898 | struct timing_entry hsync_len; /* hor. sync len */ |
| 923 | 899 | ||
| 924 | struct timing_entry vactive; /* ver. active video */ | 900 | struct timing_entry vactive; /* ver. active video */ |
| 925 | struct timing_entry vfront_porch; /* ver. front porch */ | 901 | struct timing_entry vfront_porch; /* ver. front porch */ |
| 926 | struct timing_entry vback_porch; /* ver. back porch */ | 902 | struct timing_entry vback_porch; /* ver. back porch */ |
| 927 | struct timing_entry vsync_len; /* ver. sync len */ | 903 | struct timing_entry vsync_len; /* ver. sync len */ |
| 928 | 904 | ||
| 929 | enum display_flags flags; /* display flags */ | 905 | enum display_flags flags; /* display flags */ |
| 930 | bool hdmi_monitor; /* is hdmi monitor? */ | 906 | bool hdmi_monitor; /* is hdmi monitor? */ |
| 931 | }; | 907 | }; |
| 932 | 908 | ||
| 933 | /** | 909 | /** |
| 934 | * fdtdec_decode_display_timing() - decode display timings | 910 | * fdtdec_decode_display_timing() - decode display timings |
| 935 | * | 911 | * |
| 936 | * Decode display timings from the supplied 'display-timings' node. | 912 | * Decode display timings from the supplied 'display-timings' node. |
| 937 | * See doc/device-tree-bindings/video/display-timing.txt for binding | 913 | * See doc/device-tree-bindings/video/display-timing.txt for binding |
| 938 | * information. | 914 | * information. |
| 939 | * | 915 | * |
| 940 | * @param blob FDT blob | 916 | * @param blob FDT blob |
| 941 | * @param node 'display-timing' node containing the timing subnodes | 917 | * @param node 'display-timing' node containing the timing subnodes |
| 942 | * @param index Index number to read (0=first timing subnode) | 918 | * @param index Index number to read (0=first timing subnode) |
| 943 | * @param config Place to put timings | 919 | * @param config Place to put timings |
| 944 | * @return 0 if OK, -FDT_ERR_NOTFOUND if not found | 920 | * @return 0 if OK, -FDT_ERR_NOTFOUND if not found |
| 945 | */ | 921 | */ |
| 946 | int fdtdec_decode_display_timing(const void *blob, int node, int index, | 922 | int fdtdec_decode_display_timing(const void *blob, int node, int index, |
| 947 | struct display_timing *config); | 923 | struct display_timing *config); |
| 948 | 924 | ||
| 949 | /** | 925 | /** |
| 950 | * fdtdec_setup_mem_size_base_fdt() - decode and setup gd->ram_size and | 926 | * fdtdec_setup_mem_size_base_fdt() - decode and setup gd->ram_size and |
| 951 | * gd->ram_start | 927 | * gd->ram_start |
| 952 | * | 928 | * |
| 953 | * Decode the /memory 'reg' property to determine the size and start of the | 929 | * Decode the /memory 'reg' property to determine the size and start of the |
| 954 | * first memory bank, populate the global data with the size and start of the | 930 | * first memory bank, populate the global data with the size and start of the |
| 955 | * first bank of memory. | 931 | * first bank of memory. |
| 956 | * | 932 | * |
| 957 | * This function should be called from a boards dram_init(). This helper | 933 | * This function should be called from a boards dram_init(). This helper |
| 958 | * function allows for boards to query the device tree for DRAM size and start | 934 | * function allows for boards to query the device tree for DRAM size and start |
| 959 | * address instead of hard coding the value in the case where the memory size | 935 | * address instead of hard coding the value in the case where the memory size |
| 960 | * and start address cannot be detected automatically. | 936 | * and start address cannot be detected automatically. |
| 961 | * | 937 | * |
| 962 | * @param blob FDT blob | 938 | * @param blob FDT blob |
| 963 | * | 939 | * |
| 964 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or | 940 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or |
| 965 | * invalid | 941 | * invalid |
| 966 | */ | 942 | */ |
| 967 | int fdtdec_setup_mem_size_base_fdt(const void *blob); | 943 | int fdtdec_setup_mem_size_base_fdt(const void *blob); |
| 968 | 944 | ||
| 969 | /** | 945 | /** |
| 970 | * fdtdec_setup_mem_size_base() - decode and setup gd->ram_size and | 946 | * fdtdec_setup_mem_size_base() - decode and setup gd->ram_size and |
| 971 | * gd->ram_start | 947 | * gd->ram_start |
| 972 | * | 948 | * |
| 973 | * Decode the /memory 'reg' property to determine the size and start of the | 949 | * Decode the /memory 'reg' property to determine the size and start of the |
| 974 | * first memory bank, populate the global data with the size and start of the | 950 | * first memory bank, populate the global data with the size and start of the |
| 975 | * first bank of memory. | 951 | * first bank of memory. |
| 976 | * | 952 | * |
| 977 | * This function should be called from a boards dram_init(). This helper | 953 | * This function should be called from a boards dram_init(). This helper |
| 978 | * function allows for boards to query the device tree for DRAM size and start | 954 | * function allows for boards to query the device tree for DRAM size and start |
| 979 | * address instead of hard coding the value in the case where the memory size | 955 | * address instead of hard coding the value in the case where the memory size |
| 980 | * and start address cannot be detected automatically. | 956 | * and start address cannot be detected automatically. |
| 981 | * | 957 | * |
| 982 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or | 958 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or |
| 983 | * invalid | 959 | * invalid |
| 984 | */ | 960 | */ |
| 985 | int fdtdec_setup_mem_size_base(void); | 961 | int fdtdec_setup_mem_size_base(void); |
| 986 | 962 | ||
| 987 | /** | 963 | /** |
| 988 | * fdtdec_setup_memory_banksize_fdt() - decode and populate gd->bd->bi_dram | 964 | * fdtdec_setup_memory_banksize_fdt() - decode and populate gd->bd->bi_dram |
| 989 | * | 965 | * |
| 990 | * Decode the /memory 'reg' property to determine the address and size of the | 966 | * Decode the /memory 'reg' property to determine the address and size of the |
| 991 | * memory banks. Use this data to populate the global data board info with the | 967 | * memory banks. Use this data to populate the global data board info with the |
| 992 | * phys address and size of memory banks. | 968 | * phys address and size of memory banks. |
| 993 | * | 969 | * |
| 994 | * This function should be called from a boards dram_init_banksize(). This | 970 | * This function should be called from a boards dram_init_banksize(). This |
| 995 | * helper function allows for boards to query the device tree for memory bank | 971 | * helper function allows for boards to query the device tree for memory bank |
| 996 | * information instead of hard coding the information in cases where it cannot | 972 | * information instead of hard coding the information in cases where it cannot |
| 997 | * be detected automatically. | 973 | * be detected automatically. |
| 998 | * | 974 | * |
| 999 | * @param blob FDT blob | 975 | * @param blob FDT blob |
| 1000 | * | 976 | * |
| 1001 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or | 977 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or |
| 1002 | * invalid | 978 | * invalid |
| 1003 | */ | 979 | */ |
| 1004 | int fdtdec_setup_memory_banksize_fdt(const void *blob); | 980 | int fdtdec_setup_memory_banksize_fdt(const void *blob); |
| 1005 | 981 | ||
| 1006 | /** | 982 | /** |
| 1007 | * fdtdec_setup_memory_banksize() - decode and populate gd->bd->bi_dram | 983 | * fdtdec_setup_memory_banksize() - decode and populate gd->bd->bi_dram |
| 1008 | * | 984 | * |
| 1009 | * Decode the /memory 'reg' property to determine the address and size of the | 985 | * Decode the /memory 'reg' property to determine the address and size of the |
| 1010 | * memory banks. Use this data to populate the global data board info with the | 986 | * memory banks. Use this data to populate the global data board info with the |
| 1011 | * phys address and size of memory banks. | 987 | * phys address and size of memory banks. |
| 1012 | * | 988 | * |
| 1013 | * This function should be called from a boards dram_init_banksize(). This | 989 | * This function should be called from a boards dram_init_banksize(). This |
| 1014 | * helper function allows for boards to query the device tree for memory bank | 990 | * helper function allows for boards to query the device tree for memory bank |
| 1015 | * information instead of hard coding the information in cases where it cannot | 991 | * information instead of hard coding the information in cases where it cannot |
| 1016 | * be detected automatically. | 992 | * be detected automatically. |
| 1017 | * | 993 | * |
| 1018 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or | 994 | * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or |
| 1019 | * invalid | 995 | * invalid |
| 1020 | */ | 996 | */ |
| 1021 | int fdtdec_setup_memory_banksize(void); | 997 | int fdtdec_setup_memory_banksize(void); |
| 1022 | 998 | ||
| 1023 | /** | 999 | /** |
| 1024 | * fdtdec_set_phandle() - sets the phandle of a given node | 1000 | * fdtdec_set_phandle() - sets the phandle of a given node |
| 1025 | * | 1001 | * |
| 1026 | * @param blob FDT blob | 1002 | * @param blob FDT blob |
| 1027 | * @param node offset in the FDT blob of the node whose phandle is to | 1003 | * @param node offset in the FDT blob of the node whose phandle is to |
| 1028 | * be set | 1004 | * be set |
| 1029 | * @param phandle phandle to set for the given node | 1005 | * @param phandle phandle to set for the given node |
| 1030 | * @return 0 on success or a negative error code on failure | 1006 | * @return 0 on success or a negative error code on failure |
| 1031 | */ | 1007 | */ |
| 1032 | static inline int fdtdec_set_phandle(void *blob, int node, uint32_t phandle) | 1008 | static inline int fdtdec_set_phandle(void *blob, int node, uint32_t phandle) |
| 1033 | { | 1009 | { |
| 1034 | return fdt_setprop_u32(blob, node, "phandle", phandle); | 1010 | return fdt_setprop_u32(blob, node, "phandle", phandle); |
| 1035 | } | 1011 | } |
| 1036 | 1012 | ||
| 1037 | /** | 1013 | /** |
| 1038 | * fdtdec_add_reserved_memory() - add or find a reserved-memory node | 1014 | * fdtdec_add_reserved_memory() - add or find a reserved-memory node |
| 1039 | * | 1015 | * |
| 1040 | * If a reserved-memory node already exists for the given carveout, a phandle | 1016 | * If a reserved-memory node already exists for the given carveout, a phandle |
| 1041 | * for that node will be returned. Otherwise a new node will be created and a | 1017 | * for that node will be returned. Otherwise a new node will be created and a |
| 1042 | * phandle corresponding to it will be returned. | 1018 | * phandle corresponding to it will be returned. |
| 1043 | * | 1019 | * |
| 1044 | * See Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt | 1020 | * See Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt |
| 1045 | * for details on how to use reserved memory regions. | 1021 | * for details on how to use reserved memory regions. |
| 1046 | * | 1022 | * |
| 1047 | * As an example, consider the following code snippet: | 1023 | * As an example, consider the following code snippet: |
| 1048 | * | 1024 | * |
| 1049 | * struct fdt_memory fb = { | 1025 | * struct fdt_memory fb = { |
| 1050 | * .start = 0x92cb3000, | 1026 | * .start = 0x92cb3000, |
| 1051 | * .end = 0x934b2fff, | 1027 | * .end = 0x934b2fff, |
| 1052 | * }; | 1028 | * }; |
| 1053 | * uint32_t phandle; | 1029 | * uint32_t phandle; |
| 1054 | * | 1030 | * |
| 1055 | * fdtdec_add_reserved_memory(fdt, "framebuffer", &fb, &phandle); | 1031 | * fdtdec_add_reserved_memory(fdt, "framebuffer", &fb, &phandle); |
| 1056 | * | 1032 | * |
| 1057 | * This results in the following subnode being added to the top-level | 1033 | * This results in the following subnode being added to the top-level |
| 1058 | * /reserved-memory node: | 1034 | * /reserved-memory node: |
| 1059 | * | 1035 | * |
| 1060 | * reserved-memory { | 1036 | * reserved-memory { |
| 1061 | * #address-cells = <0x00000002>; | 1037 | * #address-cells = <0x00000002>; |
| 1062 | * #size-cells = <0x00000002>; | 1038 | * #size-cells = <0x00000002>; |
| 1063 | * ranges; | 1039 | * ranges; |
| 1064 | * | 1040 | * |
| 1065 | * framebuffer@92cb3000 { | 1041 | * framebuffer@92cb3000 { |
| 1066 | * reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>; | 1042 | * reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>; |
| 1067 | * phandle = <0x0000004d>; | 1043 | * phandle = <0x0000004d>; |
| 1068 | * }; | 1044 | * }; |
| 1069 | * }; | 1045 | * }; |
| 1070 | * | 1046 | * |
| 1071 | * If the top-level /reserved-memory node does not exist, it will be created. | 1047 | * If the top-level /reserved-memory node does not exist, it will be created. |
| 1072 | * The phandle returned from the function call can be used to reference this | 1048 | * The phandle returned from the function call can be used to reference this |
| 1073 | * reserved memory region from other nodes. | 1049 | * reserved memory region from other nodes. |
| 1074 | * | 1050 | * |
| 1075 | * See fdtdec_set_carveout() for a more elaborate example. | 1051 | * See fdtdec_set_carveout() for a more elaborate example. |
| 1076 | * | 1052 | * |
| 1077 | * @param blob FDT blob | 1053 | * @param blob FDT blob |
| 1078 | * @param basename base name of the node to create | 1054 | * @param basename base name of the node to create |
| 1079 | * @param carveout information about the carveout region | 1055 | * @param carveout information about the carveout region |
| 1080 | * @param phandlep return location for the phandle of the carveout region | 1056 | * @param phandlep return location for the phandle of the carveout region |
| 1081 | * @return 0 on success or a negative error code on failure | 1057 | * @return 0 on success or a negative error code on failure |
| 1082 | */ | 1058 | */ |
| 1083 | int fdtdec_add_reserved_memory(void *blob, const char *basename, | 1059 | int fdtdec_add_reserved_memory(void *blob, const char *basename, |
| 1084 | const struct fdt_memory *carveout, | 1060 | const struct fdt_memory *carveout, |
| 1085 | uint32_t *phandlep); | 1061 | uint32_t *phandlep); |
| 1086 | 1062 | ||
| 1087 | /** | 1063 | /** |
| 1088 | * fdtdec_get_carveout() - reads a carveout from an FDT | 1064 | * fdtdec_get_carveout() - reads a carveout from an FDT |
| 1089 | * | 1065 | * |
| 1090 | * Reads information about a carveout region from an FDT. The carveout is a | 1066 | * Reads information about a carveout region from an FDT. The carveout is a |
| 1091 | * referenced by its phandle that is read from a given property in a given | 1067 | * referenced by its phandle that is read from a given property in a given |
| 1092 | * node. | 1068 | * node. |
| 1093 | * | 1069 | * |
| 1094 | * @param blob FDT blob | 1070 | * @param blob FDT blob |
| 1095 | * @param node name of a node | 1071 | * @param node name of a node |
| 1096 | * @param name name of the property in the given node that contains | 1072 | * @param name name of the property in the given node that contains |
| 1097 | * the phandle for the carveout | 1073 | * the phandle for the carveout |
| 1098 | * @param index index of the phandle for which to read the carveout | 1074 | * @param index index of the phandle for which to read the carveout |
| 1099 | * @param carveout return location for the carveout information | 1075 | * @param carveout return location for the carveout information |
| 1100 | * @return 0 on success or a negative error code on failure | 1076 | * @return 0 on success or a negative error code on failure |
| 1101 | */ | 1077 | */ |
| 1102 | int fdtdec_get_carveout(const void *blob, const char *node, const char *name, | 1078 | int fdtdec_get_carveout(const void *blob, const char *node, const char *name, |
| 1103 | unsigned int index, struct fdt_memory *carveout); | 1079 | unsigned int index, struct fdt_memory *carveout); |
| 1104 | 1080 | ||
| 1105 | /** | 1081 | /** |
| 1106 | * fdtdec_set_carveout() - sets a carveout region for a given node | 1082 | * fdtdec_set_carveout() - sets a carveout region for a given node |
| 1107 | * | 1083 | * |
| 1108 | * Sets a carveout region for a given node. If a reserved-memory node already | 1084 | * Sets a carveout region for a given node. If a reserved-memory node already |
| 1109 | * exists for the carveout, the phandle for that node will be reused. If no | 1085 | * exists for the carveout, the phandle for that node will be reused. If no |
| 1110 | * such node exists, a new one will be created and a phandle to it stored in | 1086 | * such node exists, a new one will be created and a phandle to it stored in |
| 1111 | * a specified property of the given node. | 1087 | * a specified property of the given node. |
| 1112 | * | 1088 | * |
| 1113 | * As an example, consider the following code snippet: | 1089 | * As an example, consider the following code snippet: |
| 1114 | * | 1090 | * |
| 1115 | * const char *node = "/host1x@50000000/dc@54240000"; | 1091 | * const char *node = "/host1x@50000000/dc@54240000"; |
| 1116 | * struct fdt_memory fb = { | 1092 | * struct fdt_memory fb = { |
| 1117 | * .start = 0x92cb3000, | 1093 | * .start = 0x92cb3000, |
| 1118 | * .end = 0x934b2fff, | 1094 | * .end = 0x934b2fff, |
| 1119 | * }; | 1095 | * }; |
| 1120 | * | 1096 | * |
| 1121 | * fdtdec_set_carveout(fdt, node, "memory-region", 0, "framebuffer", &fb); | 1097 | * fdtdec_set_carveout(fdt, node, "memory-region", 0, "framebuffer", &fb); |
| 1122 | * | 1098 | * |
| 1123 | * dc@54200000 is a display controller and was set up by the bootloader to | 1099 | * dc@54200000 is a display controller and was set up by the bootloader to |
| 1124 | * scan out the framebuffer specified by "fb". This would cause the following | 1100 | * scan out the framebuffer specified by "fb". This would cause the following |
| 1125 | * reserved memory region to be added: | 1101 | * reserved memory region to be added: |
| 1126 | * | 1102 | * |
| 1127 | * reserved-memory { | 1103 | * reserved-memory { |
| 1128 | * #address-cells = <0x00000002>; | 1104 | * #address-cells = <0x00000002>; |
| 1129 | * #size-cells = <0x00000002>; | 1105 | * #size-cells = <0x00000002>; |
| 1130 | * ranges; | 1106 | * ranges; |
| 1131 | * | 1107 | * |
| 1132 | * framebuffer@92cb3000 { | 1108 | * framebuffer@92cb3000 { |
| 1133 | * reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>; | 1109 | * reg = <0x00000000 0x92cb3000 0x00000000 0x00800000>; |
| 1134 | * phandle = <0x0000004d>; | 1110 | * phandle = <0x0000004d>; |
| 1135 | * }; | 1111 | * }; |
| 1136 | * }; | 1112 | * }; |
| 1137 | * | 1113 | * |
| 1138 | * A "memory-region" property will also be added to the node referenced by the | 1114 | * A "memory-region" property will also be added to the node referenced by the |
| 1139 | * offset parameter. | 1115 | * offset parameter. |
| 1140 | * | 1116 | * |
| 1141 | * host1x@50000000 { | 1117 | * host1x@50000000 { |
| 1142 | * ... | 1118 | * ... |
| 1143 | * | 1119 | * |
| 1144 | * dc@54240000 { | 1120 | * dc@54240000 { |
| 1145 | * ... | 1121 | * ... |
| 1146 | * memory-region = <0x0000004d>; | 1122 | * memory-region = <0x0000004d>; |
| 1147 | * ... | 1123 | * ... |
| 1148 | * }; | 1124 | * }; |
| 1149 | * | 1125 | * |
| 1150 | * ... | 1126 | * ... |
| 1151 | * }; | 1127 | * }; |
| 1152 | * | 1128 | * |
| 1153 | * @param blob FDT blob | 1129 | * @param blob FDT blob |
| 1154 | * @param node name of the node to add the carveout to | 1130 | * @param node name of the node to add the carveout to |
| 1155 | * @param prop_name name of the property in which to store the phandle of | 1131 | * @param prop_name name of the property in which to store the phandle of |
| 1156 | * the carveout | 1132 | * the carveout |
| 1157 | * @param index index of the phandle to store | 1133 | * @param index index of the phandle to store |
| 1158 | * @param name base name of the reserved-memory node to create | 1134 | * @param name base name of the reserved-memory node to create |
| 1159 | * @param carveout information about the carveout to add | 1135 | * @param carveout information about the carveout to add |
| 1160 | * @return 0 on success or a negative error code on failure | 1136 | * @return 0 on success or a negative error code on failure |
| 1161 | */ | 1137 | */ |
| 1162 | int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, | 1138 | int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, |
| 1163 | unsigned int index, const char *name, | 1139 | unsigned int index, const char *name, |
| 1164 | const struct fdt_memory *carveout); | 1140 | const struct fdt_memory *carveout); |
| 1165 | 1141 | ||
| 1166 | /** | 1142 | /** |
| 1167 | * Set up the device tree ready for use | 1143 | * Set up the device tree ready for use |
| 1168 | */ | 1144 | */ |
| 1169 | int fdtdec_setup(void); | 1145 | int fdtdec_setup(void); |
| 1170 | 1146 | ||
| 1171 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) | 1147 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) |
| 1172 | /** | 1148 | /** |
| 1173 | * fdtdec_resetup() - Set up the device tree again | 1149 | * fdtdec_resetup() - Set up the device tree again |
| 1174 | * | 1150 | * |
| 1175 | * The main difference with fdtdec_setup() is that it returns if the fdt has | 1151 | * The main difference with fdtdec_setup() is that it returns if the fdt has |
| 1176 | * changed because a better match has been found. | 1152 | * changed because a better match has been found. |
| 1177 | * This is typically used for boards that rely on a DM driver to detect the | 1153 | * This is typically used for boards that rely on a DM driver to detect the |
| 1178 | * board type. This function sould be called by the board code after the stuff | 1154 | * board type. This function sould be called by the board code after the stuff |
| 1179 | * needed by board_fit_config_name_match() to operate porperly is available. | 1155 | * needed by board_fit_config_name_match() to operate porperly is available. |
| 1180 | * If this functions signals that a rescan is necessary, the board code must | 1156 | * If this functions signals that a rescan is necessary, the board code must |
| 1181 | * unbind all the drivers using dm_uninit() and then rescan the DT with | 1157 | * unbind all the drivers using dm_uninit() and then rescan the DT with |
| 1182 | * dm_init_and_scan(). | 1158 | * dm_init_and_scan(). |
| 1183 | * | 1159 | * |
| 1184 | * @param rescan Returns a flag indicating that fdt has changed and rescanning | 1160 | * @param rescan Returns a flag indicating that fdt has changed and rescanning |
| 1185 | * the fdt is required | 1161 | * the fdt is required |
| 1186 | * | 1162 | * |
| 1187 | * @return 0 if OK, -ve on error | 1163 | * @return 0 if OK, -ve on error |
| 1188 | */ | 1164 | */ |
| 1189 | int fdtdec_resetup(int *rescan); | 1165 | int fdtdec_resetup(int *rescan); |
| 1190 | #endif | 1166 | #endif |
| 1191 | 1167 | ||
| 1192 | /** | 1168 | /** |
| 1193 | * Board-specific FDT initialization. Returns the address to a device tree blob. | 1169 | * Board-specific FDT initialization. Returns the address to a device tree blob. |
| 1194 | * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined | 1170 | * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined |
| 1195 | * and the board implements it. | 1171 | * and the board implements it. |
| 1196 | */ | 1172 | */ |
| 1197 | void *board_fdt_blob_setup(void); | 1173 | void *board_fdt_blob_setup(void); |
| 1198 | 1174 | ||
| 1199 | /* | 1175 | /* |
| 1200 | * Decode the size of memory | 1176 | * Decode the size of memory |
| 1201 | * | 1177 | * |
| 1202 | * RAM size is normally set in a /memory node and consists of a list of | 1178 | * RAM size is normally set in a /memory node and consists of a list of |
| 1203 | * (base, size) cells in the 'reg' property. This information is used to | 1179 | * (base, size) cells in the 'reg' property. This information is used to |
| 1204 | * determine the total available memory as well as the address and size | 1180 | * determine the total available memory as well as the address and size |
| 1205 | * of each bank. | 1181 | * of each bank. |
| 1206 | * | 1182 | * |
| 1207 | * Optionally the memory configuration can vary depending on a board id, | 1183 | * Optionally the memory configuration can vary depending on a board id, |
| 1208 | * typically read from strapping resistors or an EEPROM on the board. | 1184 | * typically read from strapping resistors or an EEPROM on the board. |
| 1209 | * | 1185 | * |
| 1210 | * Finally, memory size can be detected (within certain limits) by probing | 1186 | * Finally, memory size can be detected (within certain limits) by probing |
| 1211 | * the available memory. It is safe to do so within the limits provides by | 1187 | * the available memory. It is safe to do so within the limits provides by |
| 1212 | * the board's device tree information. This makes it possible to produce | 1188 | * the board's device tree information. This makes it possible to produce |
| 1213 | * boards with different memory sizes, where the device tree specifies the | 1189 | * boards with different memory sizes, where the device tree specifies the |
| 1214 | * maximum memory configuration, and the smaller memory configuration is | 1190 | * maximum memory configuration, and the smaller memory configuration is |
| 1215 | * probed. | 1191 | * probed. |
| 1216 | * | 1192 | * |
| 1217 | * This function decodes that information, returning the memory base address, | 1193 | * This function decodes that information, returning the memory base address, |
| 1218 | * size and bank information. See the memory.txt binding for full | 1194 | * size and bank information. See the memory.txt binding for full |
| 1219 | * documentation. | 1195 | * documentation. |
| 1220 | * | 1196 | * |
| 1221 | * @param blob Device tree blob | 1197 | * @param blob Device tree blob |
| 1222 | * @param area Name of node to check (NULL means "/memory") | 1198 | * @param area Name of node to check (NULL means "/memory") |
| 1223 | * @param board_id Board ID to look up | 1199 | * @param board_id Board ID to look up |
| 1224 | * @param basep Returns base address of first memory bank (NULL to | 1200 | * @param basep Returns base address of first memory bank (NULL to |
| 1225 | * ignore) | 1201 | * ignore) |
| 1226 | * @param sizep Returns total memory size (NULL to ignore) | 1202 | * @param sizep Returns total memory size (NULL to ignore) |
| 1227 | * @param bd Updated with the memory bank information (NULL to skip) | 1203 | * @param bd Updated with the memory bank information (NULL to skip) |
| 1228 | * @return 0 if OK, -ve on error | 1204 | * @return 0 if OK, -ve on error |
| 1229 | */ | 1205 | */ |
| 1230 | int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, | 1206 | int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, |
| 1231 | phys_addr_t *basep, phys_size_t *sizep, | 1207 | phys_addr_t *basep, phys_size_t *sizep, |
| 1232 | struct bd_info *bd); | 1208 | struct bd_info *bd); |
| 1233 | 1209 | ||
| 1234 | #endif | 1210 | #endif |
| 1235 | 1211 |
lib/fdtdec.c
| 1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2011 The Chromium OS Authors. | 3 | * Copyright (c) 2011 The Chromium OS Authors. |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #ifndef USE_HOSTCC | 6 | #ifndef USE_HOSTCC |
| 7 | #include <common.h> | 7 | #include <common.h> |
| 8 | #include <boot_fit.h> | 8 | #include <boot_fit.h> |
| 9 | #include <dm.h> | 9 | #include <dm.h> |
| 10 | #include <dm/of_extra.h> | 10 | #include <dm/of_extra.h> |
| 11 | #include <errno.h> | 11 | #include <errno.h> |
| 12 | #include <fdtdec.h> | 12 | #include <fdtdec.h> |
| 13 | #include <fdt_support.h> | 13 | #include <fdt_support.h> |
| 14 | #include <mapmem.h> | 14 | #include <mapmem.h> |
| 15 | #include <linux/libfdt.h> | 15 | #include <linux/libfdt.h> |
| 16 | #include <serial.h> | 16 | #include <serial.h> |
| 17 | #include <asm/sections.h> | 17 | #include <asm/sections.h> |
| 18 | #include <linux/ctype.h> | 18 | #include <linux/ctype.h> |
| 19 | #include <linux/lzo.h> | 19 | #include <linux/lzo.h> |
| 20 | 20 | ||
| 21 | DECLARE_GLOBAL_DATA_PTR; | 21 | DECLARE_GLOBAL_DATA_PTR; |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * Here are the type we know about. One day we might allow drivers to | 24 | * Here are the type we know about. One day we might allow drivers to |
| 25 | * register. For now we just put them here. The COMPAT macro allows us to | 25 | * register. For now we just put them here. The COMPAT macro allows us to |
| 26 | * turn this into a sparse list later, and keeps the ID with the name. | 26 | * turn this into a sparse list later, and keeps the ID with the name. |
| 27 | * | 27 | * |
| 28 | * NOTE: This list is basically a TODO list for things that need to be | 28 | * NOTE: This list is basically a TODO list for things that need to be |
| 29 | * converted to driver model. So don't add new things here unless there is a | 29 | * converted to driver model. So don't add new things here unless there is a |
| 30 | * good reason why driver-model conversion is infeasible. Examples include | 30 | * good reason why driver-model conversion is infeasible. Examples include |
| 31 | * things which are used before driver model is available. | 31 | * things which are used before driver model is available. |
| 32 | */ | 32 | */ |
| 33 | #define COMPAT(id, name) name | 33 | #define COMPAT(id, name) name |
| 34 | static const char * const compat_names[COMPAT_COUNT] = { | 34 | static const char * const compat_names[COMPAT_COUNT] = { |
| 35 | COMPAT(UNKNOWN, "<none>"), | 35 | COMPAT(UNKNOWN, "<none>"), |
| 36 | COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), | 36 | COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), |
| 37 | COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), | 37 | COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), |
| 38 | COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), | 38 | COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), |
| 39 | COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"), | 39 | COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"), |
| 40 | COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"), | 40 | COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"), |
| 41 | COMPAT(SMSC_LAN9215, "smsc,lan9215"), | 41 | COMPAT(SMSC_LAN9215, "smsc,lan9215"), |
| 42 | COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), | 42 | COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), |
| 43 | COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), | 43 | COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), |
| 44 | COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), | 44 | COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), |
| 45 | COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), | 45 | COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), |
| 46 | COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), | 46 | COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), |
| 47 | COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), | 47 | COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), |
| 48 | COMPAT(GENERIC_SPI_FLASH, "jedec,spi-nor"), | 48 | COMPAT(GENERIC_SPI_FLASH, "jedec,spi-nor"), |
| 49 | COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), | 49 | COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), |
| 50 | COMPAT(INTEL_MICROCODE, "intel,microcode"), | 50 | COMPAT(INTEL_MICROCODE, "intel,microcode"), |
| 51 | COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"), | 51 | COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"), |
| 52 | COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"), | 52 | COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"), |
| 53 | COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"), | 53 | COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"), |
| 54 | COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"), | 54 | COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"), |
| 55 | COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), | 55 | COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), |
| 56 | COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), | 56 | COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), |
| 57 | COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"), | 57 | COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"), |
| 58 | COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"), | 58 | COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"), |
| 59 | COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"), | 59 | COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"), |
| 60 | COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"), | 60 | COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"), |
| 61 | COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"), | 61 | COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"), |
| 62 | COMPAT(ALTERA_SOCFPGA_LWH2F_BRG, "altr,socfpga-lwhps2fpga-bridge"), | 62 | COMPAT(ALTERA_SOCFPGA_LWH2F_BRG, "altr,socfpga-lwhps2fpga-bridge"), |
| 63 | COMPAT(ALTERA_SOCFPGA_F2H_BRG, "altr,socfpga-fpga2hps-bridge"), | 63 | COMPAT(ALTERA_SOCFPGA_F2H_BRG, "altr,socfpga-fpga2hps-bridge"), |
| 64 | COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"), | 64 | COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"), |
| 65 | COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"), | 65 | COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"), |
| 66 | COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"), | 66 | COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"), |
| 67 | COMPAT(ALTERA_SOCFPGA_FPGA0, "altr,socfpga-a10-fpga-mgr"), | 67 | COMPAT(ALTERA_SOCFPGA_FPGA0, "altr,socfpga-a10-fpga-mgr"), |
| 68 | COMPAT(ALTERA_SOCFPGA_NOC, "altr,socfpga-a10-noc"), | 68 | COMPAT(ALTERA_SOCFPGA_NOC, "altr,socfpga-a10-noc"), |
| 69 | COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init") | 69 | COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init") |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | const char *fdtdec_get_compatible(enum fdt_compat_id id) | 72 | const char *fdtdec_get_compatible(enum fdt_compat_id id) |
| 73 | { | 73 | { |
| 74 | /* We allow reading of the 'unknown' ID for testing purposes */ | 74 | /* We allow reading of the 'unknown' ID for testing purposes */ |
| 75 | assert(id >= 0 && id < COMPAT_COUNT); | 75 | assert(id >= 0 && id < COMPAT_COUNT); |
| 76 | return compat_names[id]; | 76 | return compat_names[id]; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, | 79 | fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, |
| 80 | const char *prop_name, int index, int na, | 80 | const char *prop_name, int index, int na, |
| 81 | int ns, fdt_size_t *sizep, | 81 | int ns, fdt_size_t *sizep, |
| 82 | bool translate) | 82 | bool translate) |
| 83 | { | 83 | { |
| 84 | const fdt32_t *prop, *prop_end; | 84 | const fdt32_t *prop, *prop_end; |
| 85 | const fdt32_t *prop_addr, *prop_size, *prop_after_size; | 85 | const fdt32_t *prop_addr, *prop_size, *prop_after_size; |
| 86 | int len; | 86 | int len; |
| 87 | fdt_addr_t addr; | 87 | fdt_addr_t addr; |
| 88 | 88 | ||
| 89 | debug("%s: %s: ", __func__, prop_name); | 89 | debug("%s: %s: ", __func__, prop_name); |
| 90 | 90 | ||
| 91 | prop = fdt_getprop(blob, node, prop_name, &len); | 91 | prop = fdt_getprop(blob, node, prop_name, &len); |
| 92 | if (!prop) { | 92 | if (!prop) { |
| 93 | debug("(not found)\n"); | 93 | debug("(not found)\n"); |
| 94 | return FDT_ADDR_T_NONE; | 94 | return FDT_ADDR_T_NONE; |
| 95 | } | 95 | } |
| 96 | prop_end = prop + (len / sizeof(*prop)); | 96 | prop_end = prop + (len / sizeof(*prop)); |
| 97 | 97 | ||
| 98 | prop_addr = prop + (index * (na + ns)); | 98 | prop_addr = prop + (index * (na + ns)); |
| 99 | prop_size = prop_addr + na; | 99 | prop_size = prop_addr + na; |
| 100 | prop_after_size = prop_size + ns; | 100 | prop_after_size = prop_size + ns; |
| 101 | if (prop_after_size > prop_end) { | 101 | if (prop_after_size > prop_end) { |
| 102 | debug("(not enough data: expected >= %d cells, got %d cells)\n", | 102 | debug("(not enough data: expected >= %d cells, got %d cells)\n", |
| 103 | (u32)(prop_after_size - prop), ((u32)(prop_end - prop))); | 103 | (u32)(prop_after_size - prop), ((u32)(prop_end - prop))); |
| 104 | return FDT_ADDR_T_NONE; | 104 | return FDT_ADDR_T_NONE; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | #if CONFIG_IS_ENABLED(OF_TRANSLATE) | 107 | #if CONFIG_IS_ENABLED(OF_TRANSLATE) |
| 108 | if (translate) | 108 | if (translate) |
| 109 | addr = fdt_translate_address(blob, node, prop_addr); | 109 | addr = fdt_translate_address(blob, node, prop_addr); |
| 110 | else | 110 | else |
| 111 | #endif | 111 | #endif |
| 112 | addr = fdtdec_get_number(prop_addr, na); | 112 | addr = fdtdec_get_number(prop_addr, na); |
| 113 | 113 | ||
| 114 | if (sizep) { | 114 | if (sizep) { |
| 115 | *sizep = fdtdec_get_number(prop_size, ns); | 115 | *sizep = fdtdec_get_number(prop_size, ns); |
| 116 | debug("addr=%08llx, size=%llx\n", (unsigned long long)addr, | 116 | debug("addr=%08llx, size=%llx\n", (unsigned long long)addr, |
| 117 | (unsigned long long)*sizep); | 117 | (unsigned long long)*sizep); |
| 118 | } else { | 118 | } else { |
| 119 | debug("addr=%08llx\n", (unsigned long long)addr); | 119 | debug("addr=%08llx\n", (unsigned long long)addr); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | return addr; | 122 | return addr; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, | 125 | fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, |
| 126 | int node, const char *prop_name, | 126 | int node, const char *prop_name, |
| 127 | int index, fdt_size_t *sizep, | 127 | int index, fdt_size_t *sizep, |
| 128 | bool translate) | 128 | bool translate) |
| 129 | { | 129 | { |
| 130 | int na, ns; | 130 | int na, ns; |
| 131 | 131 | ||
| 132 | debug("%s: ", __func__); | 132 | debug("%s: ", __func__); |
| 133 | 133 | ||
| 134 | na = fdt_address_cells(blob, parent); | 134 | na = fdt_address_cells(blob, parent); |
| 135 | if (na < 1) { | 135 | if (na < 1) { |
| 136 | debug("(bad #address-cells)\n"); | 136 | debug("(bad #address-cells)\n"); |
| 137 | return FDT_ADDR_T_NONE; | 137 | return FDT_ADDR_T_NONE; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | ns = fdt_size_cells(blob, parent); | 140 | ns = fdt_size_cells(blob, parent); |
| 141 | if (ns < 0) { | 141 | if (ns < 0) { |
| 142 | debug("(bad #size-cells)\n"); | 142 | debug("(bad #size-cells)\n"); |
| 143 | return FDT_ADDR_T_NONE; | 143 | return FDT_ADDR_T_NONE; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | debug("na=%d, ns=%d, ", na, ns); | 146 | debug("na=%d, ns=%d, ", na, ns); |
| 147 | 147 | ||
| 148 | return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na, | 148 | return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na, |
| 149 | ns, sizep, translate); | 149 | ns, sizep, translate); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, | 152 | fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, |
| 153 | const char *prop_name, int index, | 153 | const char *prop_name, int index, |
| 154 | fdt_size_t *sizep, | 154 | fdt_size_t *sizep, |
| 155 | bool translate) | 155 | bool translate) |
| 156 | { | 156 | { |
| 157 | int parent; | 157 | int parent; |
| 158 | 158 | ||
| 159 | debug("%s: ", __func__); | 159 | debug("%s: ", __func__); |
| 160 | 160 | ||
| 161 | parent = fdt_parent_offset(blob, node); | 161 | parent = fdt_parent_offset(blob, node); |
| 162 | if (parent < 0) { | 162 | if (parent < 0) { |
| 163 | debug("(no parent found)\n"); | 163 | debug("(no parent found)\n"); |
| 164 | return FDT_ADDR_T_NONE; | 164 | return FDT_ADDR_T_NONE; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name, | 167 | return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name, |
| 168 | index, sizep, translate); | 168 | index, sizep, translate); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, | 171 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, |
| 172 | const char *prop_name, fdt_size_t *sizep) | 172 | const char *prop_name, fdt_size_t *sizep) |
| 173 | { | 173 | { |
| 174 | int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0; | 174 | int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0; |
| 175 | 175 | ||
| 176 | return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0, | 176 | return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0, |
| 177 | sizeof(fdt_addr_t) / sizeof(fdt32_t), | 177 | sizeof(fdt_addr_t) / sizeof(fdt32_t), |
| 178 | ns, sizep, false); | 178 | ns, sizep, false); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) | 181 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) |
| 182 | { | 182 | { |
| 183 | return fdtdec_get_addr_size(blob, node, prop_name, NULL); | 183 | return fdtdec_get_addr_size(blob, node, prop_name, NULL); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | #if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI) | 186 | #if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI) |
| 187 | int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, | 187 | int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, |
| 188 | const char *prop_name, struct fdt_pci_addr *addr) | 188 | const char *prop_name, struct fdt_pci_addr *addr) |
| 189 | { | 189 | { |
| 190 | const u32 *cell; | 190 | const u32 *cell; |
| 191 | int len; | 191 | int len; |
| 192 | int ret = -ENOENT; | 192 | int ret = -ENOENT; |
| 193 | 193 | ||
| 194 | debug("%s: %s: ", __func__, prop_name); | 194 | debug("%s: %s: ", __func__, prop_name); |
| 195 | 195 | ||
| 196 | /* | 196 | /* |
| 197 | * If we follow the pci bus bindings strictly, we should check | 197 | * If we follow the pci bus bindings strictly, we should check |
| 198 | * the value of the node's parent node's #address-cells and | 198 | * the value of the node's parent node's #address-cells and |
| 199 | * #size-cells. They need to be 3 and 2 accordingly. However, | 199 | * #size-cells. They need to be 3 and 2 accordingly. However, |
| 200 | * for simplicity we skip the check here. | 200 | * for simplicity we skip the check here. |
| 201 | */ | 201 | */ |
| 202 | cell = fdt_getprop(blob, node, prop_name, &len); | 202 | cell = fdt_getprop(blob, node, prop_name, &len); |
| 203 | if (!cell) | 203 | if (!cell) |
| 204 | goto fail; | 204 | goto fail; |
| 205 | 205 | ||
| 206 | if ((len % FDT_PCI_REG_SIZE) == 0) { | 206 | if ((len % FDT_PCI_REG_SIZE) == 0) { |
| 207 | int num = len / FDT_PCI_REG_SIZE; | 207 | int num = len / FDT_PCI_REG_SIZE; |
| 208 | int i; | 208 | int i; |
| 209 | 209 | ||
| 210 | for (i = 0; i < num; i++) { | 210 | for (i = 0; i < num; i++) { |
| 211 | debug("pci address #%d: %08lx %08lx %08lx\n", i, | 211 | debug("pci address #%d: %08lx %08lx %08lx\n", i, |
| 212 | (ulong)fdt32_to_cpu(cell[0]), | 212 | (ulong)fdt32_to_cpu(cell[0]), |
| 213 | (ulong)fdt32_to_cpu(cell[1]), | 213 | (ulong)fdt32_to_cpu(cell[1]), |
| 214 | (ulong)fdt32_to_cpu(cell[2])); | 214 | (ulong)fdt32_to_cpu(cell[2])); |
| 215 | if ((fdt32_to_cpu(*cell) & type) == type) { | 215 | if ((fdt32_to_cpu(*cell) & type) == type) { |
| 216 | addr->phys_hi = fdt32_to_cpu(cell[0]); | 216 | addr->phys_hi = fdt32_to_cpu(cell[0]); |
| 217 | addr->phys_mid = fdt32_to_cpu(cell[1]); | 217 | addr->phys_mid = fdt32_to_cpu(cell[1]); |
| 218 | addr->phys_lo = fdt32_to_cpu(cell[1]); | 218 | addr->phys_lo = fdt32_to_cpu(cell[1]); |
| 219 | break; | 219 | break; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | cell += (FDT_PCI_ADDR_CELLS + | 222 | cell += (FDT_PCI_ADDR_CELLS + |
| 223 | FDT_PCI_SIZE_CELLS); | 223 | FDT_PCI_SIZE_CELLS); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | if (i == num) { | 226 | if (i == num) { |
| 227 | ret = -ENXIO; | 227 | ret = -ENXIO; |
| 228 | goto fail; | 228 | goto fail; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | return 0; | 231 | return 0; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | ret = -EINVAL; | 234 | ret = -EINVAL; |
| 235 | 235 | ||
| 236 | fail: | 236 | fail: |
| 237 | debug("(not found)\n"); | 237 | debug("(not found)\n"); |
| 238 | return ret; | 238 | return ret; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device) | 241 | int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device) |
| 242 | { | 242 | { |
| 243 | const char *list, *end; | 243 | const char *list, *end; |
| 244 | int len; | 244 | int len; |
| 245 | 245 | ||
| 246 | list = fdt_getprop(blob, node, "compatible", &len); | 246 | list = fdt_getprop(blob, node, "compatible", &len); |
| 247 | if (!list) | 247 | if (!list) |
| 248 | return -ENOENT; | 248 | return -ENOENT; |
| 249 | 249 | ||
| 250 | end = list + len; | 250 | end = list + len; |
| 251 | while (list < end) { | 251 | while (list < end) { |
| 252 | len = strlen(list); | 252 | len = strlen(list); |
| 253 | if (len >= strlen("pciVVVV,DDDD")) { | 253 | if (len >= strlen("pciVVVV,DDDD")) { |
| 254 | char *s = strstr(list, "pci"); | 254 | char *s = strstr(list, "pci"); |
| 255 | 255 | ||
| 256 | /* | 256 | /* |
| 257 | * check if the string is something like pciVVVV,DDDD.RR | 257 | * check if the string is something like pciVVVV,DDDD.RR |
| 258 | * or just pciVVVV,DDDD | 258 | * or just pciVVVV,DDDD |
| 259 | */ | 259 | */ |
| 260 | if (s && s[7] == ',' && | 260 | if (s && s[7] == ',' && |
| 261 | (s[12] == '.' || s[12] == 0)) { | 261 | (s[12] == '.' || s[12] == 0)) { |
| 262 | s += 3; | 262 | s += 3; |
| 263 | *vendor = simple_strtol(s, NULL, 16); | 263 | *vendor = simple_strtol(s, NULL, 16); |
| 264 | 264 | ||
| 265 | s += 5; | 265 | s += 5; |
| 266 | *device = simple_strtol(s, NULL, 16); | 266 | *device = simple_strtol(s, NULL, 16); |
| 267 | 267 | ||
| 268 | return 0; | 268 | return 0; |
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | list += (len + 1); | 271 | list += (len + 1); |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | return -ENOENT; | 274 | return -ENOENT; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, | 277 | int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, |
| 278 | u32 *bar) | 278 | u32 *bar) |
| 279 | { | 279 | { |
| 280 | int barnum; | 280 | int barnum; |
| 281 | 281 | ||
| 282 | /* extract the bar number from fdt_pci_addr */ | 282 | /* extract the bar number from fdt_pci_addr */ |
| 283 | barnum = addr->phys_hi & 0xff; | 283 | barnum = addr->phys_hi & 0xff; |
| 284 | if (barnum < PCI_BASE_ADDRESS_0 || barnum > PCI_CARDBUS_CIS) | 284 | if (barnum < PCI_BASE_ADDRESS_0 || barnum > PCI_CARDBUS_CIS) |
| 285 | return -EINVAL; | 285 | return -EINVAL; |
| 286 | 286 | ||
| 287 | barnum = (barnum - PCI_BASE_ADDRESS_0) / 4; | 287 | barnum = (barnum - PCI_BASE_ADDRESS_0) / 4; |
| 288 | *bar = dm_pci_read_bar32(dev, barnum); | 288 | *bar = dm_pci_read_bar32(dev, barnum); |
| 289 | 289 | ||
| 290 | return 0; | 290 | return 0; |
| 291 | } | 291 | } |
| 292 | #endif | 292 | #endif |
| 293 | 293 | ||
| 294 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, | 294 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, |
| 295 | uint64_t default_val) | 295 | uint64_t default_val) |
| 296 | { | 296 | { |
| 297 | const uint64_t *cell64; | 297 | const uint64_t *cell64; |
| 298 | int length; | 298 | int length; |
| 299 | 299 | ||
| 300 | cell64 = fdt_getprop(blob, node, prop_name, &length); | 300 | cell64 = fdt_getprop(blob, node, prop_name, &length); |
| 301 | if (!cell64 || length < sizeof(*cell64)) | 301 | if (!cell64 || length < sizeof(*cell64)) |
| 302 | return default_val; | 302 | return default_val; |
| 303 | 303 | ||
| 304 | return fdt64_to_cpu(*cell64); | 304 | return fdt64_to_cpu(*cell64); |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | int fdtdec_get_is_enabled(const void *blob, int node) | 307 | int fdtdec_get_is_enabled(const void *blob, int node) |
| 308 | { | 308 | { |
| 309 | const char *cell; | 309 | const char *cell; |
| 310 | 310 | ||
| 311 | /* | 311 | /* |
| 312 | * It should say "okay", so only allow that. Some fdts use "ok" but | 312 | * It should say "okay", so only allow that. Some fdts use "ok" but |
| 313 | * this is a bug. Please fix your device tree source file. See here | 313 | * this is a bug. Please fix your device tree source file. See here |
| 314 | * for discussion: | 314 | * for discussion: |
| 315 | * | 315 | * |
| 316 | * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html | 316 | * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html |
| 317 | */ | 317 | */ |
| 318 | cell = fdt_getprop(blob, node, "status", NULL); | 318 | cell = fdt_getprop(blob, node, "status", NULL); |
| 319 | if (cell) | 319 | if (cell) |
| 320 | return strcmp(cell, "okay") == 0; | 320 | return strcmp(cell, "okay") == 0; |
| 321 | return 1; | 321 | return 1; |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node) | 324 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node) |
| 325 | { | 325 | { |
| 326 | enum fdt_compat_id id; | 326 | enum fdt_compat_id id; |
| 327 | 327 | ||
| 328 | /* Search our drivers */ | 328 | /* Search our drivers */ |
| 329 | for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) | 329 | for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) |
| 330 | if (fdt_node_check_compatible(blob, node, | 330 | if (fdt_node_check_compatible(blob, node, |
| 331 | compat_names[id]) == 0) | 331 | compat_names[id]) == 0) |
| 332 | return id; | 332 | return id; |
| 333 | return COMPAT_UNKNOWN; | 333 | return COMPAT_UNKNOWN; |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | int fdtdec_next_compatible(const void *blob, int node, enum fdt_compat_id id) | 336 | int fdtdec_next_compatible(const void *blob, int node, enum fdt_compat_id id) |
| 337 | { | 337 | { |
| 338 | return fdt_node_offset_by_compatible(blob, node, compat_names[id]); | 338 | return fdt_node_offset_by_compatible(blob, node, compat_names[id]); |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | int fdtdec_next_compatible_subnode(const void *blob, int node, | 341 | int fdtdec_next_compatible_subnode(const void *blob, int node, |
| 342 | enum fdt_compat_id id, int *depthp) | 342 | enum fdt_compat_id id, int *depthp) |
| 343 | { | 343 | { |
| 344 | do { | 344 | do { |
| 345 | node = fdt_next_node(blob, node, depthp); | 345 | node = fdt_next_node(blob, node, depthp); |
| 346 | } while (*depthp > 1); | 346 | } while (*depthp > 1); |
| 347 | 347 | ||
| 348 | /* If this is a direct subnode, and compatible, return it */ | 348 | /* If this is a direct subnode, and compatible, return it */ |
| 349 | if (*depthp == 1 && 0 == fdt_node_check_compatible( | 349 | if (*depthp == 1 && 0 == fdt_node_check_compatible( |
| 350 | blob, node, compat_names[id])) | 350 | blob, node, compat_names[id])) |
| 351 | return node; | 351 | return node; |
| 352 | 352 | ||
| 353 | return -FDT_ERR_NOTFOUND; | 353 | return -FDT_ERR_NOTFOUND; |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id, | 356 | int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id, |
| 357 | int *upto) | 357 | int *upto) |
| 358 | { | 358 | { |
| 359 | #define MAX_STR_LEN 20 | 359 | #define MAX_STR_LEN 20 |
| 360 | char str[MAX_STR_LEN + 20]; | 360 | char str[MAX_STR_LEN + 20]; |
| 361 | int node, err; | 361 | int node, err; |
| 362 | 362 | ||
| 363 | /* snprintf() is not available */ | 363 | /* snprintf() is not available */ |
| 364 | assert(strlen(name) < MAX_STR_LEN); | 364 | assert(strlen(name) < MAX_STR_LEN); |
| 365 | sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); | 365 | sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); |
| 366 | node = fdt_path_offset(blob, str); | 366 | node = fdt_path_offset(blob, str); |
| 367 | if (node < 0) | 367 | if (node < 0) |
| 368 | return node; | 368 | return node; |
| 369 | err = fdt_node_check_compatible(blob, node, compat_names[id]); | 369 | err = fdt_node_check_compatible(blob, node, compat_names[id]); |
| 370 | if (err < 0) | 370 | if (err < 0) |
| 371 | return err; | 371 | return err; |
| 372 | if (err) | 372 | if (err) |
| 373 | return -FDT_ERR_NOTFOUND; | 373 | return -FDT_ERR_NOTFOUND; |
| 374 | (*upto)++; | 374 | (*upto)++; |
| 375 | return node; | 375 | return node; |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, | 378 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, |
| 379 | enum fdt_compat_id id, int *node_list, | 379 | enum fdt_compat_id id, int *node_list, |
| 380 | int maxcount) | 380 | int maxcount) |
| 381 | { | 381 | { |
| 382 | memset(node_list, '\0', sizeof(*node_list) * maxcount); | 382 | memset(node_list, '\0', sizeof(*node_list) * maxcount); |
| 383 | 383 | ||
| 384 | return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount); | 384 | return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount); |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | /* TODO: Can we tighten this code up a little? */ | 387 | /* TODO: Can we tighten this code up a little? */ |
| 388 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, | 388 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, |
| 389 | enum fdt_compat_id id, int *node_list, | 389 | enum fdt_compat_id id, int *node_list, |
| 390 | int maxcount) | 390 | int maxcount) |
| 391 | { | 391 | { |
| 392 | int name_len = strlen(name); | 392 | int name_len = strlen(name); |
| 393 | int nodes[maxcount]; | 393 | int nodes[maxcount]; |
| 394 | int num_found = 0; | 394 | int num_found = 0; |
| 395 | int offset, node; | 395 | int offset, node; |
| 396 | int alias_node; | 396 | int alias_node; |
| 397 | int count; | 397 | int count; |
| 398 | int i, j; | 398 | int i, j; |
| 399 | 399 | ||
| 400 | /* find the alias node if present */ | 400 | /* find the alias node if present */ |
| 401 | alias_node = fdt_path_offset(blob, "/aliases"); | 401 | alias_node = fdt_path_offset(blob, "/aliases"); |
| 402 | 402 | ||
| 403 | /* | 403 | /* |
| 404 | * start with nothing, and we can assume that the root node can't | 404 | * start with nothing, and we can assume that the root node can't |
| 405 | * match | 405 | * match |
| 406 | */ | 406 | */ |
| 407 | memset(nodes, '\0', sizeof(nodes)); | 407 | memset(nodes, '\0', sizeof(nodes)); |
| 408 | 408 | ||
| 409 | /* First find all the compatible nodes */ | 409 | /* First find all the compatible nodes */ |
| 410 | for (node = count = 0; node >= 0 && count < maxcount;) { | 410 | for (node = count = 0; node >= 0 && count < maxcount;) { |
| 411 | node = fdtdec_next_compatible(blob, node, id); | 411 | node = fdtdec_next_compatible(blob, node, id); |
| 412 | if (node >= 0) | 412 | if (node >= 0) |
| 413 | nodes[count++] = node; | 413 | nodes[count++] = node; |
| 414 | } | 414 | } |
| 415 | if (node >= 0) | 415 | if (node >= 0) |
| 416 | debug("%s: warning: maxcount exceeded with alias '%s'\n", | 416 | debug("%s: warning: maxcount exceeded with alias '%s'\n", |
| 417 | __func__, name); | 417 | __func__, name); |
| 418 | 418 | ||
| 419 | /* Now find all the aliases */ | 419 | /* Now find all the aliases */ |
| 420 | for (offset = fdt_first_property_offset(blob, alias_node); | 420 | for (offset = fdt_first_property_offset(blob, alias_node); |
| 421 | offset > 0; | 421 | offset > 0; |
| 422 | offset = fdt_next_property_offset(blob, offset)) { | 422 | offset = fdt_next_property_offset(blob, offset)) { |
| 423 | const struct fdt_property *prop; | 423 | const struct fdt_property *prop; |
| 424 | const char *path; | 424 | const char *path; |
| 425 | int number; | 425 | int number; |
| 426 | int found; | 426 | int found; |
| 427 | 427 | ||
| 428 | node = 0; | 428 | node = 0; |
| 429 | prop = fdt_get_property_by_offset(blob, offset, NULL); | 429 | prop = fdt_get_property_by_offset(blob, offset, NULL); |
| 430 | path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); | 430 | path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); |
| 431 | if (prop->len && 0 == strncmp(path, name, name_len)) | 431 | if (prop->len && 0 == strncmp(path, name, name_len)) |
| 432 | node = fdt_path_offset(blob, prop->data); | 432 | node = fdt_path_offset(blob, prop->data); |
| 433 | if (node <= 0) | 433 | if (node <= 0) |
| 434 | continue; | 434 | continue; |
| 435 | 435 | ||
| 436 | /* Get the alias number */ | 436 | /* Get the alias number */ |
| 437 | number = simple_strtoul(path + name_len, NULL, 10); | 437 | number = simple_strtoul(path + name_len, NULL, 10); |
| 438 | if (number < 0 || number >= maxcount) { | 438 | if (number < 0 || number >= maxcount) { |
| 439 | debug("%s: warning: alias '%s' is out of range\n", | 439 | debug("%s: warning: alias '%s' is out of range\n", |
| 440 | __func__, path); | 440 | __func__, path); |
| 441 | continue; | 441 | continue; |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | /* Make sure the node we found is actually in our list! */ | 444 | /* Make sure the node we found is actually in our list! */ |
| 445 | found = -1; | 445 | found = -1; |
| 446 | for (j = 0; j < count; j++) | 446 | for (j = 0; j < count; j++) |
| 447 | if (nodes[j] == node) { | 447 | if (nodes[j] == node) { |
| 448 | found = j; | 448 | found = j; |
| 449 | break; | 449 | break; |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | if (found == -1) { | 452 | if (found == -1) { |
| 453 | debug("%s: warning: alias '%s' points to a node " | 453 | debug("%s: warning: alias '%s' points to a node " |
| 454 | "'%s' that is missing or is not compatible " | 454 | "'%s' that is missing or is not compatible " |
| 455 | " with '%s'\n", __func__, path, | 455 | " with '%s'\n", __func__, path, |
| 456 | fdt_get_name(blob, node, NULL), | 456 | fdt_get_name(blob, node, NULL), |
| 457 | compat_names[id]); | 457 | compat_names[id]); |
| 458 | continue; | 458 | continue; |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | /* | 461 | /* |
| 462 | * Add this node to our list in the right place, and mark | 462 | * Add this node to our list in the right place, and mark |
| 463 | * it as done. | 463 | * it as done. |
| 464 | */ | 464 | */ |
| 465 | if (fdtdec_get_is_enabled(blob, node)) { | 465 | if (fdtdec_get_is_enabled(blob, node)) { |
| 466 | if (node_list[number]) { | 466 | if (node_list[number]) { |
| 467 | debug("%s: warning: alias '%s' requires that " | 467 | debug("%s: warning: alias '%s' requires that " |
| 468 | "a node be placed in the list in a " | 468 | "a node be placed in the list in a " |
| 469 | "position which is already filled by " | 469 | "position which is already filled by " |
| 470 | "node '%s'\n", __func__, path, | 470 | "node '%s'\n", __func__, path, |
| 471 | fdt_get_name(blob, node, NULL)); | 471 | fdt_get_name(blob, node, NULL)); |
| 472 | continue; | 472 | continue; |
| 473 | } | 473 | } |
| 474 | node_list[number] = node; | 474 | node_list[number] = node; |
| 475 | if (number >= num_found) | 475 | if (number >= num_found) |
| 476 | num_found = number + 1; | 476 | num_found = number + 1; |
| 477 | } | 477 | } |
| 478 | nodes[found] = 0; | 478 | nodes[found] = 0; |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | /* Add any nodes not mentioned by an alias */ | 481 | /* Add any nodes not mentioned by an alias */ |
| 482 | for (i = j = 0; i < maxcount; i++) { | 482 | for (i = j = 0; i < maxcount; i++) { |
| 483 | if (!node_list[i]) { | 483 | if (!node_list[i]) { |
| 484 | for (; j < maxcount; j++) | 484 | for (; j < maxcount; j++) |
| 485 | if (nodes[j] && | 485 | if (nodes[j] && |
| 486 | fdtdec_get_is_enabled(blob, nodes[j])) | 486 | fdtdec_get_is_enabled(blob, nodes[j])) |
| 487 | break; | 487 | break; |
| 488 | 488 | ||
| 489 | /* Have we run out of nodes to add? */ | 489 | /* Have we run out of nodes to add? */ |
| 490 | if (j == maxcount) | 490 | if (j == maxcount) |
| 491 | break; | 491 | break; |
| 492 | 492 | ||
| 493 | assert(!node_list[i]); | 493 | assert(!node_list[i]); |
| 494 | node_list[i] = nodes[j++]; | 494 | node_list[i] = nodes[j++]; |
| 495 | if (i >= num_found) | 495 | if (i >= num_found) |
| 496 | num_found = i + 1; | 496 | num_found = i + 1; |
| 497 | } | 497 | } |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | return num_found; | 500 | return num_found; |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | int fdtdec_get_alias_seq(const void *blob, const char *base, int offset, | 503 | int fdtdec_get_alias_seq(const void *blob, const char *base, int offset, |
| 504 | int *seqp) | 504 | int *seqp) |
| 505 | { | 505 | { |
| 506 | int base_len = strlen(base); | 506 | int base_len = strlen(base); |
| 507 | const char *find_name; | 507 | const char *find_name; |
| 508 | int find_namelen; | 508 | int find_namelen; |
| 509 | int prop_offset; | 509 | int prop_offset; |
| 510 | int aliases; | 510 | int aliases; |
| 511 | 511 | ||
| 512 | find_name = fdt_get_name(blob, offset, &find_namelen); | 512 | find_name = fdt_get_name(blob, offset, &find_namelen); |
| 513 | debug("Looking for '%s' at %d, name %s\n", base, offset, find_name); | 513 | debug("Looking for '%s' at %d, name %s\n", base, offset, find_name); |
| 514 | 514 | ||
| 515 | aliases = fdt_path_offset(blob, "/aliases"); | 515 | aliases = fdt_path_offset(blob, "/aliases"); |
| 516 | for (prop_offset = fdt_first_property_offset(blob, aliases); | 516 | for (prop_offset = fdt_first_property_offset(blob, aliases); |
| 517 | prop_offset > 0; | 517 | prop_offset > 0; |
| 518 | prop_offset = fdt_next_property_offset(blob, prop_offset)) { | 518 | prop_offset = fdt_next_property_offset(blob, prop_offset)) { |
| 519 | const char *prop; | 519 | const char *prop; |
| 520 | const char *name; | 520 | const char *name; |
| 521 | const char *slash; | 521 | const char *slash; |
| 522 | int len, val; | 522 | int len, val; |
| 523 | 523 | ||
| 524 | prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); | 524 | prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); |
| 525 | debug(" - %s, %s\n", name, prop); | 525 | debug(" - %s, %s\n", name, prop); |
| 526 | if (len < find_namelen || *prop != '/' || prop[len - 1] || | 526 | if (len < find_namelen || *prop != '/' || prop[len - 1] || |
| 527 | strncmp(name, base, base_len)) | 527 | strncmp(name, base, base_len)) |
| 528 | continue; | 528 | continue; |
| 529 | 529 | ||
| 530 | slash = strrchr(prop, '/'); | 530 | slash = strrchr(prop, '/'); |
| 531 | if (strcmp(slash + 1, find_name)) | 531 | if (strcmp(slash + 1, find_name)) |
| 532 | continue; | 532 | continue; |
| 533 | val = trailing_strtol(name); | 533 | val = trailing_strtol(name); |
| 534 | if (val != -1) { | 534 | if (val != -1) { |
| 535 | *seqp = val; | 535 | *seqp = val; |
| 536 | debug("Found seq %d\n", *seqp); | 536 | debug("Found seq %d\n", *seqp); |
| 537 | return 0; | 537 | return 0; |
| 538 | } | 538 | } |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | debug("Not found\n"); | 541 | debug("Not found\n"); |
| 542 | return -ENOENT; | 542 | return -ENOENT; |
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | int fdtdec_get_alias_highest_id(const void *blob, const char *base) | 545 | int fdtdec_get_alias_highest_id(const void *blob, const char *base) |
| 546 | { | 546 | { |
| 547 | int base_len = strlen(base); | 547 | int base_len = strlen(base); |
| 548 | int prop_offset; | 548 | int prop_offset; |
| 549 | int aliases; | 549 | int aliases; |
| 550 | int max = -1; | 550 | int max = -1; |
| 551 | 551 | ||
| 552 | debug("Looking for highest alias id for '%s'\n", base); | 552 | debug("Looking for highest alias id for '%s'\n", base); |
| 553 | 553 | ||
| 554 | aliases = fdt_path_offset(blob, "/aliases"); | 554 | aliases = fdt_path_offset(blob, "/aliases"); |
| 555 | for (prop_offset = fdt_first_property_offset(blob, aliases); | 555 | for (prop_offset = fdt_first_property_offset(blob, aliases); |
| 556 | prop_offset > 0; | 556 | prop_offset > 0; |
| 557 | prop_offset = fdt_next_property_offset(blob, prop_offset)) { | 557 | prop_offset = fdt_next_property_offset(blob, prop_offset)) { |
| 558 | const char *prop; | 558 | const char *prop; |
| 559 | const char *name; | 559 | const char *name; |
| 560 | int len, val; | 560 | int len, val; |
| 561 | 561 | ||
| 562 | prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); | 562 | prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); |
| 563 | debug(" - %s, %s\n", name, prop); | 563 | debug(" - %s, %s\n", name, prop); |
| 564 | if (*prop != '/' || prop[len - 1] || | 564 | if (*prop != '/' || prop[len - 1] || |
| 565 | strncmp(name, base, base_len)) | 565 | strncmp(name, base, base_len)) |
| 566 | continue; | 566 | continue; |
| 567 | 567 | ||
| 568 | val = trailing_strtol(name); | 568 | val = trailing_strtol(name); |
| 569 | if (val > max) { | 569 | if (val > max) { |
| 570 | debug("Found seq %d\n", val); | 570 | debug("Found seq %d\n", val); |
| 571 | max = val; | 571 | max = val; |
| 572 | } | 572 | } |
| 573 | } | 573 | } |
| 574 | 574 | ||
| 575 | return max; | 575 | return max; |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | const char *fdtdec_get_chosen_prop(const void *blob, const char *name) | 578 | const char *fdtdec_get_chosen_prop(const void *blob, const char *name) |
| 579 | { | 579 | { |
| 580 | int chosen_node; | 580 | int chosen_node; |
| 581 | 581 | ||
| 582 | if (!blob) | 582 | if (!blob) |
| 583 | return NULL; | 583 | return NULL; |
| 584 | chosen_node = fdt_path_offset(blob, "/chosen"); | 584 | chosen_node = fdt_path_offset(blob, "/chosen"); |
| 585 | return fdt_getprop(blob, chosen_node, name, NULL); | 585 | return fdt_getprop(blob, chosen_node, name, NULL); |
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | int fdtdec_get_chosen_node(const void *blob, const char *name) | 588 | int fdtdec_get_chosen_node(const void *blob, const char *name) |
| 589 | { | 589 | { |
| 590 | const char *prop; | 590 | const char *prop; |
| 591 | 591 | ||
| 592 | prop = fdtdec_get_chosen_prop(blob, name); | 592 | prop = fdtdec_get_chosen_prop(blob, name); |
| 593 | if (!prop) | 593 | if (!prop) |
| 594 | return -FDT_ERR_NOTFOUND; | 594 | return -FDT_ERR_NOTFOUND; |
| 595 | return fdt_path_offset(blob, prop); | 595 | return fdt_path_offset(blob, prop); |
| 596 | } | 596 | } |
| 597 | 597 | ||
| 598 | int fdtdec_check_fdt(void) | 598 | int fdtdec_check_fdt(void) |
| 599 | { | 599 | { |
| 600 | /* | 600 | /* |
| 601 | * We must have an FDT, but we cannot panic() yet since the console | 601 | * We must have an FDT, but we cannot panic() yet since the console |
| 602 | * is not ready. So for now, just assert(). Boards which need an early | 602 | * is not ready. So for now, just assert(). Boards which need an early |
| 603 | * FDT (prior to console ready) will need to make their own | 603 | * FDT (prior to console ready) will need to make their own |
| 604 | * arrangements and do their own checks. | 604 | * arrangements and do their own checks. |
| 605 | */ | 605 | */ |
| 606 | assert(!fdtdec_prepare_fdt()); | 606 | assert(!fdtdec_prepare_fdt()); |
| 607 | return 0; | 607 | return 0; |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | /* | 610 | /* |
| 611 | * This function is a little odd in that it accesses global data. At some | 611 | * This function is a little odd in that it accesses global data. At some |
| 612 | * point if the architecture board.c files merge this will make more sense. | 612 | * point if the architecture board.c files merge this will make more sense. |
| 613 | * Even now, it is common code. | 613 | * Even now, it is common code. |
| 614 | */ | 614 | */ |
| 615 | int fdtdec_prepare_fdt(void) | 615 | int fdtdec_prepare_fdt(void) |
| 616 | { | 616 | { |
| 617 | if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || | 617 | if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || |
| 618 | fdt_check_header(gd->fdt_blob)) { | 618 | fdt_check_header(gd->fdt_blob)) { |
| 619 | #ifdef CONFIG_SPL_BUILD | 619 | #ifdef CONFIG_SPL_BUILD |
| 620 | puts("Missing DTB\n"); | 620 | puts("Missing DTB\n"); |
| 621 | #else | 621 | #else |
| 622 | puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); | 622 | puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); |
| 623 | # ifdef DEBUG | 623 | # ifdef DEBUG |
| 624 | if (gd->fdt_blob) { | 624 | if (gd->fdt_blob) { |
| 625 | printf("fdt_blob=%p\n", gd->fdt_blob); | 625 | printf("fdt_blob=%p\n", gd->fdt_blob); |
| 626 | print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4, | 626 | print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4, |
| 627 | 32, 0); | 627 | 32, 0); |
| 628 | } | 628 | } |
| 629 | # endif | 629 | # endif |
| 630 | #endif | 630 | #endif |
| 631 | return -1; | 631 | return -1; |
| 632 | } | 632 | } |
| 633 | return 0; | 633 | return 0; |
| 634 | } | 634 | } |
| 635 | 635 | ||
| 636 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) | 636 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) |
| 637 | { | 637 | { |
| 638 | const u32 *phandle; | 638 | const u32 *phandle; |
| 639 | int lookup; | 639 | int lookup; |
| 640 | 640 | ||
| 641 | debug("%s: %s\n", __func__, prop_name); | 641 | debug("%s: %s\n", __func__, prop_name); |
| 642 | phandle = fdt_getprop(blob, node, prop_name, NULL); | 642 | phandle = fdt_getprop(blob, node, prop_name, NULL); |
| 643 | if (!phandle) | 643 | if (!phandle) |
| 644 | return -FDT_ERR_NOTFOUND; | 644 | return -FDT_ERR_NOTFOUND; |
| 645 | 645 | ||
| 646 | lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); | 646 | lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); |
| 647 | return lookup; | 647 | return lookup; |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | /** | 650 | /** |
| 651 | * Look up a property in a node and check that it has a minimum length. | 651 | * Look up a property in a node and check that it has a minimum length. |
| 652 | * | 652 | * |
| 653 | * @param blob FDT blob | 653 | * @param blob FDT blob |
| 654 | * @param node node to examine | 654 | * @param node node to examine |
| 655 | * @param prop_name name of property to find | 655 | * @param prop_name name of property to find |
| 656 | * @param min_len minimum property length in bytes | 656 | * @param min_len minimum property length in bytes |
| 657 | * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not | 657 | * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not |
| 658 | found, or -FDT_ERR_BADLAYOUT if not enough data | 658 | found, or -FDT_ERR_BADLAYOUT if not enough data |
| 659 | * @return pointer to cell, which is only valid if err == 0 | 659 | * @return pointer to cell, which is only valid if err == 0 |
| 660 | */ | 660 | */ |
| 661 | static const void *get_prop_check_min_len(const void *blob, int node, | 661 | static const void *get_prop_check_min_len(const void *blob, int node, |
| 662 | const char *prop_name, int min_len, | 662 | const char *prop_name, int min_len, |
| 663 | int *err) | 663 | int *err) |
| 664 | { | 664 | { |
| 665 | const void *cell; | 665 | const void *cell; |
| 666 | int len; | 666 | int len; |
| 667 | 667 | ||
| 668 | debug("%s: %s\n", __func__, prop_name); | 668 | debug("%s: %s\n", __func__, prop_name); |
| 669 | cell = fdt_getprop(blob, node, prop_name, &len); | 669 | cell = fdt_getprop(blob, node, prop_name, &len); |
| 670 | if (!cell) | 670 | if (!cell) |
| 671 | *err = -FDT_ERR_NOTFOUND; | 671 | *err = -FDT_ERR_NOTFOUND; |
| 672 | else if (len < min_len) | 672 | else if (len < min_len) |
| 673 | *err = -FDT_ERR_BADLAYOUT; | 673 | *err = -FDT_ERR_BADLAYOUT; |
| 674 | else | 674 | else |
| 675 | *err = 0; | 675 | *err = 0; |
| 676 | return cell; | 676 | return cell; |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, | 679 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, |
| 680 | u32 *array, int count) | 680 | u32 *array, int count) |
| 681 | { | 681 | { |
| 682 | const u32 *cell; | 682 | const u32 *cell; |
| 683 | int err = 0; | 683 | int err = 0; |
| 684 | 684 | ||
| 685 | debug("%s: %s\n", __func__, prop_name); | 685 | debug("%s: %s\n", __func__, prop_name); |
| 686 | cell = get_prop_check_min_len(blob, node, prop_name, | 686 | cell = get_prop_check_min_len(blob, node, prop_name, |
| 687 | sizeof(u32) * count, &err); | 687 | sizeof(u32) * count, &err); |
| 688 | if (!err) { | 688 | if (!err) { |
| 689 | int i; | 689 | int i; |
| 690 | 690 | ||
| 691 | for (i = 0; i < count; i++) | 691 | for (i = 0; i < count; i++) |
| 692 | array[i] = fdt32_to_cpu(cell[i]); | 692 | array[i] = fdt32_to_cpu(cell[i]); |
| 693 | } | 693 | } |
| 694 | return err; | 694 | return err; |
| 695 | } | 695 | } |
| 696 | 696 | ||
| 697 | int fdtdec_get_int_array_count(const void *blob, int node, | 697 | int fdtdec_get_int_array_count(const void *blob, int node, |
| 698 | const char *prop_name, u32 *array, int count) | 698 | const char *prop_name, u32 *array, int count) |
| 699 | { | 699 | { |
| 700 | const u32 *cell; | 700 | const u32 *cell; |
| 701 | int len, elems; | 701 | int len, elems; |
| 702 | int i; | 702 | int i; |
| 703 | 703 | ||
| 704 | debug("%s: %s\n", __func__, prop_name); | 704 | debug("%s: %s\n", __func__, prop_name); |
| 705 | cell = fdt_getprop(blob, node, prop_name, &len); | 705 | cell = fdt_getprop(blob, node, prop_name, &len); |
| 706 | if (!cell) | 706 | if (!cell) |
| 707 | return -FDT_ERR_NOTFOUND; | 707 | return -FDT_ERR_NOTFOUND; |
| 708 | elems = len / sizeof(u32); | 708 | elems = len / sizeof(u32); |
| 709 | if (count > elems) | 709 | if (count > elems) |
| 710 | count = elems; | 710 | count = elems; |
| 711 | for (i = 0; i < count; i++) | 711 | for (i = 0; i < count; i++) |
| 712 | array[i] = fdt32_to_cpu(cell[i]); | 712 | array[i] = fdt32_to_cpu(cell[i]); |
| 713 | 713 | ||
| 714 | return count; | 714 | return count; |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | const u32 *fdtdec_locate_array(const void *blob, int node, | 717 | const u32 *fdtdec_locate_array(const void *blob, int node, |
| 718 | const char *prop_name, int count) | 718 | const char *prop_name, int count) |
| 719 | { | 719 | { |
| 720 | const u32 *cell; | 720 | const u32 *cell; |
| 721 | int err; | 721 | int err; |
| 722 | 722 | ||
| 723 | cell = get_prop_check_min_len(blob, node, prop_name, | 723 | cell = get_prop_check_min_len(blob, node, prop_name, |
| 724 | sizeof(u32) * count, &err); | 724 | sizeof(u32) * count, &err); |
| 725 | return err ? NULL : cell; | 725 | return err ? NULL : cell; |
| 726 | } | 726 | } |
| 727 | 727 | ||
| 728 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name) | 728 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name) |
| 729 | { | 729 | { |
| 730 | const s32 *cell; | 730 | const s32 *cell; |
| 731 | int len; | 731 | int len; |
| 732 | 732 | ||
| 733 | debug("%s: %s\n", __func__, prop_name); | 733 | debug("%s: %s\n", __func__, prop_name); |
| 734 | cell = fdt_getprop(blob, node, prop_name, &len); | 734 | cell = fdt_getprop(blob, node, prop_name, &len); |
| 735 | return cell != NULL; | 735 | return cell != NULL; |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | int fdtdec_parse_phandle_with_args(const void *blob, int src_node, | 738 | int fdtdec_parse_phandle_with_args(const void *blob, int src_node, |
| 739 | const char *list_name, | 739 | const char *list_name, |
| 740 | const char *cells_name, | 740 | const char *cells_name, |
| 741 | int cell_count, int index, | 741 | int cell_count, int index, |
| 742 | struct fdtdec_phandle_args *out_args) | 742 | struct fdtdec_phandle_args *out_args) |
| 743 | { | 743 | { |
| 744 | const __be32 *list, *list_end; | 744 | const __be32 *list, *list_end; |
| 745 | int rc = 0, size, cur_index = 0; | 745 | int rc = 0, size, cur_index = 0; |
| 746 | uint32_t count = 0; | 746 | uint32_t count = 0; |
| 747 | int node = -1; | 747 | int node = -1; |
| 748 | int phandle; | 748 | int phandle; |
| 749 | 749 | ||
| 750 | /* Retrieve the phandle list property */ | 750 | /* Retrieve the phandle list property */ |
| 751 | list = fdt_getprop(blob, src_node, list_name, &size); | 751 | list = fdt_getprop(blob, src_node, list_name, &size); |
| 752 | if (!list) | 752 | if (!list) |
| 753 | return -ENOENT; | 753 | return -ENOENT; |
| 754 | list_end = list + size / sizeof(*list); | 754 | list_end = list + size / sizeof(*list); |
| 755 | 755 | ||
| 756 | /* Loop over the phandles until all the requested entry is found */ | 756 | /* Loop over the phandles until all the requested entry is found */ |
| 757 | while (list < list_end) { | 757 | while (list < list_end) { |
| 758 | rc = -EINVAL; | 758 | rc = -EINVAL; |
| 759 | count = 0; | 759 | count = 0; |
| 760 | 760 | ||
| 761 | /* | 761 | /* |
| 762 | * If phandle is 0, then it is an empty entry with no | 762 | * If phandle is 0, then it is an empty entry with no |
| 763 | * arguments. Skip forward to the next entry. | 763 | * arguments. Skip forward to the next entry. |
| 764 | */ | 764 | */ |
| 765 | phandle = be32_to_cpup(list++); | 765 | phandle = be32_to_cpup(list++); |
| 766 | if (phandle) { | 766 | if (phandle) { |
| 767 | /* | 767 | /* |
| 768 | * Find the provider node and parse the #*-cells | 768 | * Find the provider node and parse the #*-cells |
| 769 | * property to determine the argument length. | 769 | * property to determine the argument length. |
| 770 | * | 770 | * |
| 771 | * This is not needed if the cell count is hard-coded | 771 | * This is not needed if the cell count is hard-coded |
| 772 | * (i.e. cells_name not set, but cell_count is set), | 772 | * (i.e. cells_name not set, but cell_count is set), |
| 773 | * except when we're going to return the found node | 773 | * except when we're going to return the found node |
| 774 | * below. | 774 | * below. |
| 775 | */ | 775 | */ |
| 776 | if (cells_name || cur_index == index) { | 776 | if (cells_name || cur_index == index) { |
| 777 | node = fdt_node_offset_by_phandle(blob, | 777 | node = fdt_node_offset_by_phandle(blob, |
| 778 | phandle); | 778 | phandle); |
| 779 | if (!node) { | 779 | if (!node) { |
| 780 | debug("%s: could not find phandle\n", | 780 | debug("%s: could not find phandle\n", |
| 781 | fdt_get_name(blob, src_node, | 781 | fdt_get_name(blob, src_node, |
| 782 | NULL)); | 782 | NULL)); |
| 783 | goto err; | 783 | goto err; |
| 784 | } | 784 | } |
| 785 | } | 785 | } |
| 786 | 786 | ||
| 787 | if (cells_name) { | 787 | if (cells_name) { |
| 788 | count = fdtdec_get_int(blob, node, cells_name, | 788 | count = fdtdec_get_int(blob, node, cells_name, |
| 789 | -1); | 789 | -1); |
| 790 | if (count == -1) { | 790 | if (count == -1) { |
| 791 | debug("%s: could not get %s for %s\n", | 791 | debug("%s: could not get %s for %s\n", |
| 792 | fdt_get_name(blob, src_node, | 792 | fdt_get_name(blob, src_node, |
| 793 | NULL), | 793 | NULL), |
| 794 | cells_name, | 794 | cells_name, |
| 795 | fdt_get_name(blob, node, | 795 | fdt_get_name(blob, node, |
| 796 | NULL)); | 796 | NULL)); |
| 797 | goto err; | 797 | goto err; |
| 798 | } | 798 | } |
| 799 | } else { | 799 | } else { |
| 800 | count = cell_count; | 800 | count = cell_count; |
| 801 | } | 801 | } |
| 802 | 802 | ||
| 803 | /* | 803 | /* |
| 804 | * Make sure that the arguments actually fit in the | 804 | * Make sure that the arguments actually fit in the |
| 805 | * remaining property data length | 805 | * remaining property data length |
| 806 | */ | 806 | */ |
| 807 | if (list + count > list_end) { | 807 | if (list + count > list_end) { |
| 808 | debug("%s: arguments longer than property\n", | 808 | debug("%s: arguments longer than property\n", |
| 809 | fdt_get_name(blob, src_node, NULL)); | 809 | fdt_get_name(blob, src_node, NULL)); |
| 810 | goto err; | 810 | goto err; |
| 811 | } | 811 | } |
| 812 | } | 812 | } |
| 813 | 813 | ||
| 814 | /* | 814 | /* |
| 815 | * All of the error cases above bail out of the loop, so at | 815 | * All of the error cases above bail out of the loop, so at |
| 816 | * this point, the parsing is successful. If the requested | 816 | * this point, the parsing is successful. If the requested |
| 817 | * index matches, then fill the out_args structure and return, | 817 | * index matches, then fill the out_args structure and return, |
| 818 | * or return -ENOENT for an empty entry. | 818 | * or return -ENOENT for an empty entry. |
| 819 | */ | 819 | */ |
| 820 | rc = -ENOENT; | 820 | rc = -ENOENT; |
| 821 | if (cur_index == index) { | 821 | if (cur_index == index) { |
| 822 | if (!phandle) | 822 | if (!phandle) |
| 823 | goto err; | 823 | goto err; |
| 824 | 824 | ||
| 825 | if (out_args) { | 825 | if (out_args) { |
| 826 | int i; | 826 | int i; |
| 827 | 827 | ||
| 828 | if (count > MAX_PHANDLE_ARGS) { | 828 | if (count > MAX_PHANDLE_ARGS) { |
| 829 | debug("%s: too many arguments %d\n", | 829 | debug("%s: too many arguments %d\n", |
| 830 | fdt_get_name(blob, src_node, | 830 | fdt_get_name(blob, src_node, |
| 831 | NULL), count); | 831 | NULL), count); |
| 832 | count = MAX_PHANDLE_ARGS; | 832 | count = MAX_PHANDLE_ARGS; |
| 833 | } | 833 | } |
| 834 | out_args->node = node; | 834 | out_args->node = node; |
| 835 | out_args->args_count = count; | 835 | out_args->args_count = count; |
| 836 | for (i = 0; i < count; i++) { | 836 | for (i = 0; i < count; i++) { |
| 837 | out_args->args[i] = | 837 | out_args->args[i] = |
| 838 | be32_to_cpup(list++); | 838 | be32_to_cpup(list++); |
| 839 | } | 839 | } |
| 840 | } | 840 | } |
| 841 | 841 | ||
| 842 | /* Found it! return success */ | 842 | /* Found it! return success */ |
| 843 | return 0; | 843 | return 0; |
| 844 | } | 844 | } |
| 845 | 845 | ||
| 846 | node = -1; | 846 | node = -1; |
| 847 | list += count; | 847 | list += count; |
| 848 | cur_index++; | 848 | cur_index++; |
| 849 | } | 849 | } |
| 850 | 850 | ||
| 851 | /* | 851 | /* |
| 852 | * Result will be one of: | 852 | * Result will be one of: |
| 853 | * -ENOENT : index is for empty phandle | 853 | * -ENOENT : index is for empty phandle |
| 854 | * -EINVAL : parsing error on data | 854 | * -EINVAL : parsing error on data |
| 855 | * [1..n] : Number of phandle (count mode; when index = -1) | 855 | * [1..n] : Number of phandle (count mode; when index = -1) |
| 856 | */ | 856 | */ |
| 857 | rc = index < 0 ? cur_index : -ENOENT; | 857 | rc = index < 0 ? cur_index : -ENOENT; |
| 858 | err: | 858 | err: |
| 859 | return rc; | 859 | return rc; |
| 860 | } | 860 | } |
| 861 | 861 | ||
| 862 | int fdtdec_get_child_count(const void *blob, int node) | 862 | int fdtdec_get_child_count(const void *blob, int node) |
| 863 | { | 863 | { |
| 864 | int subnode; | 864 | int subnode; |
| 865 | int num = 0; | 865 | int num = 0; |
| 866 | 866 | ||
| 867 | fdt_for_each_subnode(subnode, blob, node) | 867 | fdt_for_each_subnode(subnode, blob, node) |
| 868 | num++; | 868 | num++; |
| 869 | 869 | ||
| 870 | return num; | 870 | return num; |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, | 873 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, |
| 874 | u8 *array, int count) | 874 | u8 *array, int count) |
| 875 | { | 875 | { |
| 876 | const u8 *cell; | 876 | const u8 *cell; |
| 877 | int err; | 877 | int err; |
| 878 | 878 | ||
| 879 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); | 879 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); |
| 880 | if (!err) | 880 | if (!err) |
| 881 | memcpy(array, cell, count); | 881 | memcpy(array, cell, count); |
| 882 | return err; | 882 | return err; |
| 883 | } | 883 | } |
| 884 | 884 | ||
| 885 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, | 885 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, |
| 886 | const char *prop_name, int count) | 886 | const char *prop_name, int count) |
| 887 | { | 887 | { |
| 888 | const u8 *cell; | 888 | const u8 *cell; |
| 889 | int err; | 889 | int err; |
| 890 | 890 | ||
| 891 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); | 891 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); |
| 892 | if (err) | 892 | if (err) |
| 893 | return NULL; | 893 | return NULL; |
| 894 | return cell; | 894 | return cell; |
| 895 | } | 895 | } |
| 896 | 896 | ||
| 897 | int fdtdec_get_config_int(const void *blob, const char *prop_name, | 897 | int fdtdec_get_config_int(const void *blob, const char *prop_name, |
| 898 | int default_val) | 898 | int default_val) |
| 899 | { | 899 | { |
| 900 | int config_node; | 900 | int config_node; |
| 901 | 901 | ||
| 902 | debug("%s: %s\n", __func__, prop_name); | 902 | debug("%s: %s\n", __func__, prop_name); |
| 903 | config_node = fdt_path_offset(blob, "/config"); | 903 | config_node = fdt_path_offset(blob, "/config"); |
| 904 | if (config_node < 0) | 904 | if (config_node < 0) |
| 905 | return default_val; | 905 | return default_val; |
| 906 | return fdtdec_get_int(blob, config_node, prop_name, default_val); | 906 | return fdtdec_get_int(blob, config_node, prop_name, default_val); |
| 907 | } | 907 | } |
| 908 | 908 | ||
| 909 | int fdtdec_get_config_bool(const void *blob, const char *prop_name) | 909 | int fdtdec_get_config_bool(const void *blob, const char *prop_name) |
| 910 | { | 910 | { |
| 911 | int config_node; | 911 | int config_node; |
| 912 | const void *prop; | 912 | const void *prop; |
| 913 | 913 | ||
| 914 | debug("%s: %s\n", __func__, prop_name); | 914 | debug("%s: %s\n", __func__, prop_name); |
| 915 | config_node = fdt_path_offset(blob, "/config"); | 915 | config_node = fdt_path_offset(blob, "/config"); |
| 916 | if (config_node < 0) | 916 | if (config_node < 0) |
| 917 | return 0; | 917 | return 0; |
| 918 | prop = fdt_get_property(blob, config_node, prop_name, NULL); | 918 | prop = fdt_get_property(blob, config_node, prop_name, NULL); |
| 919 | 919 | ||
| 920 | return prop != NULL; | 920 | return prop != NULL; |
| 921 | } | 921 | } |
| 922 | 922 | ||
| 923 | char *fdtdec_get_config_string(const void *blob, const char *prop_name) | 923 | char *fdtdec_get_config_string(const void *blob, const char *prop_name) |
| 924 | { | 924 | { |
| 925 | const char *nodep; | 925 | const char *nodep; |
| 926 | int nodeoffset; | 926 | int nodeoffset; |
| 927 | int len; | 927 | int len; |
| 928 | 928 | ||
| 929 | debug("%s: %s\n", __func__, prop_name); | 929 | debug("%s: %s\n", __func__, prop_name); |
| 930 | nodeoffset = fdt_path_offset(blob, "/config"); | 930 | nodeoffset = fdt_path_offset(blob, "/config"); |
| 931 | if (nodeoffset < 0) | 931 | if (nodeoffset < 0) |
| 932 | return NULL; | 932 | return NULL; |
| 933 | 933 | ||
| 934 | nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); | 934 | nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); |
| 935 | if (!nodep) | 935 | if (!nodep) |
| 936 | return NULL; | 936 | return NULL; |
| 937 | 937 | ||
| 938 | return (char *)nodep; | 938 | return (char *)nodep; |
| 939 | } | 939 | } |
| 940 | 940 | ||
| 941 | u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells) | 941 | u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells) |
| 942 | { | 942 | { |
| 943 | u64 number = 0; | 943 | u64 number = 0; |
| 944 | 944 | ||
| 945 | while (cells--) | 945 | while (cells--) |
| 946 | number = (number << 32) | fdt32_to_cpu(*ptr++); | 946 | number = (number << 32) | fdt32_to_cpu(*ptr++); |
| 947 | 947 | ||
| 948 | return number; | 948 | return number; |
| 949 | } | 949 | } |
| 950 | 950 | ||
| 951 | int fdt_get_resource(const void *fdt, int node, const char *property, | 951 | int fdt_get_resource(const void *fdt, int node, const char *property, |
| 952 | unsigned int index, struct fdt_resource *res) | 952 | unsigned int index, struct fdt_resource *res) |
| 953 | { | 953 | { |
| 954 | const fdt32_t *ptr, *end; | 954 | const fdt32_t *ptr, *end; |
| 955 | int na, ns, len, parent; | 955 | int na, ns, len, parent; |
| 956 | unsigned int i = 0; | 956 | unsigned int i = 0; |
| 957 | 957 | ||
| 958 | parent = fdt_parent_offset(fdt, node); | 958 | parent = fdt_parent_offset(fdt, node); |
| 959 | if (parent < 0) | 959 | if (parent < 0) |
| 960 | return parent; | 960 | return parent; |
| 961 | 961 | ||
| 962 | na = fdt_address_cells(fdt, parent); | 962 | na = fdt_address_cells(fdt, parent); |
| 963 | ns = fdt_size_cells(fdt, parent); | 963 | ns = fdt_size_cells(fdt, parent); |
| 964 | 964 | ||
| 965 | ptr = fdt_getprop(fdt, node, property, &len); | 965 | ptr = fdt_getprop(fdt, node, property, &len); |
| 966 | if (!ptr) | 966 | if (!ptr) |
| 967 | return len; | 967 | return len; |
| 968 | 968 | ||
| 969 | end = ptr + len / sizeof(*ptr); | 969 | end = ptr + len / sizeof(*ptr); |
| 970 | 970 | ||
| 971 | while (ptr + na + ns <= end) { | 971 | while (ptr + na + ns <= end) { |
| 972 | if (i == index) { | 972 | if (i == index) { |
| 973 | res->start = fdtdec_get_number(ptr, na); | 973 | res->start = fdtdec_get_number(ptr, na); |
| 974 | res->end = res->start; | 974 | res->end = res->start; |
| 975 | res->end += fdtdec_get_number(&ptr[na], ns) - 1; | 975 | res->end += fdtdec_get_number(&ptr[na], ns) - 1; |
| 976 | return 0; | 976 | return 0; |
| 977 | } | 977 | } |
| 978 | 978 | ||
| 979 | ptr += na + ns; | 979 | ptr += na + ns; |
| 980 | i++; | 980 | i++; |
| 981 | } | 981 | } |
| 982 | 982 | ||
| 983 | return -FDT_ERR_NOTFOUND; | 983 | return -FDT_ERR_NOTFOUND; |
| 984 | } | 984 | } |
| 985 | 985 | ||
| 986 | int fdt_get_named_resource(const void *fdt, int node, const char *property, | 986 | int fdt_get_named_resource(const void *fdt, int node, const char *property, |
| 987 | const char *prop_names, const char *name, | 987 | const char *prop_names, const char *name, |
| 988 | struct fdt_resource *res) | 988 | struct fdt_resource *res) |
| 989 | { | 989 | { |
| 990 | int index; | 990 | int index; |
| 991 | 991 | ||
| 992 | index = fdt_stringlist_search(fdt, node, prop_names, name); | 992 | index = fdt_stringlist_search(fdt, node, prop_names, name); |
| 993 | if (index < 0) | 993 | if (index < 0) |
| 994 | return index; | 994 | return index; |
| 995 | 995 | ||
| 996 | return fdt_get_resource(fdt, node, property, index, res); | 996 | return fdt_get_resource(fdt, node, property, index, res); |
| 997 | } | 997 | } |
| 998 | 998 | ||
| 999 | static int decode_timing_property(const void *blob, int node, const char *name, | 999 | static int decode_timing_property(const void *blob, int node, const char *name, |
| 1000 | struct timing_entry *result) | 1000 | struct timing_entry *result) |
| 1001 | { | 1001 | { |
| 1002 | int length, ret = 0; | 1002 | int length, ret = 0; |
| 1003 | const u32 *prop; | 1003 | const u32 *prop; |
| 1004 | 1004 | ||
| 1005 | prop = fdt_getprop(blob, node, name, &length); | 1005 | prop = fdt_getprop(blob, node, name, &length); |
| 1006 | if (!prop) { | 1006 | if (!prop) { |
| 1007 | debug("%s: could not find property %s\n", | 1007 | debug("%s: could not find property %s\n", |
| 1008 | fdt_get_name(blob, node, NULL), name); | 1008 | fdt_get_name(blob, node, NULL), name); |
| 1009 | return length; | 1009 | return length; |
| 1010 | } | 1010 | } |
| 1011 | 1011 | ||
| 1012 | if (length == sizeof(u32)) { | 1012 | if (length == sizeof(u32)) { |
| 1013 | result->typ = fdtdec_get_int(blob, node, name, 0); | 1013 | result->typ = fdtdec_get_int(blob, node, name, 0); |
| 1014 | result->min = result->typ; | 1014 | result->min = result->typ; |
| 1015 | result->max = result->typ; | 1015 | result->max = result->typ; |
| 1016 | } else { | 1016 | } else { |
| 1017 | ret = fdtdec_get_int_array(blob, node, name, &result->min, 3); | 1017 | ret = fdtdec_get_int_array(blob, node, name, &result->min, 3); |
| 1018 | } | 1018 | } |
| 1019 | 1019 | ||
| 1020 | return ret; | 1020 | return ret; |
| 1021 | } | 1021 | } |
| 1022 | 1022 | ||
| 1023 | int fdtdec_decode_display_timing(const void *blob, int parent, int index, | 1023 | int fdtdec_decode_display_timing(const void *blob, int parent, int index, |
| 1024 | struct display_timing *dt) | 1024 | struct display_timing *dt) |
| 1025 | { | 1025 | { |
| 1026 | int i, node, timings_node; | 1026 | int i, node, timings_node; |
| 1027 | u32 val = 0; | 1027 | u32 val = 0; |
| 1028 | int ret = 0; | 1028 | int ret = 0; |
| 1029 | 1029 | ||
| 1030 | timings_node = fdt_subnode_offset(blob, parent, "display-timings"); | 1030 | timings_node = fdt_subnode_offset(blob, parent, "display-timings"); |
| 1031 | if (timings_node < 0) | 1031 | if (timings_node < 0) |
| 1032 | return timings_node; | 1032 | return timings_node; |
| 1033 | 1033 | ||
| 1034 | for (i = 0, node = fdt_first_subnode(blob, timings_node); | 1034 | for (i = 0, node = fdt_first_subnode(blob, timings_node); |
| 1035 | node > 0 && i != index; | 1035 | node > 0 && i != index; |
| 1036 | node = fdt_next_subnode(blob, node)) | 1036 | node = fdt_next_subnode(blob, node)) |
| 1037 | i++; | 1037 | i++; |
| 1038 | 1038 | ||
| 1039 | if (node < 0) | 1039 | if (node < 0) |
| 1040 | return node; | 1040 | return node; |
| 1041 | 1041 | ||
| 1042 | memset(dt, 0, sizeof(*dt)); | 1042 | memset(dt, 0, sizeof(*dt)); |
| 1043 | 1043 | ||
| 1044 | ret |= decode_timing_property(blob, node, "hback-porch", | 1044 | ret |= decode_timing_property(blob, node, "hback-porch", |
| 1045 | &dt->hback_porch); | 1045 | &dt->hback_porch); |
| 1046 | ret |= decode_timing_property(blob, node, "hfront-porch", | 1046 | ret |= decode_timing_property(blob, node, "hfront-porch", |
| 1047 | &dt->hfront_porch); | 1047 | &dt->hfront_porch); |
| 1048 | ret |= decode_timing_property(blob, node, "hactive", &dt->hactive); | 1048 | ret |= decode_timing_property(blob, node, "hactive", &dt->hactive); |
| 1049 | ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len); | 1049 | ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len); |
| 1050 | ret |= decode_timing_property(blob, node, "vback-porch", | 1050 | ret |= decode_timing_property(blob, node, "vback-porch", |
| 1051 | &dt->vback_porch); | 1051 | &dt->vback_porch); |
| 1052 | ret |= decode_timing_property(blob, node, "vfront-porch", | 1052 | ret |= decode_timing_property(blob, node, "vfront-porch", |
| 1053 | &dt->vfront_porch); | 1053 | &dt->vfront_porch); |
| 1054 | ret |= decode_timing_property(blob, node, "vactive", &dt->vactive); | 1054 | ret |= decode_timing_property(blob, node, "vactive", &dt->vactive); |
| 1055 | ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len); | 1055 | ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len); |
| 1056 | ret |= decode_timing_property(blob, node, "clock-frequency", | 1056 | ret |= decode_timing_property(blob, node, "clock-frequency", |
| 1057 | &dt->pixelclock); | 1057 | &dt->pixelclock); |
| 1058 | 1058 | ||
| 1059 | dt->flags = 0; | 1059 | dt->flags = 0; |
| 1060 | val = fdtdec_get_int(blob, node, "vsync-active", -1); | 1060 | val = fdtdec_get_int(blob, node, "vsync-active", -1); |
| 1061 | if (val != -1) { | 1061 | if (val != -1) { |
| 1062 | dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : | 1062 | dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : |
| 1063 | DISPLAY_FLAGS_VSYNC_LOW; | 1063 | DISPLAY_FLAGS_VSYNC_LOW; |
| 1064 | } | 1064 | } |
| 1065 | val = fdtdec_get_int(blob, node, "hsync-active", -1); | 1065 | val = fdtdec_get_int(blob, node, "hsync-active", -1); |
| 1066 | if (val != -1) { | 1066 | if (val != -1) { |
| 1067 | dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : | 1067 | dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : |
| 1068 | DISPLAY_FLAGS_HSYNC_LOW; | 1068 | DISPLAY_FLAGS_HSYNC_LOW; |
| 1069 | } | 1069 | } |
| 1070 | val = fdtdec_get_int(blob, node, "de-active", -1); | 1070 | val = fdtdec_get_int(blob, node, "de-active", -1); |
| 1071 | if (val != -1) { | 1071 | if (val != -1) { |
| 1072 | dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : | 1072 | dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : |
| 1073 | DISPLAY_FLAGS_DE_LOW; | 1073 | DISPLAY_FLAGS_DE_LOW; |
| 1074 | } | 1074 | } |
| 1075 | val = fdtdec_get_int(blob, node, "pixelclk-active", -1); | 1075 | val = fdtdec_get_int(blob, node, "pixelclk-active", -1); |
| 1076 | if (val != -1) { | 1076 | if (val != -1) { |
| 1077 | dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : | 1077 | dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : |
| 1078 | DISPLAY_FLAGS_PIXDATA_NEGEDGE; | 1078 | DISPLAY_FLAGS_PIXDATA_NEGEDGE; |
| 1079 | } | 1079 | } |
| 1080 | 1080 | ||
| 1081 | if (fdtdec_get_bool(blob, node, "interlaced")) | 1081 | if (fdtdec_get_bool(blob, node, "interlaced")) |
| 1082 | dt->flags |= DISPLAY_FLAGS_INTERLACED; | 1082 | dt->flags |= DISPLAY_FLAGS_INTERLACED; |
| 1083 | if (fdtdec_get_bool(blob, node, "doublescan")) | 1083 | if (fdtdec_get_bool(blob, node, "doublescan")) |
| 1084 | dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; | 1084 | dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; |
| 1085 | if (fdtdec_get_bool(blob, node, "doubleclk")) | 1085 | if (fdtdec_get_bool(blob, node, "doubleclk")) |
| 1086 | dt->flags |= DISPLAY_FLAGS_DOUBLECLK; | 1086 | dt->flags |= DISPLAY_FLAGS_DOUBLECLK; |
| 1087 | 1087 | ||
| 1088 | return ret; | 1088 | return ret; |
| 1089 | } | 1089 | } |
| 1090 | 1090 | ||
| 1091 | int fdtdec_setup_mem_size_base_fdt(const void *blob) | 1091 | int fdtdec_setup_mem_size_base_fdt(const void *blob) |
| 1092 | { | 1092 | { |
| 1093 | int ret, mem; | 1093 | int ret, mem; |
| 1094 | struct fdt_resource res; | 1094 | struct fdt_resource res; |
| 1095 | 1095 | ||
| 1096 | mem = fdt_path_offset(blob, "/memory"); | 1096 | mem = fdt_path_offset(blob, "/memory"); |
| 1097 | if (mem < 0) { | 1097 | if (mem < 0) { |
| 1098 | debug("%s: Missing /memory node\n", __func__); | 1098 | debug("%s: Missing /memory node\n", __func__); |
| 1099 | return -EINVAL; | 1099 | return -EINVAL; |
| 1100 | } | 1100 | } |
| 1101 | 1101 | ||
| 1102 | ret = fdt_get_resource(blob, mem, "reg", 0, &res); | 1102 | ret = fdt_get_resource(blob, mem, "reg", 0, &res); |
| 1103 | if (ret != 0) { | 1103 | if (ret != 0) { |
| 1104 | debug("%s: Unable to decode first memory bank\n", __func__); | 1104 | debug("%s: Unable to decode first memory bank\n", __func__); |
| 1105 | return -EINVAL; | 1105 | return -EINVAL; |
| 1106 | } | 1106 | } |
| 1107 | 1107 | ||
| 1108 | gd->ram_size = (phys_size_t)(res.end - res.start + 1); | 1108 | gd->ram_size = (phys_size_t)(res.end - res.start + 1); |
| 1109 | gd->ram_base = (unsigned long)res.start; | 1109 | gd->ram_base = (unsigned long)res.start; |
| 1110 | debug("%s: Initial DRAM size %llx\n", __func__, | 1110 | debug("%s: Initial DRAM size %llx\n", __func__, |
| 1111 | (unsigned long long)gd->ram_size); | 1111 | (unsigned long long)gd->ram_size); |
| 1112 | 1112 | ||
| 1113 | return 0; | 1113 | return 0; |
| 1114 | } | 1114 | } |
| 1115 | 1115 | ||
| 1116 | int fdtdec_setup_mem_size_base(void) | 1116 | int fdtdec_setup_mem_size_base(void) |
| 1117 | { | 1117 | { |
| 1118 | return fdtdec_setup_mem_size_base_fdt(gd->fdt_blob); | 1118 | return fdtdec_setup_mem_size_base_fdt(gd->fdt_blob); |
| 1119 | } | 1119 | } |
| 1120 | 1120 | ||
| 1121 | #if defined(CONFIG_NR_DRAM_BANKS) | 1121 | #if defined(CONFIG_NR_DRAM_BANKS) |
| 1122 | 1122 | ||
| 1123 | static int get_next_memory_node(const void *blob, int mem) | 1123 | static int get_next_memory_node(const void *blob, int mem) |
| 1124 | { | 1124 | { |
| 1125 | do { | 1125 | do { |
| 1126 | mem = fdt_node_offset_by_prop_value(blob, mem, | 1126 | mem = fdt_node_offset_by_prop_value(blob, mem, |
| 1127 | "device_type", "memory", 7); | 1127 | "device_type", "memory", 7); |
| 1128 | } while (!fdtdec_get_is_enabled(blob, mem)); | 1128 | } while (!fdtdec_get_is_enabled(blob, mem)); |
| 1129 | 1129 | ||
| 1130 | return mem; | 1130 | return mem; |
| 1131 | } | 1131 | } |
| 1132 | 1132 | ||
| 1133 | int fdtdec_setup_memory_banksize_fdt(const void *blob) | 1133 | int fdtdec_setup_memory_banksize_fdt(const void *blob) |
| 1134 | { | 1134 | { |
| 1135 | int bank, ret, mem, reg = 0; | 1135 | int bank, ret, mem, reg = 0; |
| 1136 | struct fdt_resource res; | 1136 | struct fdt_resource res; |
| 1137 | 1137 | ||
| 1138 | mem = get_next_memory_node(blob, -1); | 1138 | mem = get_next_memory_node(blob, -1); |
| 1139 | if (mem < 0) { | 1139 | if (mem < 0) { |
| 1140 | debug("%s: Missing /memory node\n", __func__); | 1140 | debug("%s: Missing /memory node\n", __func__); |
| 1141 | return -EINVAL; | 1141 | return -EINVAL; |
| 1142 | } | 1142 | } |
| 1143 | 1143 | ||
| 1144 | for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { | 1144 | for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { |
| 1145 | ret = fdt_get_resource(blob, mem, "reg", reg++, &res); | 1145 | ret = fdt_get_resource(blob, mem, "reg", reg++, &res); |
| 1146 | if (ret == -FDT_ERR_NOTFOUND) { | 1146 | if (ret == -FDT_ERR_NOTFOUND) { |
| 1147 | reg = 0; | 1147 | reg = 0; |
| 1148 | mem = get_next_memory_node(blob, mem); | 1148 | mem = get_next_memory_node(blob, mem); |
| 1149 | if (mem == -FDT_ERR_NOTFOUND) | 1149 | if (mem == -FDT_ERR_NOTFOUND) |
| 1150 | break; | 1150 | break; |
| 1151 | 1151 | ||
| 1152 | ret = fdt_get_resource(blob, mem, "reg", reg++, &res); | 1152 | ret = fdt_get_resource(blob, mem, "reg", reg++, &res); |
| 1153 | if (ret == -FDT_ERR_NOTFOUND) | 1153 | if (ret == -FDT_ERR_NOTFOUND) |
| 1154 | break; | 1154 | break; |
| 1155 | } | 1155 | } |
| 1156 | if (ret != 0) { | 1156 | if (ret != 0) { |
| 1157 | return -EINVAL; | 1157 | return -EINVAL; |
| 1158 | } | 1158 | } |
| 1159 | 1159 | ||
| 1160 | gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; | 1160 | gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; |
| 1161 | gd->bd->bi_dram[bank].size = | 1161 | gd->bd->bi_dram[bank].size = |
| 1162 | (phys_size_t)(res.end - res.start + 1); | 1162 | (phys_size_t)(res.end - res.start + 1); |
| 1163 | 1163 | ||
| 1164 | debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n", | 1164 | debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n", |
| 1165 | __func__, bank, | 1165 | __func__, bank, |
| 1166 | (unsigned long long)gd->bd->bi_dram[bank].start, | 1166 | (unsigned long long)gd->bd->bi_dram[bank].start, |
| 1167 | (unsigned long long)gd->bd->bi_dram[bank].size); | 1167 | (unsigned long long)gd->bd->bi_dram[bank].size); |
| 1168 | } | 1168 | } |
| 1169 | 1169 | ||
| 1170 | return 0; | 1170 | return 0; |
| 1171 | } | 1171 | } |
| 1172 | 1172 | ||
| 1173 | int fdtdec_setup_memory_banksize(void) | 1173 | int fdtdec_setup_memory_banksize(void) |
| 1174 | { | 1174 | { |
| 1175 | return fdtdec_setup_memory_banksize_fdt(gd->fdt_blob); | 1175 | return fdtdec_setup_memory_banksize_fdt(gd->fdt_blob); |
| 1176 | 1176 | ||
| 1177 | } | 1177 | } |
| 1178 | #endif | 1178 | #endif |
| 1179 | 1179 | ||
| 1180 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) | 1180 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) |
| 1181 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ | 1181 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ |
| 1182 | CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) | 1182 | CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) |
| 1183 | static int uncompress_blob(const void *src, ulong sz_src, void **dstp) | 1183 | static int uncompress_blob(const void *src, ulong sz_src, void **dstp) |
| 1184 | { | 1184 | { |
| 1185 | size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ); | 1185 | size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ); |
| 1186 | bool gzip = 0, lzo = 0; | 1186 | bool gzip = 0, lzo = 0; |
| 1187 | ulong sz_in = sz_src; | 1187 | ulong sz_in = sz_src; |
| 1188 | void *dst; | 1188 | void *dst; |
| 1189 | int rc; | 1189 | int rc; |
| 1190 | 1190 | ||
| 1191 | if (CONFIG_IS_ENABLED(GZIP)) | 1191 | if (CONFIG_IS_ENABLED(GZIP)) |
| 1192 | if (gzip_parse_header(src, sz_in) >= 0) | 1192 | if (gzip_parse_header(src, sz_in) >= 0) |
| 1193 | gzip = 1; | 1193 | gzip = 1; |
| 1194 | if (CONFIG_IS_ENABLED(LZO)) | 1194 | if (CONFIG_IS_ENABLED(LZO)) |
| 1195 | if (!gzip && lzop_is_valid_header(src)) | 1195 | if (!gzip && lzop_is_valid_header(src)) |
| 1196 | lzo = 1; | 1196 | lzo = 1; |
| 1197 | 1197 | ||
| 1198 | if (!gzip && !lzo) | 1198 | if (!gzip && !lzo) |
| 1199 | return -EBADMSG; | 1199 | return -EBADMSG; |
| 1200 | 1200 | ||
| 1201 | 1201 | ||
| 1202 | if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) { | 1202 | if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) { |
| 1203 | dst = malloc(sz_out); | 1203 | dst = malloc(sz_out); |
| 1204 | if (!dst) { | 1204 | if (!dst) { |
| 1205 | puts("uncompress_blob: Unable to allocate memory\n"); | 1205 | puts("uncompress_blob: Unable to allocate memory\n"); |
| 1206 | return -ENOMEM; | 1206 | return -ENOMEM; |
| 1207 | } | 1207 | } |
| 1208 | } else { | 1208 | } else { |
| 1209 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) | 1209 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) |
| 1210 | dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); | 1210 | dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); |
| 1211 | # else | 1211 | # else |
| 1212 | return -ENOTSUPP; | 1212 | return -ENOTSUPP; |
| 1213 | # endif | 1213 | # endif |
| 1214 | } | 1214 | } |
| 1215 | 1215 | ||
| 1216 | if (CONFIG_IS_ENABLED(GZIP) && gzip) | 1216 | if (CONFIG_IS_ENABLED(GZIP) && gzip) |
| 1217 | rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); | 1217 | rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); |
| 1218 | else if (CONFIG_IS_ENABLED(LZO) && lzo) | 1218 | else if (CONFIG_IS_ENABLED(LZO) && lzo) |
| 1219 | rc = lzop_decompress(src, sz_in, dst, &sz_out); | 1219 | rc = lzop_decompress(src, sz_in, dst, &sz_out); |
| 1220 | else | 1220 | else |
| 1221 | hang(); | 1221 | hang(); |
| 1222 | 1222 | ||
| 1223 | if (rc < 0) { | 1223 | if (rc < 0) { |
| 1224 | /* not a valid compressed blob */ | 1224 | /* not a valid compressed blob */ |
| 1225 | puts("uncompress_blob: Unable to uncompress\n"); | 1225 | puts("uncompress_blob: Unable to uncompress\n"); |
| 1226 | if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) | 1226 | if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) |
| 1227 | free(dst); | 1227 | free(dst); |
| 1228 | return -EBADMSG; | 1228 | return -EBADMSG; |
| 1229 | } | 1229 | } |
| 1230 | *dstp = dst; | 1230 | *dstp = dst; |
| 1231 | return 0; | 1231 | return 0; |
| 1232 | } | 1232 | } |
| 1233 | # else | 1233 | # else |
| 1234 | static int uncompress_blob(const void *src, ulong sz_src, void **dstp) | 1234 | static int uncompress_blob(const void *src, ulong sz_src, void **dstp) |
| 1235 | { | 1235 | { |
| 1236 | *dstp = (void *)src; | 1236 | *dstp = (void *)src; |
| 1237 | return 0; | 1237 | return 0; |
| 1238 | } | 1238 | } |
| 1239 | # endif | 1239 | # endif |
| 1240 | #endif | 1240 | #endif |
| 1241 | 1241 | ||
| 1242 | #if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) | 1242 | #if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) |
| 1243 | /* | 1243 | /* |
| 1244 | * For CONFIG_OF_SEPARATE, the board may optionally implement this to | 1244 | * For CONFIG_OF_SEPARATE, the board may optionally implement this to |
| 1245 | * provide and/or fixup the fdt. | 1245 | * provide and/or fixup the fdt. |
| 1246 | */ | 1246 | */ |
| 1247 | __weak void *board_fdt_blob_setup(void) | 1247 | __weak void *board_fdt_blob_setup(void) |
| 1248 | { | 1248 | { |
| 1249 | void *fdt_blob = NULL; | 1249 | void *fdt_blob = NULL; |
| 1250 | #ifdef CONFIG_SPL_BUILD | 1250 | #ifdef CONFIG_SPL_BUILD |
| 1251 | /* FDT is at end of BSS unless it is in a different memory region */ | 1251 | /* FDT is at end of BSS unless it is in a different memory region */ |
| 1252 | if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) | 1252 | if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) |
| 1253 | fdt_blob = (ulong *)&_image_binary_end; | 1253 | fdt_blob = (ulong *)&_image_binary_end; |
| 1254 | else | 1254 | else |
| 1255 | fdt_blob = (ulong *)&__bss_end; | 1255 | fdt_blob = (ulong *)&__bss_end; |
| 1256 | #else | 1256 | #else |
| 1257 | /* FDT is at end of image */ | 1257 | /* FDT is at end of image */ |
| 1258 | fdt_blob = (ulong *)&_end; | 1258 | fdt_blob = (ulong *)&_end; |
| 1259 | #endif | 1259 | #endif |
| 1260 | return fdt_blob; | 1260 | return fdt_blob; |
| 1261 | } | 1261 | } |
| 1262 | #endif | 1262 | #endif |
| 1263 | 1263 | ||
| 1264 | static int fdtdec_init_reserved_memory(void *blob) | 1264 | static int fdtdec_init_reserved_memory(void *blob) |
| 1265 | { | 1265 | { |
| 1266 | int na, ns, node, err; | 1266 | int na, ns, node, err; |
| 1267 | fdt32_t value; | 1267 | fdt32_t value; |
| 1268 | 1268 | ||
| 1269 | /* inherit #address-cells and #size-cells from the root node */ | 1269 | /* inherit #address-cells and #size-cells from the root node */ |
| 1270 | na = fdt_address_cells(blob, 0); | 1270 | na = fdt_address_cells(blob, 0); |
| 1271 | ns = fdt_size_cells(blob, 0); | 1271 | ns = fdt_size_cells(blob, 0); |
| 1272 | 1272 | ||
| 1273 | node = fdt_add_subnode(blob, 0, "reserved-memory"); | 1273 | node = fdt_add_subnode(blob, 0, "reserved-memory"); |
| 1274 | if (node < 0) | 1274 | if (node < 0) |
| 1275 | return node; | 1275 | return node; |
| 1276 | 1276 | ||
| 1277 | err = fdt_setprop(blob, node, "ranges", NULL, 0); | 1277 | err = fdt_setprop(blob, node, "ranges", NULL, 0); |
| 1278 | if (err < 0) | 1278 | if (err < 0) |
| 1279 | return err; | 1279 | return err; |
| 1280 | 1280 | ||
| 1281 | value = cpu_to_fdt32(ns); | 1281 | value = cpu_to_fdt32(ns); |
| 1282 | 1282 | ||
| 1283 | err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value)); | 1283 | err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value)); |
| 1284 | if (err < 0) | 1284 | if (err < 0) |
| 1285 | return err; | 1285 | return err; |
| 1286 | 1286 | ||
| 1287 | value = cpu_to_fdt32(na); | 1287 | value = cpu_to_fdt32(na); |
| 1288 | 1288 | ||
| 1289 | err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value)); | 1289 | err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value)); |
| 1290 | if (err < 0) | 1290 | if (err < 0) |
| 1291 | return err; | 1291 | return err; |
| 1292 | 1292 | ||
| 1293 | return node; | 1293 | return node; |
| 1294 | } | 1294 | } |
| 1295 | 1295 | ||
| 1296 | int fdtdec_add_reserved_memory(void *blob, const char *basename, | 1296 | int fdtdec_add_reserved_memory(void *blob, const char *basename, |
| 1297 | const struct fdt_memory *carveout, | 1297 | const struct fdt_memory *carveout, |
| 1298 | uint32_t *phandlep) | 1298 | uint32_t *phandlep) |
| 1299 | { | 1299 | { |
| 1300 | fdt32_t cells[4] = {}, *ptr = cells; | 1300 | fdt32_t cells[4] = {}, *ptr = cells; |
| 1301 | uint32_t upper, lower, phandle; | 1301 | uint32_t upper, lower, phandle; |
| 1302 | int parent, node, na, ns, err; | 1302 | int parent, node, na, ns, err; |
| 1303 | fdt_size_t size; | ||
| 1303 | char name[64]; | 1304 | char name[64]; |
| 1304 | 1305 | ||
| 1305 | /* create an empty /reserved-memory node if one doesn't exist */ | 1306 | /* create an empty /reserved-memory node if one doesn't exist */ |
| 1306 | parent = fdt_path_offset(blob, "/reserved-memory"); | 1307 | parent = fdt_path_offset(blob, "/reserved-memory"); |
| 1307 | if (parent < 0) { | 1308 | if (parent < 0) { |
| 1308 | parent = fdtdec_init_reserved_memory(blob); | 1309 | parent = fdtdec_init_reserved_memory(blob); |
| 1309 | if (parent < 0) | 1310 | if (parent < 0) |
| 1310 | return parent; | 1311 | return parent; |
| 1311 | } | 1312 | } |
| 1312 | 1313 | ||
| 1313 | /* only 1 or 2 #address-cells and #size-cells are supported */ | 1314 | /* only 1 or 2 #address-cells and #size-cells are supported */ |
| 1314 | na = fdt_address_cells(blob, parent); | 1315 | na = fdt_address_cells(blob, parent); |
| 1315 | if (na < 1 || na > 2) | 1316 | if (na < 1 || na > 2) |
| 1316 | return -FDT_ERR_BADNCELLS; | 1317 | return -FDT_ERR_BADNCELLS; |
| 1317 | 1318 | ||
| 1318 | ns = fdt_size_cells(blob, parent); | 1319 | ns = fdt_size_cells(blob, parent); |
| 1319 | if (ns < 1 || ns > 2) | 1320 | if (ns < 1 || ns > 2) |
| 1320 | return -FDT_ERR_BADNCELLS; | 1321 | return -FDT_ERR_BADNCELLS; |
| 1321 | 1322 | ||
| 1322 | /* find a matching node and return the phandle to that */ | 1323 | /* find a matching node and return the phandle to that */ |
| 1323 | fdt_for_each_subnode(node, blob, parent) { | 1324 | fdt_for_each_subnode(node, blob, parent) { |
| 1324 | const char *name = fdt_get_name(blob, node, NULL); | 1325 | const char *name = fdt_get_name(blob, node, NULL); |
| 1325 | phys_addr_t addr, size; | 1326 | phys_addr_t addr, size; |
| 1326 | 1327 | ||
| 1327 | addr = fdtdec_get_addr_size(blob, node, "reg", &size); | 1328 | addr = fdtdec_get_addr_size(blob, node, "reg", &size); |
| 1328 | if (addr == FDT_ADDR_T_NONE) { | 1329 | if (addr == FDT_ADDR_T_NONE) { |
| 1329 | debug("failed to read address/size for %s\n", name); | 1330 | debug("failed to read address/size for %s\n", name); |
| 1330 | continue; | 1331 | continue; |
| 1331 | } | 1332 | } |
| 1332 | 1333 | ||
| 1333 | if (addr == carveout->start && (addr + size) == carveout->end) { | 1334 | if (addr == carveout->start && (addr + size) == carveout->end) { |
| 1334 | *phandlep = fdt_get_phandle(blob, node); | 1335 | *phandlep = fdt_get_phandle(blob, node); |
| 1335 | return 0; | 1336 | return 0; |
| 1336 | } | 1337 | } |
| 1337 | } | 1338 | } |
| 1338 | 1339 | ||
| 1339 | /* | 1340 | /* |
| 1340 | * Unpack the start address and generate the name of the new node | 1341 | * Unpack the start address and generate the name of the new node |
| 1341 | * base on the basename and the unit-address. | 1342 | * base on the basename and the unit-address. |
| 1342 | */ | 1343 | */ |
| 1343 | lower = fdt_addr_unpack(carveout->start, &upper); | 1344 | upper = upper_32_bits(carveout->start); |
| 1345 | lower = lower_32_bits(carveout->start); | ||
| 1344 | 1346 | ||
| 1345 | if (na > 1 && upper > 0) | 1347 | if (na > 1 && upper > 0) |
| 1346 | snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, | 1348 | snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, |
| 1347 | lower); | 1349 | lower); |
| 1348 | else { | 1350 | else { |
| 1349 | if (upper > 0) { | 1351 | if (upper > 0) { |
| 1350 | debug("address %08x:%08x exceeds addressable space\n", | 1352 | debug("address %08x:%08x exceeds addressable space\n", |
| 1351 | upper, lower); | 1353 | upper, lower); |
| 1352 | return -FDT_ERR_BADVALUE; | 1354 | return -FDT_ERR_BADVALUE; |
| 1353 | } | 1355 | } |
| 1354 | 1356 | ||
| 1355 | snprintf(name, sizeof(name), "%s@%x", basename, lower); | 1357 | snprintf(name, sizeof(name), "%s@%x", basename, lower); |
| 1356 | } | 1358 | } |
| 1357 | 1359 | ||
| 1358 | node = fdt_add_subnode(blob, parent, name); | 1360 | node = fdt_add_subnode(blob, parent, name); |
| 1359 | if (node < 0) | 1361 | if (node < 0) |
| 1360 | return node; | 1362 | return node; |
| 1361 | 1363 | ||
| 1362 | err = fdt_generate_phandle(blob, &phandle); | 1364 | err = fdt_generate_phandle(blob, &phandle); |
| 1363 | if (err < 0) | 1365 | if (err < 0) |
| 1364 | return err; | 1366 | return err; |
| 1365 | 1367 | ||
| 1366 | err = fdtdec_set_phandle(blob, node, phandle); | 1368 | err = fdtdec_set_phandle(blob, node, phandle); |
| 1367 | if (err < 0) | 1369 | if (err < 0) |
| 1368 | return err; | 1370 | return err; |
| 1369 | 1371 | ||
| 1370 | /* store one or two address cells */ | 1372 | /* store one or two address cells */ |
| 1371 | if (na > 1) | 1373 | if (na > 1) |
| 1372 | *ptr++ = cpu_to_fdt32(upper); | 1374 | *ptr++ = cpu_to_fdt32(upper); |
| 1373 | 1375 | ||
| 1374 | *ptr++ = cpu_to_fdt32(lower); | 1376 | *ptr++ = cpu_to_fdt32(lower); |
| 1375 | 1377 | ||
| 1376 | /* store one or two size cells */ | 1378 | /* store one or two size cells */ |
| 1377 | lower = fdt_size_unpack(carveout->end - carveout->start + 1, &upper); | 1379 | size = carveout->end - carveout->start + 1; |
| 1380 | upper = upper_32_bits(size); | ||
| 1381 | lower = lower_32_bits(size); | ||
| 1378 | 1382 | ||
| 1379 | if (ns > 1) | 1383 | if (ns > 1) |
| 1380 | *ptr++ = cpu_to_fdt32(upper); | 1384 | *ptr++ = cpu_to_fdt32(upper); |
| 1381 | 1385 | ||
| 1382 | *ptr++ = cpu_to_fdt32(lower); | 1386 | *ptr++ = cpu_to_fdt32(lower); |
| 1383 | 1387 | ||
| 1384 | err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells)); | 1388 | err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells)); |
| 1385 | if (err < 0) | 1389 | if (err < 0) |
| 1386 | return err; | 1390 | return err; |
| 1387 | 1391 | ||
| 1388 | /* return the phandle for the new node for the caller to use */ | 1392 | /* return the phandle for the new node for the caller to use */ |
| 1389 | if (phandlep) | 1393 | if (phandlep) |
| 1390 | *phandlep = phandle; | 1394 | *phandlep = phandle; |
| 1391 | 1395 | ||
| 1392 | return 0; | 1396 | return 0; |
| 1393 | } | 1397 | } |
| 1394 | 1398 | ||
| 1395 | int fdtdec_get_carveout(const void *blob, const char *node, const char *name, | 1399 | int fdtdec_get_carveout(const void *blob, const char *node, const char *name, |
| 1396 | unsigned int index, struct fdt_memory *carveout) | 1400 | unsigned int index, struct fdt_memory *carveout) |
| 1397 | { | 1401 | { |
| 1398 | const fdt32_t *prop; | 1402 | const fdt32_t *prop; |
| 1399 | uint32_t phandle; | 1403 | uint32_t phandle; |
| 1400 | int offset, len; | 1404 | int offset, len; |
| 1401 | fdt_size_t size; | 1405 | fdt_size_t size; |
| 1402 | 1406 | ||
| 1403 | offset = fdt_path_offset(blob, node); | 1407 | offset = fdt_path_offset(blob, node); |
| 1404 | if (offset < 0) | 1408 | if (offset < 0) |
| 1405 | return offset; | 1409 | return offset; |
| 1406 | 1410 | ||
| 1407 | prop = fdt_getprop(blob, offset, name, &len); | 1411 | prop = fdt_getprop(blob, offset, name, &len); |
| 1408 | if (!prop) { | 1412 | if (!prop) { |
| 1409 | debug("failed to get %s for %s\n", name, node); | 1413 | debug("failed to get %s for %s\n", name, node); |
| 1410 | return -FDT_ERR_NOTFOUND; | 1414 | return -FDT_ERR_NOTFOUND; |
| 1411 | } | 1415 | } |
| 1412 | 1416 | ||
| 1413 | if ((len % sizeof(phandle)) != 0) { | 1417 | if ((len % sizeof(phandle)) != 0) { |
| 1414 | debug("invalid phandle property\n"); | 1418 | debug("invalid phandle property\n"); |
| 1415 | return -FDT_ERR_BADPHANDLE; | 1419 | return -FDT_ERR_BADPHANDLE; |
| 1416 | } | 1420 | } |
| 1417 | 1421 | ||
| 1418 | if (len < (sizeof(phandle) * (index + 1))) { | 1422 | if (len < (sizeof(phandle) * (index + 1))) { |
| 1419 | debug("invalid phandle index\n"); | 1423 | debug("invalid phandle index\n"); |
| 1420 | return -FDT_ERR_BADPHANDLE; | 1424 | return -FDT_ERR_BADPHANDLE; |
| 1421 | } | 1425 | } |
| 1422 | 1426 | ||
| 1423 | phandle = fdt32_to_cpu(prop[index]); | 1427 | phandle = fdt32_to_cpu(prop[index]); |
| 1424 | 1428 | ||
| 1425 | offset = fdt_node_offset_by_phandle(blob, phandle); | 1429 | offset = fdt_node_offset_by_phandle(blob, phandle); |
| 1426 | if (offset < 0) { | 1430 | if (offset < 0) { |
| 1427 | debug("failed to find node for phandle %u\n", phandle); | 1431 | debug("failed to find node for phandle %u\n", phandle); |
| 1428 | return offset; | 1432 | return offset; |
| 1429 | } | 1433 | } |
| 1430 | 1434 | ||
| 1431 | carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset, | 1435 | carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset, |
| 1432 | "reg", 0, &size, | 1436 | "reg", 0, &size, |
| 1433 | true); | 1437 | true); |
| 1434 | if (carveout->start == FDT_ADDR_T_NONE) { | 1438 | if (carveout->start == FDT_ADDR_T_NONE) { |
| 1435 | debug("failed to read address/size from \"reg\" property\n"); | 1439 | debug("failed to read address/size from \"reg\" property\n"); |
| 1436 | return -FDT_ERR_NOTFOUND; | 1440 | return -FDT_ERR_NOTFOUND; |
| 1437 | } | 1441 | } |
| 1438 | 1442 | ||
| 1439 | carveout->end = carveout->start + size - 1; | 1443 | carveout->end = carveout->start + size - 1; |
| 1440 | 1444 | ||
| 1441 | return 0; | 1445 | return 0; |
| 1442 | } | 1446 | } |
| 1443 | 1447 | ||
| 1444 | int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, | 1448 | int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, |
| 1445 | unsigned int index, const char *name, | 1449 | unsigned int index, const char *name, |
| 1446 | const struct fdt_memory *carveout) | 1450 | const struct fdt_memory *carveout) |
| 1447 | { | 1451 | { |
| 1448 | uint32_t phandle; | 1452 | uint32_t phandle; |
| 1449 | int err, offset; | 1453 | int err, offset; |
| 1450 | fdt32_t value; | 1454 | fdt32_t value; |
| 1451 | 1455 | ||
| 1452 | /* XXX implement support for multiple phandles */ | 1456 | /* XXX implement support for multiple phandles */ |
| 1453 | if (index > 0) { | 1457 | if (index > 0) { |
| 1454 | debug("invalid index %u\n", index); | 1458 | debug("invalid index %u\n", index); |
| 1455 | return -FDT_ERR_BADOFFSET; | 1459 | return -FDT_ERR_BADOFFSET; |
| 1456 | } | 1460 | } |
| 1457 | 1461 | ||
| 1458 | err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle); | 1462 | err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle); |
| 1459 | if (err < 0) { | 1463 | if (err < 0) { |
| 1460 | debug("failed to add reserved memory: %d\n", err); | 1464 | debug("failed to add reserved memory: %d\n", err); |
| 1461 | return err; | 1465 | return err; |
| 1462 | } | 1466 | } |
| 1463 | 1467 | ||
| 1464 | offset = fdt_path_offset(blob, node); | 1468 | offset = fdt_path_offset(blob, node); |
| 1465 | if (offset < 0) { | 1469 | if (offset < 0) { |
| 1466 | debug("failed to find offset for node %s: %d\n", node, offset); | 1470 | debug("failed to find offset for node %s: %d\n", node, offset); |
| 1467 | return offset; | 1471 | return offset; |
| 1468 | } | 1472 | } |
| 1469 | 1473 | ||
| 1470 | value = cpu_to_fdt32(phandle); | 1474 | value = cpu_to_fdt32(phandle); |
| 1471 | 1475 | ||
| 1472 | err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value)); | 1476 | err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value)); |
| 1473 | if (err < 0) { | 1477 | if (err < 0) { |
| 1474 | debug("failed to set %s property for node %s: %d\n", prop_name, | 1478 | debug("failed to set %s property for node %s: %d\n", prop_name, |
| 1475 | node, err); | 1479 | node, err); |
| 1476 | return err; | 1480 | return err; |
| 1477 | } | 1481 | } |
| 1478 | 1482 | ||
| 1479 | return 0; | 1483 | return 0; |
| 1480 | } | 1484 | } |
| 1481 | 1485 | ||
| 1482 | int fdtdec_setup(void) | 1486 | int fdtdec_setup(void) |
| 1483 | { | 1487 | { |
| 1484 | #if CONFIG_IS_ENABLED(OF_CONTROL) | 1488 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
| 1485 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT) | 1489 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT) |
| 1486 | void *fdt_blob; | 1490 | void *fdt_blob; |
| 1487 | # endif | 1491 | # endif |
| 1488 | # ifdef CONFIG_OF_EMBED | 1492 | # ifdef CONFIG_OF_EMBED |
| 1489 | /* Get a pointer to the FDT */ | 1493 | /* Get a pointer to the FDT */ |
| 1490 | # ifdef CONFIG_SPL_BUILD | 1494 | # ifdef CONFIG_SPL_BUILD |
| 1491 | gd->fdt_blob = __dtb_dt_spl_begin; | 1495 | gd->fdt_blob = __dtb_dt_spl_begin; |
| 1492 | # else | 1496 | # else |
| 1493 | gd->fdt_blob = __dtb_dt_begin; | 1497 | gd->fdt_blob = __dtb_dt_begin; |
| 1494 | # endif | 1498 | # endif |
| 1495 | # elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) | 1499 | # elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) |
| 1496 | /* Allow the board to override the fdt address. */ | 1500 | /* Allow the board to override the fdt address. */ |
| 1497 | gd->fdt_blob = board_fdt_blob_setup(); | 1501 | gd->fdt_blob = board_fdt_blob_setup(); |
| 1498 | # elif defined(CONFIG_OF_HOSTFILE) | 1502 | # elif defined(CONFIG_OF_HOSTFILE) |
| 1499 | if (sandbox_read_fdt_from_file()) { | 1503 | if (sandbox_read_fdt_from_file()) { |
| 1500 | puts("Failed to read control FDT\n"); | 1504 | puts("Failed to read control FDT\n"); |
| 1501 | return -1; | 1505 | return -1; |
| 1502 | } | 1506 | } |
| 1503 | # endif | 1507 | # endif |
| 1504 | # ifndef CONFIG_SPL_BUILD | 1508 | # ifndef CONFIG_SPL_BUILD |
| 1505 | /* Allow the early environment to override the fdt address */ | 1509 | /* Allow the early environment to override the fdt address */ |
| 1506 | # if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) | 1510 | # if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) |
| 1507 | gd->fdt_blob = (void *)prior_stage_fdt_address; | 1511 | gd->fdt_blob = (void *)prior_stage_fdt_address; |
| 1508 | # else | 1512 | # else |
| 1509 | gd->fdt_blob = map_sysmem | 1513 | gd->fdt_blob = map_sysmem |
| 1510 | (env_get_ulong("fdtcontroladdr", 16, | 1514 | (env_get_ulong("fdtcontroladdr", 16, |
| 1511 | (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); | 1515 | (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); |
| 1512 | # endif | 1516 | # endif |
| 1513 | # endif | 1517 | # endif |
| 1514 | 1518 | ||
| 1515 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT) | 1519 | # if CONFIG_IS_ENABLED(MULTI_DTB_FIT) |
| 1516 | /* | 1520 | /* |
| 1517 | * Try and uncompress the blob. | 1521 | * Try and uncompress the blob. |
| 1518 | * Unfortunately there is no way to know how big the input blob really | 1522 | * Unfortunately there is no way to know how big the input blob really |
| 1519 | * is. So let us set the maximum input size arbitrarily high. 16MB | 1523 | * is. So let us set the maximum input size arbitrarily high. 16MB |
| 1520 | * ought to be more than enough for packed DTBs. | 1524 | * ought to be more than enough for packed DTBs. |
| 1521 | */ | 1525 | */ |
| 1522 | if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) | 1526 | if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) |
| 1523 | gd->fdt_blob = fdt_blob; | 1527 | gd->fdt_blob = fdt_blob; |
| 1524 | 1528 | ||
| 1525 | /* | 1529 | /* |
| 1526 | * Check if blob is a FIT images containings DTBs. | 1530 | * Check if blob is a FIT images containings DTBs. |
| 1527 | * If so, pick the most relevant | 1531 | * If so, pick the most relevant |
| 1528 | */ | 1532 | */ |
| 1529 | fdt_blob = locate_dtb_in_fit(gd->fdt_blob); | 1533 | fdt_blob = locate_dtb_in_fit(gd->fdt_blob); |
| 1530 | if (fdt_blob) { | 1534 | if (fdt_blob) { |
| 1531 | gd->multi_dtb_fit = gd->fdt_blob; | 1535 | gd->multi_dtb_fit = gd->fdt_blob; |
| 1532 | gd->fdt_blob = fdt_blob; | 1536 | gd->fdt_blob = fdt_blob; |
| 1533 | } | 1537 | } |
| 1534 | 1538 | ||
| 1535 | # endif | 1539 | # endif |
| 1536 | #endif | 1540 | #endif |
| 1537 | 1541 | ||
| 1538 | return fdtdec_prepare_fdt(); | 1542 | return fdtdec_prepare_fdt(); |
| 1539 | } | 1543 | } |
| 1540 | 1544 | ||
| 1541 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) | 1545 | #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) |
| 1542 | int fdtdec_resetup(int *rescan) | 1546 | int fdtdec_resetup(int *rescan) |
| 1543 | { | 1547 | { |
| 1544 | void *fdt_blob; | 1548 | void *fdt_blob; |
| 1545 | 1549 | ||
| 1546 | /* | 1550 | /* |
| 1547 | * If the current DTB is part of a compressed FIT image, | 1551 | * If the current DTB is part of a compressed FIT image, |
| 1548 | * try to locate the best match from the uncompressed | 1552 | * try to locate the best match from the uncompressed |
| 1549 | * FIT image stillpresent there. Save the time and space | 1553 | * FIT image stillpresent there. Save the time and space |
| 1550 | * required to uncompress it again. | 1554 | * required to uncompress it again. |
| 1551 | */ | 1555 | */ |
| 1552 | if (gd->multi_dtb_fit) { | 1556 | if (gd->multi_dtb_fit) { |
| 1553 | fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit); | 1557 | fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit); |
| 1554 | 1558 | ||
| 1555 | if (fdt_blob == gd->fdt_blob) { | 1559 | if (fdt_blob == gd->fdt_blob) { |
| 1556 | /* | 1560 | /* |
| 1557 | * The best match did not change. no need to tear down | 1561 | * The best match did not change. no need to tear down |
| 1558 | * the DM and rescan the fdt. | 1562 | * the DM and rescan the fdt. |
| 1559 | */ | 1563 | */ |
| 1560 | *rescan = 0; | 1564 | *rescan = 0; |
| 1561 | return 0; | 1565 | return 0; |
| 1562 | } | 1566 | } |
| 1563 | 1567 | ||
| 1564 | *rescan = 1; | 1568 | *rescan = 1; |
| 1565 | gd->fdt_blob = fdt_blob; | 1569 | gd->fdt_blob = fdt_blob; |
| 1566 | return fdtdec_prepare_fdt(); | 1570 | return fdtdec_prepare_fdt(); |
| 1567 | } | 1571 | } |
| 1568 | 1572 | ||
| 1569 | /* | 1573 | /* |
| 1570 | * If multi_dtb_fit is NULL, it means that blob appended to u-boot is | 1574 | * If multi_dtb_fit is NULL, it means that blob appended to u-boot is |
| 1571 | * not a FIT image containings DTB, but a single DTB. There is no need | 1575 | * not a FIT image containings DTB, but a single DTB. There is no need |
| 1572 | * to teard down DM and rescan the DT in this case. | 1576 | * to teard down DM and rescan the DT in this case. |
| 1573 | */ | 1577 | */ |
| 1574 | *rescan = 0; | 1578 | *rescan = 0; |
| 1575 | return 0; | 1579 | return 0; |
| 1576 | } | 1580 | } |
| 1577 | #endif | 1581 | #endif |
| 1578 | 1582 | ||
| 1579 | #ifdef CONFIG_NR_DRAM_BANKS | 1583 | #ifdef CONFIG_NR_DRAM_BANKS |
| 1580 | int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, | 1584 | int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, |
| 1581 | phys_addr_t *basep, phys_size_t *sizep, bd_t *bd) | 1585 | phys_addr_t *basep, phys_size_t *sizep, bd_t *bd) |
| 1582 | { | 1586 | { |
| 1583 | int addr_cells, size_cells; | 1587 | int addr_cells, size_cells; |
| 1584 | const u32 *cell, *end; | 1588 | const u32 *cell, *end; |
| 1585 | u64 total_size, size, addr; | 1589 | u64 total_size, size, addr; |
| 1586 | int node, child; | 1590 | int node, child; |
| 1587 | bool auto_size; | 1591 | bool auto_size; |
| 1588 | int bank; | 1592 | int bank; |
| 1589 | int len; | 1593 | int len; |
| 1590 | 1594 | ||
| 1591 | debug("%s: board_id=%d\n", __func__, board_id); | 1595 | debug("%s: board_id=%d\n", __func__, board_id); |
| 1592 | if (!area) | 1596 | if (!area) |
| 1593 | area = "/memory"; | 1597 | area = "/memory"; |
| 1594 | node = fdt_path_offset(blob, area); | 1598 | node = fdt_path_offset(blob, area); |
| 1595 | if (node < 0) { | 1599 | if (node < 0) { |
| 1596 | debug("No %s node found\n", area); | 1600 | debug("No %s node found\n", area); |
| 1597 | return -ENOENT; | 1601 | return -ENOENT; |
| 1598 | } | 1602 | } |
| 1599 | 1603 | ||
| 1600 | cell = fdt_getprop(blob, node, "reg", &len); | 1604 | cell = fdt_getprop(blob, node, "reg", &len); |
| 1601 | if (!cell) { | 1605 | if (!cell) { |
| 1602 | debug("No reg property found\n"); | 1606 | debug("No reg property found\n"); |
| 1603 | return -ENOENT; | 1607 | return -ENOENT; |
| 1604 | } | 1608 | } |
| 1605 | 1609 | ||
| 1606 | addr_cells = fdt_address_cells(blob, node); | 1610 | addr_cells = fdt_address_cells(blob, node); |
| 1607 | size_cells = fdt_size_cells(blob, node); | 1611 | size_cells = fdt_size_cells(blob, node); |
| 1608 | 1612 | ||
| 1609 | /* Check the board id and mask */ | 1613 | /* Check the board id and mask */ |
| 1610 | for (child = fdt_first_subnode(blob, node); | 1614 | for (child = fdt_first_subnode(blob, node); |
| 1611 | child >= 0; | 1615 | child >= 0; |
| 1612 | child = fdt_next_subnode(blob, child)) { | 1616 | child = fdt_next_subnode(blob, child)) { |
| 1613 | int match_mask, match_value; | 1617 | int match_mask, match_value; |
| 1614 | 1618 | ||
| 1615 | match_mask = fdtdec_get_int(blob, child, "match-mask", -1); | 1619 | match_mask = fdtdec_get_int(blob, child, "match-mask", -1); |
| 1616 | match_value = fdtdec_get_int(blob, child, "match-value", -1); | 1620 | match_value = fdtdec_get_int(blob, child, "match-value", -1); |
| 1617 | 1621 | ||
| 1618 | if (match_value >= 0 && | 1622 | if (match_value >= 0 && |
| 1619 | ((board_id & match_mask) == match_value)) { | 1623 | ((board_id & match_mask) == match_value)) { |
| 1620 | /* Found matching mask */ | 1624 | /* Found matching mask */ |
| 1621 | debug("Found matching mask %d\n", match_mask); | 1625 | debug("Found matching mask %d\n", match_mask); |
| 1622 | node = child; | 1626 | node = child; |
| 1623 | cell = fdt_getprop(blob, node, "reg", &len); | 1627 | cell = fdt_getprop(blob, node, "reg", &len); |
| 1624 | if (!cell) { | 1628 | if (!cell) { |
| 1625 | debug("No memory-banks property found\n"); | 1629 | debug("No memory-banks property found\n"); |
| 1626 | return -EINVAL; | 1630 | return -EINVAL; |
| 1627 | } | 1631 | } |
| 1628 | break; | 1632 | break; |
| 1629 | } | 1633 | } |
| 1630 | } | 1634 | } |
| 1631 | /* Note: if no matching subnode was found we use the parent node */ | 1635 | /* Note: if no matching subnode was found we use the parent node */ |
| 1632 | 1636 | ||
| 1633 | if (bd) { | 1637 | if (bd) { |
| 1634 | memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) * | 1638 | memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) * |
| 1635 | CONFIG_NR_DRAM_BANKS); | 1639 | CONFIG_NR_DRAM_BANKS); |
| 1636 | } | 1640 | } |
| 1637 | 1641 | ||
| 1638 | auto_size = fdtdec_get_bool(blob, node, "auto-size"); | 1642 | auto_size = fdtdec_get_bool(blob, node, "auto-size"); |
| 1639 | 1643 | ||
| 1640 | total_size = 0; | 1644 | total_size = 0; |
| 1641 | end = cell + len / 4 - addr_cells - size_cells; | 1645 | end = cell + len / 4 - addr_cells - size_cells; |
| 1642 | debug("cell at %p, end %p\n", cell, end); | 1646 | debug("cell at %p, end %p\n", cell, end); |
| 1643 | for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { | 1647 | for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { |
| 1644 | if (cell > end) | 1648 | if (cell > end) |
| 1645 | break; | 1649 | break; |
| 1646 | addr = 0; | 1650 | addr = 0; |
| 1647 | if (addr_cells == 2) | 1651 | if (addr_cells == 2) |
| 1648 | addr += (u64)fdt32_to_cpu(*cell++) << 32UL; | 1652 | addr += (u64)fdt32_to_cpu(*cell++) << 32UL; |
| 1649 | addr += fdt32_to_cpu(*cell++); | 1653 | addr += fdt32_to_cpu(*cell++); |
| 1650 | if (bd) | 1654 | if (bd) |
| 1651 | bd->bi_dram[bank].start = addr; | 1655 | bd->bi_dram[bank].start = addr; |
| 1652 | if (basep && !bank) | 1656 | if (basep && !bank) |
| 1653 | *basep = (phys_addr_t)addr; | 1657 | *basep = (phys_addr_t)addr; |
| 1654 | 1658 | ||
| 1655 | size = 0; | 1659 | size = 0; |
| 1656 | if (size_cells == 2) | 1660 | if (size_cells == 2) |
| 1657 | size += (u64)fdt32_to_cpu(*cell++) << 32UL; | 1661 | size += (u64)fdt32_to_cpu(*cell++) << 32UL; |
| 1658 | size += fdt32_to_cpu(*cell++); | 1662 | size += fdt32_to_cpu(*cell++); |
| 1659 | 1663 | ||
| 1660 | if (auto_size) { | 1664 | if (auto_size) { |
| 1661 | u64 new_size; | 1665 | u64 new_size; |
| 1662 | 1666 | ||
| 1663 | debug("Auto-sizing %llx, size %llx: ", addr, size); | 1667 | debug("Auto-sizing %llx, size %llx: ", addr, size); |
| 1664 | new_size = get_ram_size((long *)(uintptr_t)addr, size); | 1668 | new_size = get_ram_size((long *)(uintptr_t)addr, size); |
| 1665 | if (new_size == size) { | 1669 | if (new_size == size) { |
| 1666 | debug("OK\n"); | 1670 | debug("OK\n"); |
| 1667 | } else { | 1671 | } else { |
| 1668 | debug("sized to %llx\n", new_size); | 1672 | debug("sized to %llx\n", new_size); |
| 1669 | size = new_size; | 1673 | size = new_size; |
| 1670 | } | 1674 | } |
| 1671 | } | 1675 | } |
| 1672 | 1676 | ||
| 1673 | if (bd) | 1677 | if (bd) |
| 1674 | bd->bi_dram[bank].size = size; | 1678 | bd->bi_dram[bank].size = size; |
| 1675 | total_size += size; | 1679 | total_size += size; |
| 1676 | } | 1680 | } |
| 1677 | 1681 | ||
| 1678 | debug("Memory size %llu\n", total_size); | 1682 | debug("Memory size %llu\n", total_size); |
| 1679 | if (sizep) | 1683 | if (sizep) |
| 1680 | *sizep = (phys_size_t)total_size; | 1684 | *sizep = (phys_size_t)total_size; |
| 1681 | 1685 | ||
| 1682 | return 0; | 1686 | return 0; |
| 1683 | } | 1687 | } |
| 1684 | #endif /* CONFIG_NR_DRAM_BANKS */ | 1688 | #endif /* CONFIG_NR_DRAM_BANKS */ |
| 1685 | 1689 | ||
| 1686 | #endif /* !USE_HOSTCC */ | 1690 | #endif /* !USE_HOSTCC */ |
| 1687 | 1691 |
lib/fdtdec_test.c
| 1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* | 2 | /* |
| 3 | * Some very basic tests for fdtdec, accessed through test_fdtdec command. | 3 | * Some very basic tests for fdtdec, accessed through test_fdtdec command. |
| 4 | * They are easiest to use with sandbox. | 4 | * They are easiest to use with sandbox. |
| 5 | * | 5 | * |
| 6 | * Copyright (c) 2011 The Chromium OS Authors. | 6 | * Copyright (c) 2011 The Chromium OS Authors. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <common.h> | 9 | #include <common.h> |
| 10 | #include <fdtdec.h> | 10 | #include <fdtdec.h> |
| 11 | #include <linux/libfdt.h> | 11 | #include <linux/libfdt.h> |
| 12 | #include <malloc.h> | 12 | #include <malloc.h> |
| 13 | #include <os.h> | 13 | #include <os.h> |
| 14 | 14 | ||
| 15 | /* The size of our test fdt blob */ | 15 | /* The size of our test fdt blob */ |
| 16 | #define FDT_SIZE (16 * 1024) | 16 | #define FDT_SIZE (16 * 1024) |
| 17 | 17 | ||
| 18 | #define CHECK(op) ({ \ | 18 | #define CHECK(op) ({ \ |
| 19 | int err = op; \ | 19 | int err = op; \ |
| 20 | if (err < 0) { \ | 20 | if (err < 0) { \ |
| 21 | printf("%s: %s: %s\n", __func__, #op, \ | 21 | printf("%s: %s: %s\n", __func__, #op, \ |
| 22 | fdt_strerror(err)); \ | 22 | fdt_strerror(err)); \ |
| 23 | return err; \ | 23 | return err; \ |
| 24 | } \ | 24 | } \ |
| 25 | \ | 25 | \ |
| 26 | err; \ | 26 | err; \ |
| 27 | }) | 27 | }) |
| 28 | 28 | ||
| 29 | #define CHECKVAL(op, expected) ({ \ | 29 | #define CHECKVAL(op, expected) ({ \ |
| 30 | int err = op; \ | 30 | int err = op; \ |
| 31 | if (err != expected) { \ | 31 | if (err != expected) { \ |
| 32 | printf("%s: %s: expected %d, but returned %d\n",\ | 32 | printf("%s: %s: expected %d, but returned %d\n",\ |
| 33 | __func__, #op, expected, err); \ | 33 | __func__, #op, expected, err); \ |
| 34 | return err; \ | 34 | return err; \ |
| 35 | } \ | 35 | } \ |
| 36 | \ | 36 | \ |
| 37 | err; \ | 37 | err; \ |
| 38 | }) | 38 | }) |
| 39 | 39 | ||
| 40 | #define CHECKOK(op) CHECKVAL(op, 0) | 40 | #define CHECKOK(op) CHECKVAL(op, 0) |
| 41 | 41 | ||
| 42 | /* maximum number of nodes / aliases to generate */ | 42 | /* maximum number of nodes / aliases to generate */ |
| 43 | #define MAX_NODES 20 | 43 | #define MAX_NODES 20 |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Make a test fdt | 46 | * Make a test fdt |
| 47 | * | 47 | * |
| 48 | * @param fdt Device tree pointer | 48 | * @param fdt Device tree pointer |
| 49 | * @param size Size of device tree blob | 49 | * @param size Size of device tree blob |
| 50 | * @param aliases Specifies alias assignments. Format is a list of items | 50 | * @param aliases Specifies alias assignments. Format is a list of items |
| 51 | * separated by space. Items are #a where | 51 | * separated by space. Items are #a where |
| 52 | * # is the alias number | 52 | * # is the alias number |
| 53 | * a is the node to point to | 53 | * a is the node to point to |
| 54 | * @param nodes Specifies nodes to generate (a=0, b=1), upper case | 54 | * @param nodes Specifies nodes to generate (a=0, b=1), upper case |
| 55 | * means to create a disabled node | 55 | * means to create a disabled node |
| 56 | */ | 56 | */ |
| 57 | static int make_fdt(void *fdt, int size, const char *aliases, | 57 | static int make_fdt(void *fdt, int size, const char *aliases, |
| 58 | const char *nodes) | 58 | const char *nodes) |
| 59 | { | 59 | { |
| 60 | char name[20], value[20]; | 60 | char name[20], value[20]; |
| 61 | const char *s; | 61 | const char *s; |
| 62 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) | 62 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) |
| 63 | int fd; | 63 | int fd; |
| 64 | #endif | 64 | #endif |
| 65 | 65 | ||
| 66 | CHECK(fdt_create(fdt, size)); | 66 | CHECK(fdt_create(fdt, size)); |
| 67 | CHECK(fdt_finish_reservemap(fdt)); | 67 | CHECK(fdt_finish_reservemap(fdt)); |
| 68 | CHECK(fdt_begin_node(fdt, "")); | 68 | CHECK(fdt_begin_node(fdt, "")); |
| 69 | 69 | ||
| 70 | CHECK(fdt_begin_node(fdt, "aliases")); | 70 | CHECK(fdt_begin_node(fdt, "aliases")); |
| 71 | for (s = aliases; *s;) { | 71 | for (s = aliases; *s;) { |
| 72 | sprintf(name, "i2c%c", *s); | 72 | sprintf(name, "i2c%c", *s); |
| 73 | sprintf(value, "/i2c%d@0", s[1] - 'a'); | 73 | sprintf(value, "/i2c%d@0", s[1] - 'a'); |
| 74 | CHECK(fdt_property_string(fdt, name, value)); | 74 | CHECK(fdt_property_string(fdt, name, value)); |
| 75 | s += 2 + (s[2] != '\0'); | 75 | s += 2 + (s[2] != '\0'); |
| 76 | } | 76 | } |
| 77 | CHECK(fdt_end_node(fdt)); | 77 | CHECK(fdt_end_node(fdt)); |
| 78 | 78 | ||
| 79 | for (s = nodes; *s; s++) { | 79 | for (s = nodes; *s; s++) { |
| 80 | sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A'); | 80 | sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A'); |
| 81 | CHECK(fdt_begin_node(fdt, value)); | 81 | CHECK(fdt_begin_node(fdt, value)); |
| 82 | CHECK(fdt_property_string(fdt, "compatible", | 82 | CHECK(fdt_property_string(fdt, "compatible", |
| 83 | fdtdec_get_compatible(COMPAT_UNKNOWN))); | 83 | fdtdec_get_compatible(COMPAT_UNKNOWN))); |
| 84 | if (*s <= 'Z') | 84 | if (*s <= 'Z') |
| 85 | CHECK(fdt_property_string(fdt, "status", "disabled")); | 85 | CHECK(fdt_property_string(fdt, "status", "disabled")); |
| 86 | CHECK(fdt_end_node(fdt)); | 86 | CHECK(fdt_end_node(fdt)); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | CHECK(fdt_end_node(fdt)); | 89 | CHECK(fdt_end_node(fdt)); |
| 90 | CHECK(fdt_finish(fdt)); | 90 | CHECK(fdt_finish(fdt)); |
| 91 | CHECK(fdt_pack(fdt)); | 91 | CHECK(fdt_pack(fdt)); |
| 92 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) | 92 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) |
| 93 | fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY); | 93 | fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY); |
| 94 | if (fd == -1) { | 94 | if (fd == -1) { |
| 95 | printf("Could not open .dtb file to write\n"); | 95 | printf("Could not open .dtb file to write\n"); |
| 96 | return -1; | 96 | return -1; |
| 97 | } | 97 | } |
| 98 | os_write(fd, fdt, size); | 98 | os_write(fd, fdt, size); |
| 99 | os_close(fd); | 99 | os_close(fd); |
| 100 | #endif | 100 | #endif |
| 101 | return 0; | 101 | return 0; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static int run_test(const char *aliases, const char *nodes, const char *expect) | 104 | static int run_test(const char *aliases, const char *nodes, const char *expect) |
| 105 | { | 105 | { |
| 106 | int list[MAX_NODES]; | 106 | int list[MAX_NODES]; |
| 107 | const char *s; | 107 | const char *s; |
| 108 | void *blob; | 108 | void *blob; |
| 109 | int i; | 109 | int i; |
| 110 | 110 | ||
| 111 | blob = malloc(FDT_SIZE); | 111 | blob = malloc(FDT_SIZE); |
| 112 | if (!blob) { | 112 | if (!blob) { |
| 113 | printf("%s: out of memory\n", __func__); | 113 | printf("%s: out of memory\n", __func__); |
| 114 | return 1; | 114 | return 1; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | printf("aliases=%s, nodes=%s, expect=%s: ", aliases, nodes, expect); | 117 | printf("aliases=%s, nodes=%s, expect=%s: ", aliases, nodes, expect); |
| 118 | CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0); | 118 | CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0); |
| 119 | CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c", | 119 | CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c", |
| 120 | COMPAT_UNKNOWN, | 120 | COMPAT_UNKNOWN, |
| 121 | list, ARRAY_SIZE(list)), (int)strlen(expect)); | 121 | list, ARRAY_SIZE(list)), (int)strlen(expect)); |
| 122 | 122 | ||
| 123 | /* Check we got the right ones */ | 123 | /* Check we got the right ones */ |
| 124 | for (i = 0, s = expect; *s; s++, i++) { | 124 | for (i = 0, s = expect; *s; s++, i++) { |
| 125 | int want = *s; | 125 | int want = *s; |
| 126 | const char *name; | 126 | const char *name; |
| 127 | int got = ' '; | 127 | int got = ' '; |
| 128 | 128 | ||
| 129 | name = list[i] ? fdt_get_name(blob, list[i], NULL) : NULL; | 129 | name = list[i] ? fdt_get_name(blob, list[i], NULL) : NULL; |
| 130 | if (name) | 130 | if (name) |
| 131 | got = name[3] + 'a' - '0'; | 131 | got = name[3] + 'a' - '0'; |
| 132 | 132 | ||
| 133 | if (got != want) { | 133 | if (got != want) { |
| 134 | printf("Position %d: Expected '%c', got '%c' ('%s')\n", | 134 | printf("Position %d: Expected '%c', got '%c' ('%s')\n", |
| 135 | i, want, got, name); | 135 | i, want, got, name); |
| 136 | return 1; | 136 | return 1; |
| 137 | } | 137 | } |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | printf("pass\n"); | 140 | printf("pass\n"); |
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static int make_fdt_carveout_device(void *fdt, uint32_t na, uint32_t ns) | 144 | static int make_fdt_carveout_device(void *fdt, uint32_t na, uint32_t ns) |
| 145 | { | 145 | { |
| 146 | const char *basename = "/display"; | 146 | const char *basename = "/display"; |
| 147 | struct fdt_memory carveout = { | 147 | struct fdt_memory carveout = { |
| 148 | #ifdef CONFIG_PHYS_64BIT | 148 | #ifdef CONFIG_PHYS_64BIT |
| 149 | .start = 0x180000000, | 149 | .start = 0x180000000, |
| 150 | .end = 0x18fffffff, | 150 | .end = 0x18fffffff, |
| 151 | #else | 151 | #else |
| 152 | .start = 0x80000000, | 152 | .start = 0x80000000, |
| 153 | .end = 0x8fffffff, | 153 | .end = 0x8fffffff, |
| 154 | #endif | 154 | #endif |
| 155 | }; | 155 | }; |
| 156 | fdt32_t cells[4], *ptr = cells; | 156 | fdt32_t cells[4], *ptr = cells; |
| 157 | uint32_t upper, lower; | 157 | uint32_t upper, lower; |
| 158 | fdt_size_t size; | ||
| 158 | char name[32]; | 159 | char name[32]; |
| 159 | int offset; | 160 | int offset; |
| 160 | 161 | ||
| 161 | /* store one or two address cells */ | 162 | /* store one or two address cells */ |
| 162 | lower = fdt_addr_unpack(carveout.start, &upper); | 163 | upper = upper_32_bits(carveout.start); |
| 164 | lower = lower_32_bits(carveout.start); | ||
| 163 | 165 | ||
| 164 | if (na > 1 && upper > 0) | 166 | if (na > 1 && upper > 0) |
| 165 | snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, | 167 | snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, |
| 166 | lower); | 168 | lower); |
| 167 | else | 169 | else |
| 168 | snprintf(name, sizeof(name), "%s@%x", basename, lower); | 170 | snprintf(name, sizeof(name), "%s@%x", basename, lower); |
| 169 | 171 | ||
| 170 | if (na > 1) | 172 | if (na > 1) |
| 171 | *ptr++ = cpu_to_fdt32(upper); | 173 | *ptr++ = cpu_to_fdt32(upper); |
| 172 | 174 | ||
| 173 | *ptr++ = cpu_to_fdt32(lower); | 175 | *ptr++ = cpu_to_fdt32(lower); |
| 174 | 176 | ||
| 175 | /* store one or two size cells */ | 177 | /* store one or two size cells */ |
| 176 | lower = fdt_size_unpack(carveout.end - carveout.start + 1, &upper); | 178 | size = carveout.end - carveout.start + 1; |
| 179 | upper = upper_32_bits(size); | ||
| 180 | lower = lower_32_bits(size); | ||
| 177 | 181 | ||
| 178 | if (ns > 1) | 182 | if (ns > 1) |
| 179 | *ptr++ = cpu_to_fdt32(upper); | 183 | *ptr++ = cpu_to_fdt32(upper); |
| 180 | 184 | ||
| 181 | *ptr++ = cpu_to_fdt32(lower); | 185 | *ptr++ = cpu_to_fdt32(lower); |
| 182 | 186 | ||
| 183 | offset = CHECK(fdt_add_subnode(fdt, 0, name + 1)); | 187 | offset = CHECK(fdt_add_subnode(fdt, 0, name + 1)); |
| 184 | CHECK(fdt_setprop(fdt, offset, "reg", cells, (na + ns) * sizeof(*cells))); | 188 | CHECK(fdt_setprop(fdt, offset, "reg", cells, (na + ns) * sizeof(*cells))); |
| 185 | 189 | ||
| 186 | return fdtdec_set_carveout(fdt, name, "memory-region", 0, | 190 | return fdtdec_set_carveout(fdt, name, "memory-region", 0, |
| 187 | "framebuffer", &carveout); | 191 | "framebuffer", &carveout); |
| 188 | } | 192 | } |
| 189 | 193 | ||
| 190 | static int check_fdt_carveout(void *fdt, uint32_t address_cells, | 194 | static int check_fdt_carveout(void *fdt, uint32_t address_cells, |
| 191 | uint32_t size_cells) | 195 | uint32_t size_cells) |
| 192 | { | 196 | { |
| 193 | #ifdef CONFIG_PHYS_64BIT | 197 | #ifdef CONFIG_PHYS_64BIT |
| 194 | const char *name = "/display@1,80000000"; | 198 | const char *name = "/display@1,80000000"; |
| 195 | const struct fdt_memory expected = { | 199 | const struct fdt_memory expected = { |
| 196 | .start = 0x180000000, | 200 | .start = 0x180000000, |
| 197 | .end = 0x18fffffff, | 201 | .end = 0x18fffffff, |
| 198 | }; | 202 | }; |
| 199 | #else | 203 | #else |
| 200 | const char *name = "/display@80000000"; | 204 | const char *name = "/display@80000000"; |
| 201 | const struct fdt_memory expected = { | 205 | const struct fdt_memory expected = { |
| 202 | .start = 0x80000000, | 206 | .start = 0x80000000, |
| 203 | .end = 0x8fffffff, | 207 | .end = 0x8fffffff, |
| 204 | }; | 208 | }; |
| 205 | #endif | 209 | #endif |
| 206 | struct fdt_memory carveout; | 210 | struct fdt_memory carveout; |
| 207 | 211 | ||
| 208 | printf("carveout: %pap-%pap na=%u ns=%u: ", &expected.start, | 212 | printf("carveout: %pap-%pap na=%u ns=%u: ", &expected.start, |
| 209 | &expected.end, address_cells, size_cells); | 213 | &expected.end, address_cells, size_cells); |
| 210 | 214 | ||
| 211 | CHECK(fdtdec_get_carveout(fdt, name, "memory-region", 0, &carveout)); | 215 | CHECK(fdtdec_get_carveout(fdt, name, "memory-region", 0, &carveout)); |
| 212 | 216 | ||
| 213 | if ((carveout.start != expected.start) || | 217 | if ((carveout.start != expected.start) || |
| 214 | (carveout.end != expected.end)) { | 218 | (carveout.end != expected.end)) { |
| 215 | printf("carveout: %pap-%pap, expected %pap-%pap\n", | 219 | printf("carveout: %pap-%pap, expected %pap-%pap\n", |
| 216 | &carveout.start, &carveout.end, | 220 | &carveout.start, &carveout.end, |
| 217 | &expected.start, &expected.end); | 221 | &expected.start, &expected.end); |
| 218 | return 1; | 222 | return 1; |
| 219 | } | 223 | } |
| 220 | 224 | ||
| 221 | printf("pass\n"); | 225 | printf("pass\n"); |
| 222 | return 0; | 226 | return 0; |
| 223 | } | 227 | } |
| 224 | 228 | ||
| 225 | static int make_fdt_carveout(void *fdt, int size, uint32_t address_cells, | 229 | static int make_fdt_carveout(void *fdt, int size, uint32_t address_cells, |
| 226 | uint32_t size_cells) | 230 | uint32_t size_cells) |
| 227 | { | 231 | { |
| 228 | fdt32_t na = cpu_to_fdt32(address_cells); | 232 | fdt32_t na = cpu_to_fdt32(address_cells); |
| 229 | fdt32_t ns = cpu_to_fdt32(size_cells); | 233 | fdt32_t ns = cpu_to_fdt32(size_cells); |
| 230 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) | 234 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) |
| 231 | char filename[512]; | 235 | char filename[512]; |
| 232 | int fd; | 236 | int fd; |
| 233 | #endif | 237 | #endif |
| 234 | int err; | 238 | int err; |
| 235 | 239 | ||
| 236 | CHECK(fdt_create(fdt, size)); | 240 | CHECK(fdt_create(fdt, size)); |
| 237 | CHECK(fdt_finish_reservemap(fdt)); | 241 | CHECK(fdt_finish_reservemap(fdt)); |
| 238 | CHECK(fdt_begin_node(fdt, "")); | 242 | CHECK(fdt_begin_node(fdt, "")); |
| 239 | CHECK(fdt_property(fdt, "#address-cells", &na, sizeof(na))); | 243 | CHECK(fdt_property(fdt, "#address-cells", &na, sizeof(na))); |
| 240 | CHECK(fdt_property(fdt, "#size-cells", &ns, sizeof(ns))); | 244 | CHECK(fdt_property(fdt, "#size-cells", &ns, sizeof(ns))); |
| 241 | CHECK(fdt_end_node(fdt)); | 245 | CHECK(fdt_end_node(fdt)); |
| 242 | CHECK(fdt_finish(fdt)); | 246 | CHECK(fdt_finish(fdt)); |
| 243 | CHECK(fdt_pack(fdt)); | 247 | CHECK(fdt_pack(fdt)); |
| 244 | 248 | ||
| 245 | CHECK(fdt_open_into(fdt, fdt, FDT_SIZE)); | 249 | CHECK(fdt_open_into(fdt, fdt, FDT_SIZE)); |
| 246 | 250 | ||
| 247 | err = make_fdt_carveout_device(fdt, address_cells, size_cells); | 251 | err = make_fdt_carveout_device(fdt, address_cells, size_cells); |
| 248 | 252 | ||
| 249 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) | 253 | #if defined(DEBUG) && defined(CONFIG_SANDBOX) |
| 250 | snprintf(filename, sizeof(filename), "/tmp/fdtdec-carveout-%u-%u.dtb", | 254 | snprintf(filename, sizeof(filename), "/tmp/fdtdec-carveout-%u-%u.dtb", |
| 251 | address_cells, size_cells); | 255 | address_cells, size_cells); |
| 252 | 256 | ||
| 253 | fd = os_open(filename, OS_O_CREAT | OS_O_WRONLY); | 257 | fd = os_open(filename, OS_O_CREAT | OS_O_WRONLY); |
| 254 | if (fd < 0) { | 258 | if (fd < 0) { |
| 255 | printf("could not open .dtb file to write\n"); | 259 | printf("could not open .dtb file to write\n"); |
| 256 | goto out; | 260 | goto out; |
| 257 | } | 261 | } |
| 258 | 262 | ||
| 259 | os_write(fd, fdt, size); | 263 | os_write(fd, fdt, size); |
| 260 | os_close(fd); | 264 | os_close(fd); |
| 261 | 265 | ||
| 262 | out: | 266 | out: |
| 263 | #endif | 267 | #endif |
| 264 | return err; | 268 | return err; |
| 265 | } | 269 | } |
| 266 | 270 | ||
| 267 | static int check_carveout(void) | 271 | static int check_carveout(void) |
| 268 | { | 272 | { |
| 269 | void *fdt; | 273 | void *fdt; |
| 270 | 274 | ||
| 271 | fdt = malloc(FDT_SIZE); | 275 | fdt = malloc(FDT_SIZE); |
| 272 | if (!fdt) { | 276 | if (!fdt) { |
| 273 | printf("%s: out of memory\n", __func__); | 277 | printf("%s: out of memory\n", __func__); |
| 274 | return 1; | 278 | return 1; |
| 275 | } | 279 | } |
| 276 | 280 | ||
| 277 | #ifndef CONFIG_PHYS_64BIT | 281 | #ifndef CONFIG_PHYS_64BIT |
| 278 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), 0); | 282 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), 0); |
| 279 | CHECKOK(check_fdt_carveout(fdt, 1, 1)); | 283 | CHECKOK(check_fdt_carveout(fdt, 1, 1)); |
| 280 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), 0); | 284 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), 0); |
| 281 | CHECKOK(check_fdt_carveout(fdt, 1, 2)); | 285 | CHECKOK(check_fdt_carveout(fdt, 1, 2)); |
| 282 | #else | 286 | #else |
| 283 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), -FDT_ERR_BADVALUE); | 287 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), -FDT_ERR_BADVALUE); |
| 284 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), -FDT_ERR_BADVALUE); | 288 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), -FDT_ERR_BADVALUE); |
| 285 | #endif | 289 | #endif |
| 286 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 1), 0); | 290 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 1), 0); |
| 287 | CHECKOK(check_fdt_carveout(fdt, 2, 1)); | 291 | CHECKOK(check_fdt_carveout(fdt, 2, 1)); |
| 288 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 2), 0); | 292 | CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 2), 0); |
| 289 | CHECKOK(check_fdt_carveout(fdt, 2, 2)); | 293 | CHECKOK(check_fdt_carveout(fdt, 2, 2)); |
| 290 | 294 | ||
| 291 | return 0; | 295 | return 0; |
| 292 | } | 296 | } |
| 293 | 297 | ||
| 294 | static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc, | 298 | static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc, |
| 295 | char * const argv[]) | 299 | char * const argv[]) |
| 296 | { | 300 | { |
| 297 | /* basic tests */ | 301 | /* basic tests */ |
| 298 | CHECKOK(run_test("", "", "")); | 302 | CHECKOK(run_test("", "", "")); |
| 299 | CHECKOK(run_test("1e 3d", "", "")); | 303 | CHECKOK(run_test("1e 3d", "", "")); |
| 300 | 304 | ||
| 301 | /* | 305 | /* |
| 302 | * 'a' represents 0, 'b' represents 1, etc. | 306 | * 'a' represents 0, 'b' represents 1, etc. |
| 303 | * The first character is the alias number, the second is the node | 307 | * The first character is the alias number, the second is the node |
| 304 | * number. So the params mean: | 308 | * number. So the params mean: |
| 305 | * 0a 1b : point alias 0 to node 0 (a), alias 1 to node 1(b) | 309 | * 0a 1b : point alias 0 to node 0 (a), alias 1 to node 1(b) |
| 306 | * ab : to create nodes 0 and 1 (a and b) | 310 | * ab : to create nodes 0 and 1 (a and b) |
| 307 | * ab : we expect the function to return two nodes, in | 311 | * ab : we expect the function to return two nodes, in |
| 308 | * the order 0, 1 | 312 | * the order 0, 1 |
| 309 | */ | 313 | */ |
| 310 | CHECKOK(run_test("0a 1b", "ab", "ab")); | 314 | CHECKOK(run_test("0a 1b", "ab", "ab")); |
| 311 | 315 | ||
| 312 | CHECKOK(run_test("0a 1c", "ab", "ab")); | 316 | CHECKOK(run_test("0a 1c", "ab", "ab")); |
| 313 | CHECKOK(run_test("1c", "ab", "ab")); | 317 | CHECKOK(run_test("1c", "ab", "ab")); |
| 314 | CHECKOK(run_test("1b", "ab", "ab")); | 318 | CHECKOK(run_test("1b", "ab", "ab")); |
| 315 | CHECKOK(run_test("0b", "ab", "ba")); | 319 | CHECKOK(run_test("0b", "ab", "ba")); |
| 316 | CHECKOK(run_test("0b 2d", "dbc", "bcd")); | 320 | CHECKOK(run_test("0b 2d", "dbc", "bcd")); |
| 317 | CHECKOK(run_test("0d 3a 1c 2b", "dbac", "dcba")); | 321 | CHECKOK(run_test("0d 3a 1c 2b", "dbac", "dcba")); |
| 318 | 322 | ||
| 319 | /* things with holes */ | 323 | /* things with holes */ |
| 320 | CHECKOK(run_test("1b 3d", "dbc", "cb d")); | 324 | CHECKOK(run_test("1b 3d", "dbc", "cb d")); |
| 321 | CHECKOK(run_test("1e 3d", "dbc", "bc d")); | 325 | CHECKOK(run_test("1e 3d", "dbc", "bc d")); |
| 322 | 326 | ||
| 323 | /* no aliases */ | 327 | /* no aliases */ |
| 324 | CHECKOK(run_test("", "dbac", "dbac")); | 328 | CHECKOK(run_test("", "dbac", "dbac")); |
| 325 | 329 | ||
| 326 | /* disabled nodes */ | 330 | /* disabled nodes */ |
| 327 | CHECKOK(run_test("0d 3a 1c 2b", "dBac", "dc a")); | 331 | CHECKOK(run_test("0d 3a 1c 2b", "dBac", "dc a")); |
| 328 | CHECKOK(run_test("0b 2d", "DBc", "c")); | 332 | CHECKOK(run_test("0b 2d", "DBc", "c")); |
| 329 | CHECKOK(run_test("0b 4d 2c", "DBc", " c")); | 333 | CHECKOK(run_test("0b 4d 2c", "DBc", " c")); |
| 330 | 334 | ||
| 331 | /* conflicting aliases - first one gets it */ | 335 | /* conflicting aliases - first one gets it */ |
| 332 | CHECKOK(run_test("2a 1a 0a", "a", " a")); | 336 | CHECKOK(run_test("2a 1a 0a", "a", " a")); |
| 333 | CHECKOK(run_test("0a 1a 2a", "a", "a")); | 337 | CHECKOK(run_test("0a 1a 2a", "a", "a")); |
| 334 | 338 | ||
| 335 | CHECKOK(check_carveout()); | 339 | CHECKOK(check_carveout()); |
| 336 | 340 | ||
| 337 | printf("Test passed\n"); | 341 | printf("Test passed\n"); |
| 338 | return 0; | 342 | return 0; |
| 339 | } | 343 | } |
| 340 | 344 | ||
| 341 | U_BOOT_CMD( | 345 | U_BOOT_CMD( |
| 342 | test_fdtdec, 3, 1, do_test_fdtdec, | 346 | test_fdtdec, 3, 1, do_test_fdtdec, |
| 343 | "test_fdtdec", | 347 | "test_fdtdec", |
| 344 | "Run tests for fdtdec library"); | 348 | "Run tests for fdtdec library"); |
| 345 | 349 |