xref: /rk3399_rockchip-uboot/board/broadcom/bcmstb/bcmstb.c (revision f36ea2f6e17621c4d9dd97c4dbfab62d03d061df)
1*f36ea2f6SThomas Fitzsimmons // SPDX-License-Identifier: GPL-2.0+
2*f36ea2f6SThomas Fitzsimmons /*
3*f36ea2f6SThomas Fitzsimmons  * (C) Copyright 2018  Cisco Systems, Inc.
4*f36ea2f6SThomas Fitzsimmons  *
5*f36ea2f6SThomas Fitzsimmons  * Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
6*f36ea2f6SThomas Fitzsimmons  */
7*f36ea2f6SThomas Fitzsimmons 
8*f36ea2f6SThomas Fitzsimmons #include <linux/types.h>
9*f36ea2f6SThomas Fitzsimmons #include <common.h>
10*f36ea2f6SThomas Fitzsimmons #include <asm/io.h>
11*f36ea2f6SThomas Fitzsimmons #include <asm/bootm.h>
12*f36ea2f6SThomas Fitzsimmons #include <mach/sdhci.h>
13*f36ea2f6SThomas Fitzsimmons #include <mach/timer.h>
14*f36ea2f6SThomas Fitzsimmons #include <mmc.h>
15*f36ea2f6SThomas Fitzsimmons #include <fdtdec.h>
16*f36ea2f6SThomas Fitzsimmons 
17*f36ea2f6SThomas Fitzsimmons DECLARE_GLOBAL_DATA_PTR;
18*f36ea2f6SThomas Fitzsimmons 
19*f36ea2f6SThomas Fitzsimmons #define BCMSTB_DATA_SECTION __attribute__((section(".data")))
20*f36ea2f6SThomas Fitzsimmons 
21*f36ea2f6SThomas Fitzsimmons struct bcmstb_boot_parameters bcmstb_boot_parameters BCMSTB_DATA_SECTION;
22*f36ea2f6SThomas Fitzsimmons 
23*f36ea2f6SThomas Fitzsimmons phys_addr_t prior_stage_fdt_address BCMSTB_DATA_SECTION;
24*f36ea2f6SThomas Fitzsimmons 
25*f36ea2f6SThomas Fitzsimmons union reg_value_union {
26*f36ea2f6SThomas Fitzsimmons 	const char *data;
27*f36ea2f6SThomas Fitzsimmons 	const phys_addr_t *address;
28*f36ea2f6SThomas Fitzsimmons };
29*f36ea2f6SThomas Fitzsimmons 
board_init(void)30*f36ea2f6SThomas Fitzsimmons int board_init(void)
31*f36ea2f6SThomas Fitzsimmons {
32*f36ea2f6SThomas Fitzsimmons 	return 0;
33*f36ea2f6SThomas Fitzsimmons }
34*f36ea2f6SThomas Fitzsimmons 
get_board_rev(void)35*f36ea2f6SThomas Fitzsimmons u32 get_board_rev(void)
36*f36ea2f6SThomas Fitzsimmons {
37*f36ea2f6SThomas Fitzsimmons 	return 0;
38*f36ea2f6SThomas Fitzsimmons }
39*f36ea2f6SThomas Fitzsimmons 
reset_cpu(ulong ignored)40*f36ea2f6SThomas Fitzsimmons void reset_cpu(ulong ignored)
41*f36ea2f6SThomas Fitzsimmons {
42*f36ea2f6SThomas Fitzsimmons }
43*f36ea2f6SThomas Fitzsimmons 
print_cpuinfo(void)44*f36ea2f6SThomas Fitzsimmons int print_cpuinfo(void)
45*f36ea2f6SThomas Fitzsimmons {
46*f36ea2f6SThomas Fitzsimmons 	return 0;
47*f36ea2f6SThomas Fitzsimmons }
48*f36ea2f6SThomas Fitzsimmons 
dram_init(void)49*f36ea2f6SThomas Fitzsimmons int dram_init(void)
50*f36ea2f6SThomas Fitzsimmons {
51*f36ea2f6SThomas Fitzsimmons 	if (fdtdec_setup_memory_size() != 0)
52*f36ea2f6SThomas Fitzsimmons 		return -EINVAL;
53*f36ea2f6SThomas Fitzsimmons 
54*f36ea2f6SThomas Fitzsimmons 	return 0;
55*f36ea2f6SThomas Fitzsimmons }
56*f36ea2f6SThomas Fitzsimmons 
dram_init_banksize(void)57*f36ea2f6SThomas Fitzsimmons int dram_init_banksize(void)
58*f36ea2f6SThomas Fitzsimmons {
59*f36ea2f6SThomas Fitzsimmons 	fdtdec_setup_memory_banksize();
60*f36ea2f6SThomas Fitzsimmons 
61*f36ea2f6SThomas Fitzsimmons 	/*
62*f36ea2f6SThomas Fitzsimmons 	 * On this SoC, U-Boot is running as an ELF file.  Change the
63*f36ea2f6SThomas Fitzsimmons 	 * relocation address to CONFIG_SYS_TEXT_BASE, so that in
64*f36ea2f6SThomas Fitzsimmons 	 * setup_reloc, gd->reloc_off works out to 0, effectively
65*f36ea2f6SThomas Fitzsimmons 	 * disabling relocation.  Otherwise U-Boot hangs in the setup
66*f36ea2f6SThomas Fitzsimmons 	 * instructions just before relocate_code in
67*f36ea2f6SThomas Fitzsimmons 	 * arch/arm/lib/crt0.S.
68*f36ea2f6SThomas Fitzsimmons 	 */
69*f36ea2f6SThomas Fitzsimmons 	gd->relocaddr = CONFIG_SYS_TEXT_BASE;
70*f36ea2f6SThomas Fitzsimmons 
71*f36ea2f6SThomas Fitzsimmons 	return 0;
72*f36ea2f6SThomas Fitzsimmons }
73*f36ea2f6SThomas Fitzsimmons 
enable_caches(void)74*f36ea2f6SThomas Fitzsimmons void enable_caches(void)
75*f36ea2f6SThomas Fitzsimmons {
76*f36ea2f6SThomas Fitzsimmons 	/*
77*f36ea2f6SThomas Fitzsimmons 	 * This port assumes that the prior stage bootloader has
78*f36ea2f6SThomas Fitzsimmons 	 * enabled I-cache and D-cache already.  Implementing this
79*f36ea2f6SThomas Fitzsimmons 	 * function silences the warning in the default function.
80*f36ea2f6SThomas Fitzsimmons 	 */
81*f36ea2f6SThomas Fitzsimmons }
82*f36ea2f6SThomas Fitzsimmons 
bcmstb_sdhci_address(u32 alias_index)83*f36ea2f6SThomas Fitzsimmons static const phys_addr_t bcmstb_sdhci_address(u32 alias_index)
84*f36ea2f6SThomas Fitzsimmons {
85*f36ea2f6SThomas Fitzsimmons 	int node = 0;
86*f36ea2f6SThomas Fitzsimmons 	int ret = 0;
87*f36ea2f6SThomas Fitzsimmons 	char sdhci[16] = { 0 };
88*f36ea2f6SThomas Fitzsimmons 	const void *fdt = gd->fdt_blob;
89*f36ea2f6SThomas Fitzsimmons 	const char *path = NULL;
90*f36ea2f6SThomas Fitzsimmons 	struct fdt_resource resource = { 0 };
91*f36ea2f6SThomas Fitzsimmons 
92*f36ea2f6SThomas Fitzsimmons 	if (!fdt) {
93*f36ea2f6SThomas Fitzsimmons 		printf("%s: Invalid gd->fdt_blob\n", __func__);
94*f36ea2f6SThomas Fitzsimmons 		return 0;
95*f36ea2f6SThomas Fitzsimmons 	}
96*f36ea2f6SThomas Fitzsimmons 
97*f36ea2f6SThomas Fitzsimmons 	node = fdt_path_offset(fdt, "/aliases");
98*f36ea2f6SThomas Fitzsimmons 	if (node < 0) {
99*f36ea2f6SThomas Fitzsimmons 		printf("%s: Failed to find /aliases node\n", __func__);
100*f36ea2f6SThomas Fitzsimmons 		return 0;
101*f36ea2f6SThomas Fitzsimmons 	}
102*f36ea2f6SThomas Fitzsimmons 
103*f36ea2f6SThomas Fitzsimmons 	sprintf(sdhci, "sdhci%d", alias_index);
104*f36ea2f6SThomas Fitzsimmons 	path = fdt_getprop(fdt, node, sdhci, NULL);
105*f36ea2f6SThomas Fitzsimmons 	if (!path) {
106*f36ea2f6SThomas Fitzsimmons 		printf("%s: Failed to find alias for %s\n", __func__, sdhci);
107*f36ea2f6SThomas Fitzsimmons 		return 0;
108*f36ea2f6SThomas Fitzsimmons 	}
109*f36ea2f6SThomas Fitzsimmons 
110*f36ea2f6SThomas Fitzsimmons 	node = fdt_path_offset(fdt, path);
111*f36ea2f6SThomas Fitzsimmons 	if (node < 0) {
112*f36ea2f6SThomas Fitzsimmons 		printf("%s: Failed to resolve BCMSTB SDHCI alias\n", __func__);
113*f36ea2f6SThomas Fitzsimmons 		return 0;
114*f36ea2f6SThomas Fitzsimmons 	}
115*f36ea2f6SThomas Fitzsimmons 
116*f36ea2f6SThomas Fitzsimmons 	ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
117*f36ea2f6SThomas Fitzsimmons 				     "host", &resource);
118*f36ea2f6SThomas Fitzsimmons 	if (ret) {
119*f36ea2f6SThomas Fitzsimmons 		printf("%s: Failed to read BCMSTB SDHCI host resource\n",
120*f36ea2f6SThomas Fitzsimmons 		       __func__);
121*f36ea2f6SThomas Fitzsimmons 		return 0;
122*f36ea2f6SThomas Fitzsimmons 	}
123*f36ea2f6SThomas Fitzsimmons 
124*f36ea2f6SThomas Fitzsimmons 	return resource.start;
125*f36ea2f6SThomas Fitzsimmons }
126*f36ea2f6SThomas Fitzsimmons 
board_mmc_init(bd_t * bis)127*f36ea2f6SThomas Fitzsimmons int board_mmc_init(bd_t *bis)
128*f36ea2f6SThomas Fitzsimmons {
129*f36ea2f6SThomas Fitzsimmons 	phys_addr_t sdhci_base_address = 0;
130*f36ea2f6SThomas Fitzsimmons 
131*f36ea2f6SThomas Fitzsimmons 	sdhci_base_address = bcmstb_sdhci_address(CONFIG_BCMSTB_SDHCI_INDEX);
132*f36ea2f6SThomas Fitzsimmons 
133*f36ea2f6SThomas Fitzsimmons 	if (!sdhci_base_address) {
134*f36ea2f6SThomas Fitzsimmons 		sdhci_base_address = BCMSTB_SDHCI_BASE;
135*f36ea2f6SThomas Fitzsimmons 		printf("%s: Assuming BCMSTB SDHCI address: 0x%p\n",
136*f36ea2f6SThomas Fitzsimmons 		       __func__, (void *)sdhci_base_address);
137*f36ea2f6SThomas Fitzsimmons 	}
138*f36ea2f6SThomas Fitzsimmons 
139*f36ea2f6SThomas Fitzsimmons 	debug("BCMSTB SDHCI base address: 0x%p\n", (void *)sdhci_base_address);
140*f36ea2f6SThomas Fitzsimmons 
141*f36ea2f6SThomas Fitzsimmons 	bcmstb_sdhci_init(sdhci_base_address);
142*f36ea2f6SThomas Fitzsimmons 
143*f36ea2f6SThomas Fitzsimmons 	return 0;
144*f36ea2f6SThomas Fitzsimmons }
145*f36ea2f6SThomas Fitzsimmons 
timer_init(void)146*f36ea2f6SThomas Fitzsimmons int timer_init(void)
147*f36ea2f6SThomas Fitzsimmons {
148*f36ea2f6SThomas Fitzsimmons 	gd->arch.timer_rate_hz = readl(BCMSTB_TIMER_FREQUENCY);
149*f36ea2f6SThomas Fitzsimmons 
150*f36ea2f6SThomas Fitzsimmons 	return 0;
151*f36ea2f6SThomas Fitzsimmons }
152*f36ea2f6SThomas Fitzsimmons 
get_tbclk(void)153*f36ea2f6SThomas Fitzsimmons ulong get_tbclk(void)
154*f36ea2f6SThomas Fitzsimmons {
155*f36ea2f6SThomas Fitzsimmons 	return gd->arch.timer_rate_hz;
156*f36ea2f6SThomas Fitzsimmons }
157*f36ea2f6SThomas Fitzsimmons 
get_ticks(void)158*f36ea2f6SThomas Fitzsimmons uint64_t get_ticks(void)
159*f36ea2f6SThomas Fitzsimmons {
160*f36ea2f6SThomas Fitzsimmons 	gd->timebase_h = readl(BCMSTB_TIMER_HIGH);
161*f36ea2f6SThomas Fitzsimmons 	gd->timebase_l = readl(BCMSTB_TIMER_LOW);
162*f36ea2f6SThomas Fitzsimmons 
163*f36ea2f6SThomas Fitzsimmons 	return ((uint64_t)gd->timebase_h << 32) | gd->timebase_l;
164*f36ea2f6SThomas Fitzsimmons }
165*f36ea2f6SThomas Fitzsimmons 
board_late_init(void)166*f36ea2f6SThomas Fitzsimmons int board_late_init(void)
167*f36ea2f6SThomas Fitzsimmons {
168*f36ea2f6SThomas Fitzsimmons 	debug("Arguments from prior stage bootloader:\n");
169*f36ea2f6SThomas Fitzsimmons 	debug("General Purpose Register 0: 0x%x\n", bcmstb_boot_parameters.r0);
170*f36ea2f6SThomas Fitzsimmons 	debug("General Purpose Register 1: 0x%x\n", bcmstb_boot_parameters.r1);
171*f36ea2f6SThomas Fitzsimmons 	debug("General Purpose Register 2: 0x%x\n", bcmstb_boot_parameters.r2);
172*f36ea2f6SThomas Fitzsimmons 	debug("General Purpose Register 3: 0x%x\n", bcmstb_boot_parameters.r3);
173*f36ea2f6SThomas Fitzsimmons 	debug("Stack Pointer Register:     0x%x\n", bcmstb_boot_parameters.sp);
174*f36ea2f6SThomas Fitzsimmons 	debug("Link Register:              0x%x\n", bcmstb_boot_parameters.lr);
175*f36ea2f6SThomas Fitzsimmons 	debug("Assuming timer frequency register at: 0x%p\n",
176*f36ea2f6SThomas Fitzsimmons 	      (void *)BCMSTB_TIMER_FREQUENCY);
177*f36ea2f6SThomas Fitzsimmons 	debug("Read timer frequency (in Hz): %ld\n", gd->arch.timer_rate_hz);
178*f36ea2f6SThomas Fitzsimmons 	debug("Prior stage provided DTB at: 0x%p\n",
179*f36ea2f6SThomas Fitzsimmons 	      (void *)prior_stage_fdt_address);
180*f36ea2f6SThomas Fitzsimmons 
181*f36ea2f6SThomas Fitzsimmons 	/*
182*f36ea2f6SThomas Fitzsimmons 	 * Set fdtcontroladdr in the environment so that scripts can
183*f36ea2f6SThomas Fitzsimmons 	 * refer to it, for example, to reuse it for fdtaddr.
184*f36ea2f6SThomas Fitzsimmons 	 */
185*f36ea2f6SThomas Fitzsimmons 	env_set_hex("fdtcontroladdr", prior_stage_fdt_address);
186*f36ea2f6SThomas Fitzsimmons 
187*f36ea2f6SThomas Fitzsimmons 	/*
188*f36ea2f6SThomas Fitzsimmons 	 * Do not set machid to the machine identifier value provided
189*f36ea2f6SThomas Fitzsimmons 	 * by the prior stage bootloader (bcmstb_boot_parameters.r1)
190*f36ea2f6SThomas Fitzsimmons 	 * because we're using a device tree to boot Linux.
191*f36ea2f6SThomas Fitzsimmons 	 */
192*f36ea2f6SThomas Fitzsimmons 
193*f36ea2f6SThomas Fitzsimmons 	return 0;
194*f36ea2f6SThomas Fitzsimmons }
195