xref: /linux/arch/powerpc/boot/treeboot-akebono.c (revision 95298d63c67673c654c08952672d016212b26054)
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 }
160