York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 Freescale Semiconductor, Inc. |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0+ |
| 5 | */ |
| 6 | |
| 7 | #include <common.h> |
| 8 | #include <libfdt.h> |
| 9 | #include <fdt_support.h> |
Stuart Yoder | eaea504 | 2015-07-02 11:29:04 +0530 | [diff] [blame^] | 10 | #include <asm/arch-fsl-lsch3/fdt.h> |
Yangbo Lu | d0e295d | 2015-03-20 19:28:31 -0700 | [diff] [blame] | 11 | #ifdef CONFIG_FSL_ESDHC |
| 12 | #include <fsl_esdhc.h> |
| 13 | #endif |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 14 | #include "mp.h" |
| 15 | |
| 16 | #ifdef CONFIG_MP |
| 17 | void ft_fixup_cpu(void *blob) |
| 18 | { |
| 19 | int off; |
| 20 | __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); |
| 21 | fdt32_t *reg; |
| 22 | int addr_cells; |
Arnab Basu | 0cb1942 | 2015-01-06 13:18:41 -0800 | [diff] [blame] | 23 | u64 val, core_id; |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 24 | size_t *boot_code_size = &(__secondary_boot_code_size); |
| 25 | |
| 26 | off = fdt_path_offset(blob, "/cpus"); |
| 27 | if (off < 0) { |
| 28 | puts("couldn't find /cpus node\n"); |
| 29 | return; |
| 30 | } |
| 31 | of_bus_default_count_cells(blob, off, &addr_cells, NULL); |
| 32 | |
| 33 | off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); |
| 34 | while (off != -FDT_ERR_NOTFOUND) { |
| 35 | reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); |
Arnab Basu | 0cb1942 | 2015-01-06 13:18:41 -0800 | [diff] [blame] | 36 | core_id = of_read_number(reg, addr_cells); |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 37 | if (reg) { |
Arnab Basu | 0cb1942 | 2015-01-06 13:18:41 -0800 | [diff] [blame] | 38 | if (core_id == 0 || (is_core_online(core_id))) { |
| 39 | val = spin_tbl_addr; |
| 40 | val += id_to_core(core_id) * |
| 41 | SPIN_TABLE_ELEM_SIZE; |
| 42 | val = cpu_to_fdt64(val); |
| 43 | fdt_setprop_string(blob, off, "enable-method", |
| 44 | "spin-table"); |
| 45 | fdt_setprop(blob, off, "cpu-release-addr", |
| 46 | &val, sizeof(val)); |
| 47 | } else { |
| 48 | debug("skipping offline core\n"); |
| 49 | } |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 50 | } else { |
| 51 | puts("Warning: found cpu node without reg property\n"); |
| 52 | } |
| 53 | off = fdt_node_offset_by_prop_value(blob, off, "device_type", |
| 54 | "cpu", 4); |
| 55 | } |
| 56 | |
| 57 | fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, |
| 58 | *boot_code_size); |
| 59 | } |
| 60 | #endif |
| 61 | |
Stuart Yoder | eaea504 | 2015-07-02 11:29:04 +0530 | [diff] [blame^] | 62 | /* |
| 63 | * the burden is on the the caller to not request a count |
| 64 | * exceeding the bounds of the stream_ids[] array |
| 65 | */ |
| 66 | void alloc_stream_ids(int start_id, int count, u32 *stream_ids, int max_cnt) |
| 67 | { |
| 68 | int i; |
| 69 | |
| 70 | if (count > max_cnt) { |
| 71 | printf("\n%s: ERROR: max per-device stream ID count exceed\n", |
| 72 | __func__); |
| 73 | return; |
| 74 | } |
| 75 | |
| 76 | for (i = 0; i < count; i++) |
| 77 | stream_ids[i] = start_id++; |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | * This function updates the mmu-masters property on the SMMU |
| 82 | * node as per the SMMU binding-- phandle and list of stream IDs |
| 83 | * for each MMU master. |
| 84 | */ |
| 85 | void append_mmu_masters(void *blob, const char *smmu_path, |
| 86 | const char *master_name, u32 *stream_ids, int count) |
| 87 | { |
| 88 | u32 phandle; |
| 89 | int smmu_nodeoffset; |
| 90 | int master_nodeoffset; |
| 91 | int i; |
| 92 | |
| 93 | /* get phandle of mmu master device */ |
| 94 | master_nodeoffset = fdt_path_offset(blob, master_name); |
| 95 | if (master_nodeoffset < 0) { |
| 96 | printf("\n%s: ERROR: master not found\n", __func__); |
| 97 | return; |
| 98 | } |
| 99 | phandle = fdt_get_phandle(blob, master_nodeoffset); |
| 100 | if (!phandle) { /* if master has no phandle, create one */ |
| 101 | phandle = fdt_create_phandle(blob, master_nodeoffset); |
| 102 | if (!phandle) { |
| 103 | printf("\n%s: ERROR: unable to create phandle\n", |
| 104 | __func__); |
| 105 | return; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /* append it to mmu-masters */ |
| 110 | smmu_nodeoffset = fdt_path_offset(blob, smmu_path); |
| 111 | if (fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", |
| 112 | phandle) < 0) { |
| 113 | printf("\n%s: ERROR: unable to update SMMU node\n", __func__); |
| 114 | return; |
| 115 | } |
| 116 | |
| 117 | /* for each stream ID, append to mmu-masters */ |
| 118 | for (i = 0; i < count; i++) { |
| 119 | fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", |
| 120 | stream_ids[i]); |
| 121 | } |
| 122 | |
| 123 | /* fix up #stream-id-cells with stream ID count */ |
| 124 | if (fdt_setprop_u32(blob, master_nodeoffset, "#stream-id-cells", |
| 125 | count) < 0) |
| 126 | printf("\n%s: ERROR: unable to update #stream-id-cells\n", |
| 127 | __func__); |
| 128 | } |
| 129 | |
| 130 | |
| 131 | /* |
| 132 | * The info below summarizes how streamID partitioning works |
| 133 | * for ls2085a and how it is conveyed to the OS via the device tree. |
| 134 | * |
| 135 | * -non-PCI legacy, platform devices (USB, SD/MMC, SATA, DMA) |
| 136 | * -all legacy devices get a unique ICID assigned and programmed in |
| 137 | * their AMQR registers by u-boot |
| 138 | * -u-boot updates the hardware device tree with streamID properties |
| 139 | * for each platform/legacy device (smmu-masters property) |
| 140 | * |
| 141 | * -PCIe |
| 142 | * -for each PCI controller that is active (as per RCW settings), |
| 143 | * u-boot will allocate a range of ICID and convey that to Linux via |
| 144 | * the device tree (smmu-masters property) |
| 145 | * |
| 146 | * -DPAA2 |
| 147 | * -u-boot will allocate a range of ICIDs to be used by the Management |
| 148 | * Complex for containers and will set these values in the MC DPC image. |
| 149 | * -the MC is responsible for allocating and setting up ICIDs |
| 150 | * for all DPAA2 devices. |
| 151 | * |
| 152 | */ |
| 153 | static void fdt_fixup_smmu(void *blob) |
| 154 | { |
| 155 | int nodeoffset; |
| 156 | |
| 157 | nodeoffset = fdt_path_offset(blob, "/iommu@5000000"); |
| 158 | if (nodeoffset < 0) { |
| 159 | printf("\n%s: WARNING: no SMMU node found\n", __func__); |
| 160 | return; |
| 161 | } |
| 162 | |
| 163 | /* fixup for all PCI controllers */ |
| 164 | #ifdef CONFIG_PCI |
| 165 | fdt_fixup_smmu_pcie(blob); |
| 166 | #endif |
| 167 | } |
| 168 | |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 169 | void ft_cpu_setup(void *blob, bd_t *bd) |
| 170 | { |
| 171 | #ifdef CONFIG_MP |
| 172 | ft_fixup_cpu(blob); |
| 173 | #endif |
Bhupesh Sharma | c771040 | 2015-01-06 13:18:44 -0800 | [diff] [blame] | 174 | |
| 175 | #ifdef CONFIG_SYS_NS16550 |
Scott Wood | 3e7fd6f | 2015-03-20 19:28:14 -0700 | [diff] [blame] | 176 | do_fixup_by_compat_u32(blob, "fsl,ns16550", |
Bhupesh Sharma | c771040 | 2015-01-06 13:18:44 -0800 | [diff] [blame] | 177 | "clock-frequency", CONFIG_SYS_NS16550_CLK, 1); |
| 178 | #endif |
Yangbo Lu | d0e295d | 2015-03-20 19:28:31 -0700 | [diff] [blame] | 179 | |
Prabhakar Kushwaha | 940a316 | 2015-05-28 14:53:59 +0530 | [diff] [blame] | 180 | #ifdef CONFIG_PCI |
| 181 | ft_pci_setup(blob, bd); |
| 182 | #endif |
| 183 | |
Yangbo Lu | d0e295d | 2015-03-20 19:28:31 -0700 | [diff] [blame] | 184 | #if defined(CONFIG_FSL_ESDHC) |
| 185 | fdt_fixup_esdhc(blob, bd); |
| 186 | #endif |
Stuart Yoder | eaea504 | 2015-07-02 11:29:04 +0530 | [diff] [blame^] | 187 | |
| 188 | fdt_fixup_smmu(blob); |
York Sun | 56cc3db | 2014-09-08 12:20:00 -0700 | [diff] [blame] | 189 | } |