162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2013 Tony Breeds IBM Corporation 462306a36Sopenharmony_ci * Copyright © 2013 Alistair Popple IBM Corporation 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based on earlier code: 762306a36Sopenharmony_ci * Copyright (C) Paul Mackerras 1997. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 1062306a36Sopenharmony_ci * Copyright 2002-2005 MontaVista Software Inc. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> 1362306a36Sopenharmony_ci * Copyright (c) 2003, 2004 Zultys Technologies 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Copyright 2007 David Gibson, IBM Corporation. 1662306a36Sopenharmony_ci * Copyright 2010 Ben. Herrenschmidt, IBM Corporation. 1762306a36Sopenharmony_ci * Copyright © 2011 David Kleikamp IBM Corporation 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci#include <stdarg.h> 2062306a36Sopenharmony_ci#include <stddef.h> 2162306a36Sopenharmony_ci#include "types.h" 2262306a36Sopenharmony_ci#include "elf.h" 2362306a36Sopenharmony_ci#include "string.h" 2462306a36Sopenharmony_ci#include "stdlib.h" 2562306a36Sopenharmony_ci#include "stdio.h" 2662306a36Sopenharmony_ci#include "page.h" 2762306a36Sopenharmony_ci#include "ops.h" 2862306a36Sopenharmony_ci#include "reg.h" 2962306a36Sopenharmony_ci#include "io.h" 3062306a36Sopenharmony_ci#include "dcr.h" 3162306a36Sopenharmony_ci#include "4xx.h" 3262306a36Sopenharmony_ci#include "44x.h" 3362306a36Sopenharmony_ci#include "libfdt.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciBSS_STACK(4096); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define SPRN_PIR 0x11E /* Processor Identification Register */ 3862306a36Sopenharmony_ci#define USERDATA_LEN 256 /* Length of userdata passed in by PIBS */ 3962306a36Sopenharmony_ci#define MAX_RANKS 0x4 4062306a36Sopenharmony_ci#define DDR3_MR0CF 0x80010011U 4162306a36Sopenharmony_ci#define CCTL0_MCO2 0x8000080FU 4262306a36Sopenharmony_ci#define CCTL0_MCO3 0x80000810U 4362306a36Sopenharmony_ci#define CCTL0_MCO4 0x80000811U 4462306a36Sopenharmony_ci#define CCTL0_MCO5 0x80000812U 4562306a36Sopenharmony_ci#define CCTL0_MCO6 0x80000813U 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic unsigned long long ibm_akebono_memsize; 4862306a36Sopenharmony_cistatic long long unsigned mac_addr; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic unsigned long long ibm_akebono_detect_memsize(void) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci u32 reg; 5362306a36Sopenharmony_ci unsigned i; 5462306a36Sopenharmony_ci unsigned long long memsize = 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (i = 0; i < MAX_RANKS; i++) { 5762306a36Sopenharmony_ci reg = mfdcrx(DDR3_MR0CF + i); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (!(reg & 1)) 6062306a36Sopenharmony_ci continue; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci reg &= 0x0000f000; 6362306a36Sopenharmony_ci reg >>= 12; 6462306a36Sopenharmony_ci memsize += (0x800000ULL << reg); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return memsize; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void ibm_akebono_fixups(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci void *emac; 7362306a36Sopenharmony_ci u32 reg; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci dt_fixup_memory(0x0ULL, ibm_akebono_memsize); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Fixup the SD timeout frequency */ 7862306a36Sopenharmony_ci mtdcrx(CCTL0_MCO4, 0x1); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Disable SD high-speed mode (which seems to be broken) */ 8162306a36Sopenharmony_ci reg = mfdcrx(CCTL0_MCO2) & ~0x2; 8262306a36Sopenharmony_ci mtdcrx(CCTL0_MCO2, reg); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Set the MAC address */ 8562306a36Sopenharmony_ci emac = finddevice("/plb/opb/ethernet"); 8662306a36Sopenharmony_ci if (emac > 0) { 8762306a36Sopenharmony_ci if (mac_addr) 8862306a36Sopenharmony_ci setprop(emac, "local-mac-address", 8962306a36Sopenharmony_ci ((u8 *) &mac_addr) + 2 , 6); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_civoid platform_init(char *userdata) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci unsigned long end_of_ram, avail_ram; 9662306a36Sopenharmony_ci u32 pir_reg; 9762306a36Sopenharmony_ci int node, size; 9862306a36Sopenharmony_ci const u32 *timebase; 9962306a36Sopenharmony_ci int len, i, userdata_len; 10062306a36Sopenharmony_ci char *end; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci userdata[USERDATA_LEN - 1] = '\0'; 10362306a36Sopenharmony_ci userdata_len = strlen(userdata); 10462306a36Sopenharmony_ci for (i = 0; i < userdata_len - 15; i++) { 10562306a36Sopenharmony_ci if (strncmp(&userdata[i], "local-mac-addr=", 15) == 0) { 10662306a36Sopenharmony_ci if (i > 0 && userdata[i - 1] != ' ') { 10762306a36Sopenharmony_ci /* We've only found a substring ending 10862306a36Sopenharmony_ci * with local-mac-addr so this isn't 10962306a36Sopenharmony_ci * our mac address. */ 11062306a36Sopenharmony_ci continue; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci mac_addr = strtoull(&userdata[i + 15], &end, 16); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* Remove the "local-mac-addr=<...>" from the kernel 11662306a36Sopenharmony_ci * command line, including the tailing space if 11762306a36Sopenharmony_ci * present. */ 11862306a36Sopenharmony_ci if (*end == ' ') 11962306a36Sopenharmony_ci end++; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci len = ((int) end) - ((int) &userdata[i]); 12262306a36Sopenharmony_ci memmove(&userdata[i], end, 12362306a36Sopenharmony_ci userdata_len - (len + i) + 1); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci loader_info.cmdline = userdata; 12962306a36Sopenharmony_ci loader_info.cmdline_len = 256; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci ibm_akebono_memsize = ibm_akebono_detect_memsize(); 13262306a36Sopenharmony_ci if (ibm_akebono_memsize >> 32) 13362306a36Sopenharmony_ci end_of_ram = ~0UL; 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci end_of_ram = ibm_akebono_memsize; 13662306a36Sopenharmony_ci avail_ram = end_of_ram - (unsigned long)_end; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci simple_alloc_init(_end, avail_ram, 128, 64); 13962306a36Sopenharmony_ci platform_ops.fixups = ibm_akebono_fixups; 14062306a36Sopenharmony_ci platform_ops.exit = ibm44x_dbcr_reset; 14162306a36Sopenharmony_ci pir_reg = mfspr(SPRN_PIR); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Make sure FDT blob is sane */ 14462306a36Sopenharmony_ci if (fdt_check_header(_dtb_start) != 0) 14562306a36Sopenharmony_ci fatal("Invalid device tree blob\n"); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", 14862306a36Sopenharmony_ci "cpu", sizeof("cpu")); 14962306a36Sopenharmony_ci if (!node) 15062306a36Sopenharmony_ci fatal("Cannot find cpu node\n"); 15162306a36Sopenharmony_ci timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); 15262306a36Sopenharmony_ci if (timebase && (size == 4)) 15362306a36Sopenharmony_ci timebase_period_ns = 1000000000 / *timebase; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci fdt_set_boot_cpuid_phys(_dtb_start, pir_reg); 15662306a36Sopenharmony_ci fdt_init(_dtb_start); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci serial_console_init(); 15962306a36Sopenharmony_ci} 160