Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / arch / powerpc / boot / treeboot-akebono.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright © 2013 Tony Breeds IBM Corporation
4  * Copyright © 2013 Alistair Popple IBM Corporation
5  *
6  * Based on earlier code:
7  *   Copyright (C) Paul Mackerras 1997.
8  *
9  *   Matt Porter <mporter@kernel.crashing.org>
10  *   Copyright 2002-2005 MontaVista Software Inc.
11  *
12  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
13  *   Copyright (c) 2003, 2004 Zultys Technologies
14  *
15  *    Copyright 2007 David Gibson, IBM Corporation.
16  *    Copyright 2010 Ben. Herrenschmidt, IBM Corporation.
17  *    Copyright © 2011 David Kleikamp IBM Corporation
18  */
19 #include <stdarg.h>
20 #include <stddef.h>
21 #include "types.h"
22 #include "elf.h"
23 #include "string.h"
24 #include "stdlib.h"
25 #include "stdio.h"
26 #include "page.h"
27 #include "ops.h"
28 #include "reg.h"
29 #include "io.h"
30 #include "dcr.h"
31 #include "4xx.h"
32 #include "44x.h"
33 #include "libfdt.h"
34
35 BSS_STACK(4096);
36
37 #define SPRN_PIR        0x11E   /* Processor Identification Register */
38 #define USERDATA_LEN    256     /* Length of userdata passed in by PIBS */
39 #define MAX_RANKS       0x4
40 #define DDR3_MR0CF      0x80010011U
41 #define CCTL0_MCO2      0x8000080FU
42 #define CCTL0_MCO3      0x80000810U
43 #define CCTL0_MCO4      0x80000811U
44 #define CCTL0_MCO5      0x80000812U
45 #define CCTL0_MCO6      0x80000813U
46
47 static unsigned long long ibm_akebono_memsize;
48 static long long unsigned mac_addr;
49
50 static unsigned long long ibm_akebono_detect_memsize(void)
51 {
52         u32 reg;
53         unsigned i;
54         unsigned long long memsize = 0;
55
56         for (i = 0; i < MAX_RANKS; i++) {
57                 reg = mfdcrx(DDR3_MR0CF + i);
58
59                 if (!(reg & 1))
60                         continue;
61
62                 reg &= 0x0000f000;
63                 reg >>= 12;
64                 memsize += (0x800000ULL << reg);
65         }
66
67         return memsize;
68 }
69
70 static void ibm_akebono_fixups(void)
71 {
72         void *emac;
73         u32 reg;
74
75         dt_fixup_memory(0x0ULL,  ibm_akebono_memsize);
76
77         /* Fixup the SD timeout frequency */
78         mtdcrx(CCTL0_MCO4, 0x1);
79
80         /* Disable SD high-speed mode (which seems to be broken) */
81         reg = mfdcrx(CCTL0_MCO2) & ~0x2;
82         mtdcrx(CCTL0_MCO2, reg);
83
84         /* Set the MAC address */
85         emac = finddevice("/plb/opb/ethernet");
86         if (emac > 0) {
87                 if (mac_addr)
88                         setprop(emac, "local-mac-address",
89                                 ((u8 *) &mac_addr) + 2 , 6);
90         }
91 }
92
93 void platform_init(char *userdata)
94 {
95         unsigned long end_of_ram, avail_ram;
96         u32 pir_reg;
97         int node, size;
98         const u32 *timebase;
99         int len, i, userdata_len;
100         char *end;
101
102         userdata[USERDATA_LEN - 1] = '\0';
103         userdata_len = strlen(userdata);
104         for (i = 0; i < userdata_len - 15; i++) {
105                 if (strncmp(&userdata[i], "local-mac-addr=", 15) == 0) {
106                         if (i > 0 && userdata[i - 1] != ' ') {
107                                 /* We've only found a substring ending
108                                  * with local-mac-addr so this isn't
109                                  * our mac address. */
110                                 continue;
111                         }
112
113                         mac_addr = strtoull(&userdata[i + 15], &end, 16);
114
115                         /* Remove the "local-mac-addr=<...>" from the kernel
116                          * command line, including the tailing space if
117                          * present. */
118                         if (*end == ' ')
119                                 end++;
120
121                         len = ((int) end) - ((int) &userdata[i]);
122                         memmove(&userdata[i], end,
123                                 userdata_len - (len + i) + 1);
124                         break;
125                 }
126         }
127
128         loader_info.cmdline = userdata;
129         loader_info.cmdline_len = 256;
130
131         ibm_akebono_memsize = ibm_akebono_detect_memsize();
132         if (ibm_akebono_memsize >> 32)
133                 end_of_ram = ~0UL;
134         else
135                 end_of_ram = ibm_akebono_memsize;
136         avail_ram = end_of_ram - (unsigned long)_end;
137
138         simple_alloc_init(_end, avail_ram, 128, 64);
139         platform_ops.fixups = ibm_akebono_fixups;
140         platform_ops.exit = ibm44x_dbcr_reset;
141         pir_reg = mfspr(SPRN_PIR);
142
143         /* Make sure FDT blob is sane */
144         if (fdt_check_header(_dtb_start) != 0)
145                 fatal("Invalid device tree blob\n");
146
147         node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
148                                              "cpu", sizeof("cpu"));
149         if (!node)
150                 fatal("Cannot find cpu node\n");
151         timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
152         if (timebase && (size == 4))
153                 timebase_period_ns = 1000000000 / *timebase;
154
155         fdt_set_boot_cpuid_phys(_dtb_start, pir_reg);
156         fdt_init(_dtb_start);
157
158         serial_console_init();
159 }