summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-layerscape/soc.c
blob: 1742ff58ce1036b072a37dc2a6b037b86225354a (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
// SPDX-License-Identifier: GPL-2.0-only
#include <soc/fsl/scfg.h>
#include <io.h>
#include <init.h>
#include <memory.h>
#include <linux/bug.h>
#include <linux/bitfield.h>
#include <linux/printk.h>
#include <mach/layerscape/layerscape.h>
#include <of.h>
#include <of_address.h>

int __layerscape_soc_type;

static enum scfg_endianess scfg_endianess = SCFG_ENDIANESS_INVALID;

static void scfg_check_endianess(void)
{
	BUG_ON(scfg_endianess == SCFG_ENDIANESS_INVALID);
}

void scfg_clrsetbits32(void __iomem *addr, u32 clear, u32 set)
{
	scfg_check_endianess();

	if (scfg_endianess == SCFG_ENDIANESS_LITTLE)
		clrsetbits_le32(addr, clear, set);
	else
		clrsetbits_be32(addr, clear, set);
}

void scfg_clrbits32(void __iomem *addr, u32 clear)
{
	scfg_check_endianess();

	if (scfg_endianess == SCFG_ENDIANESS_LITTLE)
		clrbits_le32(addr, clear);
	else
		clrbits_be32(addr, clear);
}

void scfg_setbits32(void __iomem *addr, u32 set)
{
	scfg_check_endianess();

	if (scfg_endianess == SCFG_ENDIANESS_LITTLE)
		setbits_le32(addr, set);
	else
		setbits_be32(addr, set);
}

void scfg_out16(void __iomem *addr, u16 val)
{
	scfg_check_endianess();

	if (scfg_endianess == SCFG_ENDIANESS_LITTLE)
		out_le16(addr, val);
	else
		out_be16(addr, val);
}

void scfg_init(enum scfg_endianess endianess)
{
	scfg_endianess = endianess;
}

static int layerscape_soc_from_dt(void)
{
	if (of_machine_is_compatible("fsl,ls1021a"))
		return LAYERSCAPE_SOC_LS1021A;
	if (of_machine_is_compatible("fsl,ls1028a"))
		return LAYERSCAPE_SOC_LS1028A;
	if (of_machine_is_compatible("fsl,ls1046a"))
		return LAYERSCAPE_SOC_LS1046A;

	return 0;
}

static int ls1021a_init(void)
{
	if (!cpu_is_ls1021a())
		return -EINVAL;

	ls1021a_bootsource_init();
	ls102xa_smmu_stream_id_init();
	layerscape_register_pbl_image_handler();
	ls1021a_restart_register_feature();

	return 0;
}

static int ls1028a_init(void)
{
	if (!cpu_is_ls1028a())
		return -EINVAL;

	ls1028a_bootsource_init();
	layerscape_register_pbl_image_handler();
	ls1028a_setup_icids();

	return 0;
}

static int ls1028a_reserve_tfa(void)
{
	resource_size_t tfa_start = LS1028A_TFA_RESERVED_START;
	resource_size_t tfa_size = LS1028A_TFA_RESERVED_SIZE;
	struct resource *res;

	if (!cpu_is_ls1028a())
		return 0;

	res = reserve_sdram_region("tfa", tfa_start, tfa_size);
	if (!res) {
		pr_err("Cannot request SDRAM region %pa - %pa\n", &tfa_start, &tfa_size);
                return -EINVAL;
	}

	of_register_fixup(of_fixup_reserved_memory, res);

	return 0;
}
mmu_initcall(ls1028a_reserve_tfa);

#define DWC3_GSBUSCFG0				0xc100
#define DWC3_GSBUSCFG0_CACHETYPE_MASK		GENMASK(31, 16)

static void layerscape_usb_enable_snooping(void)
{
	struct device_node *np;

	for_each_compatible_node(np, NULL, "snps,dwc3") {
		struct resource res;

		if (of_address_to_resource(np, 0, &res))
			continue;

		/* Set cacheable bit for all of Data read, Descriptor read,
		 * Data write and Descriptor write. Bufferable and read/write
		 * allocate bits are not set. This is the recommended configurationr
		 * in LS1046ARM Rev. 3 34.2.10.2:
		 * "For master interface DMA access, program the GSBUSCFG0
		 * register to 0x2222000F for better performance.".
		 * The 0x000F is configured via snps,incr-burst-type-adjustment
		 * (which despite the name is Layerscape-specific), so below
		 * line only manipulates the upper 16 bits.
		 */
		clrsetbits_le32(IOMEM(res.start) + DWC3_GSBUSCFG0,
				DWC3_GSBUSCFG0_CACHETYPE_MASK,
				FIELD_PREP(DWC3_GSBUSCFG0_CACHETYPE_MASK, 0x2222));
	}
}

static int ls1046a_init(void)
{
	if (!cpu_is_ls1046a())
		return -EINVAL;

	ls1046a_bootsource_init();
	ls1046a_setup_icids();
	layerscape_register_pbl_image_handler();
	layerscape_usb_enable_snooping();

	return 0;
}

static int layerscape_init(void)
{
	struct device_node *root;

	root = of_get_root_node();
	if (root) {
		__layerscape_soc_type = layerscape_soc_from_dt();
		if (!__layerscape_soc_type)
			return 0;
	}

	switch (__layerscape_soc_type) {
	case LAYERSCAPE_SOC_LS1021A:
		return ls1021a_init();
	case LAYERSCAPE_SOC_LS1028A:
		return ls1028a_init();
	case LAYERSCAPE_SOC_LS1046A:
		return ls1046a_init();
	}

	return 0;
}
postcore_initcall(layerscape_init);