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