18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RouterBoard 500 specific prom routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr> 78c2ecf20Sopenharmony_ci * Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org> 88c2ecf20Sopenharmony_ci * Felix Fietkau <nbd@openwrt.org> 98c2ecf20Sopenharmony_ci * Florian Fainelli <florian@openwrt.org> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/export.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/console.h> 178c2ecf20Sopenharmony_ci#include <linux/memblock.h> 188c2ecf20Sopenharmony_ci#include <linux/ioport.h> 198c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 228c2ecf20Sopenharmony_ci#include <asm/mach-rc32434/ddr.h> 238c2ecf20Sopenharmony_ci#include <asm/mach-rc32434/prom.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciunsigned int idt_cpu_freq = 132000000; 268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(idt_cpu_freq); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct resource ddr_reg[] = { 298c2ecf20Sopenharmony_ci { 308c2ecf20Sopenharmony_ci .name = "ddr-reg", 318c2ecf20Sopenharmony_ci .start = DDR0_PHYS_ADDR, 328c2ecf20Sopenharmony_ci .end = DDR0_PHYS_ADDR + sizeof(struct ddr_ram), 338c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci /* No prom memory to free */ 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline int match_tag(char *arg, const char *tag) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return strncmp(arg, tag, strlen(tag)) == 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline unsigned long tag2ul(char *arg, const char *tag) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci char *num; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci num = arg + strlen(tag); 528c2ecf20Sopenharmony_ci return simple_strtoul(num, 0, 10); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_civoid __init prom_setup_cmdline(void) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci static char cmd_line[COMMAND_LINE_SIZE] __initdata; 588c2ecf20Sopenharmony_ci char *cp, *board; 598c2ecf20Sopenharmony_ci int prom_argc; 608c2ecf20Sopenharmony_ci char **prom_argv; 618c2ecf20Sopenharmony_ci int i; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci prom_argc = fw_arg0; 648c2ecf20Sopenharmony_ci prom_argv = (char **) fw_arg1; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci cp = cmd_line; 678c2ecf20Sopenharmony_ci /* Note: it is common that parameters start 688c2ecf20Sopenharmony_ci * at argv[1] and not argv[0], 698c2ecf20Sopenharmony_ci * however, our elf loader starts at [0] */ 708c2ecf20Sopenharmony_ci for (i = 0; i < prom_argc; i++) { 718c2ecf20Sopenharmony_ci if (match_tag(prom_argv[i], FREQ_TAG)) { 728c2ecf20Sopenharmony_ci idt_cpu_freq = tag2ul(prom_argv[i], FREQ_TAG); 738c2ecf20Sopenharmony_ci continue; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci#ifdef IGNORE_CMDLINE_MEM 768c2ecf20Sopenharmony_ci /* parses out the "mem=xx" arg */ 778c2ecf20Sopenharmony_ci if (match_tag(prom_argv[i], MEM_TAG)) 788c2ecf20Sopenharmony_ci continue; 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci if (i > 0) 818c2ecf20Sopenharmony_ci *(cp++) = ' '; 828c2ecf20Sopenharmony_ci if (match_tag(prom_argv[i], BOARD_TAG)) { 838c2ecf20Sopenharmony_ci board = prom_argv[i] + strlen(BOARD_TAG); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (match_tag(board, BOARD_RB532A)) 868c2ecf20Sopenharmony_ci mips_machtype = MACH_MIKROTIK_RB532A; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci mips_machtype = MACH_MIKROTIK_RB532; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci strcpy(cp, prom_argv[i]); 928c2ecf20Sopenharmony_ci cp += strlen(prom_argv[i]); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci *(cp++) = ' '; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci i = strlen(arcs_cmdline); 978c2ecf20Sopenharmony_ci if (i > 0) { 988c2ecf20Sopenharmony_ci *(cp++) = ' '; 998c2ecf20Sopenharmony_ci strcpy(cp, arcs_cmdline); 1008c2ecf20Sopenharmony_ci cp += strlen(arcs_cmdline); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci cmd_line[COMMAND_LINE_SIZE - 1] = '\0'; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci strcpy(arcs_cmdline, cmd_line); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid __init prom_init(void) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct ddr_ram __iomem *ddr; 1108c2ecf20Sopenharmony_ci phys_addr_t memsize; 1118c2ecf20Sopenharmony_ci phys_addr_t ddrbase; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ddr = ioremap(ddr_reg[0].start, 1148c2ecf20Sopenharmony_ci ddr_reg[0].end - ddr_reg[0].start); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!ddr) { 1178c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to remap DDR register\n"); 1188c2ecf20Sopenharmony_ci return; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ddrbase = (phys_addr_t)&ddr->ddrbase; 1228c2ecf20Sopenharmony_ci memsize = (phys_addr_t)&ddr->ddrmask; 1238c2ecf20Sopenharmony_ci memsize = 0 - memsize; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci prom_setup_cmdline(); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* give all RAM to boot allocator, 1288c2ecf20Sopenharmony_ci * except for the first 0x400 and the last 0x200 bytes */ 1298c2ecf20Sopenharmony_ci memblock_add(ddrbase + 0x400, memsize - 0x600); 1308c2ecf20Sopenharmony_ci} 131