summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/armv8/fsl-lsch3/fdt.c
blob: 922e8a0d6ebb83b17459c7d1020ddd5d6c97389e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * Copyright 2014 Freescale Semiconductor, Inc.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <libfdt.h>
#include <fdt_support.h>
#include <asm/arch-fsl-lsch3/fdt.h>
#ifdef CONFIG_FSL_ESDHC
#include <fsl_esdhc.h>
#endif
#include "mp.h"

#ifdef CONFIG_MP
void ft_fixup_cpu(void *blob)
{
	int off;
	__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr();
	fdt32_t *reg;
	int addr_cells;
	u64 val, core_id;
	size_t *boot_code_size = &(__secondary_boot_code_size);

	off = fdt_path_offset(blob, "/cpus");
	if (off < 0) {
		puts("couldn't find /cpus node\n");
		return;
	}
	of_bus_default_count_cells(blob, off, &addr_cells, NULL);

	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
	while (off != -FDT_ERR_NOTFOUND) {
		reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
		if (reg) {
			core_id = of_read_number(reg, addr_cells);
			if (core_id  == 0 || (is_core_online(core_id))) {
				val = spin_tbl_addr;
				val += id_to_core(core_id) *
				       SPIN_TABLE_ELEM_SIZE;
				val = cpu_to_fdt64(val);
				fdt_setprop_string(blob, off, "enable-method",
						   "spin-table");
				fdt_setprop(blob, off, "cpu-release-addr",
					    &val, sizeof(val));
			} else {
				debug("skipping offline core\n");
			}
		} else {
			puts("Warning: found cpu node without reg property\n");
		}
		off = fdt_node_offset_by_prop_value(blob, off, "device_type",
						    "cpu", 4);
	}

	fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
			*boot_code_size);
}
#endif

/*
 * the burden is on the the caller to not request a count
 * exceeding the bounds of the stream_ids[] array
 */
void alloc_stream_ids(int start_id, int count, u32 *stream_ids, int max_cnt)
{
	int i;

	if (count > max_cnt) {
		printf("\n%s: ERROR: max per-device stream ID count exceed\n",
		       __func__);
		return;
	}

	for (i = 0; i < count; i++)
		stream_ids[i] = start_id++;
}

/*
 * This function updates the mmu-masters property on the SMMU
 * node as per the SMMU binding-- phandle and list of stream IDs
 * for each MMU master.
 */
void append_mmu_masters(void *blob, const char *smmu_path,
			const char *master_name, u32 *stream_ids, int count)
{
	u32 phandle;
	int smmu_nodeoffset;
	int master_nodeoffset;
	int i;

	/* get phandle of mmu master device */
	master_nodeoffset = fdt_path_offset(blob, master_name);
	if (master_nodeoffset < 0) {
		printf("\n%s: ERROR: master not found\n", __func__);
		return;
	}
	phandle = fdt_get_phandle(blob, master_nodeoffset);
	if (!phandle) { /* if master has no phandle, create one */
		phandle = fdt_create_phandle(blob, master_nodeoffset);
		if (!phandle) {
			printf("\n%s: ERROR: unable to create phandle\n",
			       __func__);
			return;
		}
	}

	/* append it to mmu-masters */
	smmu_nodeoffset = fdt_path_offset(blob, smmu_path);
	if (fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters",
			       phandle) < 0) {
		printf("\n%s: ERROR: unable to update SMMU node\n", __func__);
		return;
	}

	/* for each stream ID, append to mmu-masters */
	for (i = 0; i < count; i++) {
		fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters",
				   stream_ids[i]);
	}

	/* fix up #stream-id-cells with stream ID count */
	if (fdt_setprop_u32(blob, master_nodeoffset, "#stream-id-cells",
			    count) < 0)
		printf("\n%s: ERROR: unable to update #stream-id-cells\n",
		       __func__);
}


/*
 * The info below summarizes how streamID partitioning works
 * for ls2085a and how it is conveyed to the OS via the device tree.
 *
 *  -non-PCI legacy, platform devices (USB, SD/MMC, SATA, DMA)
 *     -all legacy devices get a unique ICID assigned and programmed in
 *      their AMQR registers by u-boot
 *     -u-boot updates the hardware device tree with streamID properties
 *      for each platform/legacy device (smmu-masters property)
 *
 *  -PCIe
 *     -for each PCI controller that is active (as per RCW settings),
 *      u-boot will allocate a range of ICID and convey that to Linux via
 *      the device tree (smmu-masters property)
 *
 *  -DPAA2
 *     -u-boot will allocate a range of ICIDs to be used by the Management
 *      Complex for containers and will set these values in the MC DPC image.
 *     -the MC is responsible for allocating and setting up ICIDs
 *      for all DPAA2 devices.
 *
 */
static void fdt_fixup_smmu(void *blob)
{
	int nodeoffset;

	nodeoffset = fdt_path_offset(blob, "/iommu@5000000");
	if (nodeoffset < 0) {
		printf("\n%s: WARNING: no SMMU node found\n", __func__);
		return;
	}

	/* fixup for all PCI controllers */
#ifdef CONFIG_PCI
	fdt_fixup_smmu_pcie(blob);
#endif
}

void ft_cpu_setup(void *blob, bd_t *bd)
{
#ifdef CONFIG_MP
	ft_fixup_cpu(blob);
#endif

#ifdef CONFIG_SYS_NS16550
	do_fixup_by_compat_u32(blob, "fsl,ns16550",
			       "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
#endif

#ifdef CONFIG_PCI
	ft_pci_setup(blob, bd);
#endif

#if defined(CONFIG_FSL_ESDHC)
	fdt_fixup_esdhc(blob, bd);
#endif

	fdt_fixup_smmu(blob);
}
OpenPOWER on IntegriCloud