X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/f203cd4d6d968d81d98c76ef992ae91c17552b03..04f0dfd2d31a2ac3d2fcd389c6c693c524bb8d02:/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c index 947b5b96a..c9d53ad32 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c @@ -1,135 +1,179 @@ -/***************************************************************************** - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2003 ADMtek Incorporated. - * daniell@admtek.com.tw - * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) +/* + * $Id$ * - * ######################################################################## + * Copyright (C) 2007 OpenWrt.org + * Copyright (C) 2007 Gabor Juhos * - * This program is free software; you can distribute it and/or modify it - * under the terms of the GNU General Public License (Version 2) as - * published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. * - * ######################################################################## - * - *****************************************************************************/ + */ -#include #include -#include -#include -#include -#include +#include +#include #include -#include -#include - -#include +#include -extern char *prom_getenv(char *envname); -void prom_printf(char *, ...); +#include +#include +#include +#include -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) +#define SWITCH_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r)) +#define SWITCH_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v) -#define ADM5120_MEMCTRL 0x1200001c -#define ADM5120_MEMCTRL_SDRAM_MASK 0x7 +#define MPMC_READ(r) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r)) +#define MPMC_WRITE(r,v) *(u32 *)(KSEG1ADDR(ADM5120_SWITCH_BASE)+(r))=(v) -static const unsigned long adm_sdramsize[] __initdata = { - 0x0, /* Reserved */ - 0x0400000, /* 4Mb */ - 0x0800000, /* 8Mb */ - 0x1000000, /* 16Mb */ - 0x4000000, /* 64Mb */ - 0x8000000, /* 128Mb */ -}; +#if 1 +# define mem_dbg(f, a...) printk("mem_detect: " f, ## a) +#else +# define mem_dbg(f, a...) +#endif -/* determined physical memory size, not overridden by command line args */ -unsigned long physical_memsize = 0L; +#define MEM_WR_DELAY 10000 /* 0.01 usec */ -struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; +unsigned long adm5120_memsize; -struct prom_pmemblock * __init prom_getmdesc(void) +static int __init mem_check_pattern(u8 *addr, unsigned long offs) { - char *memsize_str; - unsigned int memsize; - char cmdline[CL_SIZE], *ptr; + volatile u32 *p1 = (volatile u32 *)addr; + volatile u32 *p2 = (volatile u32 *)(addr+offs); + u32 t,u,v; - memsize_str = prom_getenv("memsize"); + /* save original value */ + t = *p1; + u = *p2; - if (!memsize_str) - { - prom_printf("memsize not set in boot prom, set to default (8Mb)\n"); - physical_memsize = 0x00800000; - } - else -#ifdef DEBUG - prom_printf("prom_memsize = %s\n", memsize_str); -#endif - physical_memsize = simple_strtol(memsize_str, NULL, 0); + if (t != u) + return 0; - /* Check the command line for a memsize directive that overrides - * the physical/default amount */ - strcpy(cmdline, arcs_cmdline); - ptr = strstr(cmdline, "memsize="); - if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) - ptr = strstr(ptr, " memsize="); + v = 0x55555555; + if (u == v) + v = 0xAAAAAAAA; - if (ptr) - memsize = memparse(ptr + 8, &ptr); - else - memsize = physical_memsize; + mem_dbg("write 0x%08X to 0x%08lX\n", v, (unsigned long)p1); - memset(mdesc, 0, sizeof(mdesc)); + *p1 = v; + mem_dbg("delay %d ns\n", MEM_WR_DELAY); + adm5120_ndelay(MEM_WR_DELAY); + u = *p2; - mdesc[0].type = BOOT_MEM_RAM; - mdesc[0].base = CPHYSADDR(PFN_ALIGN(&_end)); - mdesc[0].size = memsize - mdesc[0].base; + mem_dbg("pattern at 0x%08lX is 0x%08X\n", (unsigned long)p2, u); - return &mdesc[0]; + /* restore original value */ + *p1 = t; + + return (v == u); } -void __init prom_meminit(void) +static void __init adm5120_detect_memsize(void) { - struct prom_pmemblock *p; - - p = prom_getmdesc(); - - while (p->size) - { - long type; - unsigned long base, size; - base = p->base; - type = p->type, - size = p->size; - add_memory_region(base, size, type); - p++; + u32 memctrl; + u32 size, maxsize; + u8 *p; + + memctrl = SWITCH_READ(SWITCH_REG_MEMCTRL); + switch (memctrl & MEMCTRL_SDRS_MASK) { + case MEMCTRL_SDRS_4M: + maxsize = 4 << 20; + break; + case MEMCTRL_SDRS_8M: + maxsize = 8 << 20; + break; + case MEMCTRL_SDRS_16M: + maxsize = 16 << 20; + break; + default: + maxsize = 64 << 20; + break; } -} -#if 0 -void __init prom_meminit(void) -{ - unsigned long base = CPHYSADDR(PFN_ALIGN(&_end)); - unsigned long size; + /* disable buffers for both SDRAM banks */ + mem_dbg("disable buffers for both banks\n"); + MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) & ~DC_BE); + MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) & ~DC_BE); + + mem_dbg("checking for %uMB chip in 1st bank\n", maxsize >> 20); + + /* detect size of the 1st SDRAM bank */ + p = (u8 *)KSEG1ADDR(0); + for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) { + if (mem_check_pattern(p, size)) { + /* mirrored address */ + mem_dbg("mirrored data found at offset 0x%08X\n", size); + break; + } + } + + mem_dbg("chip size in 1st bank is %uMB\n", size >> 20); + adm5120_memsize = size; - u32 memctrl = *(u32*)KSEG1ADDR(ADM5120_MEMCTRL); - size = adm_sdramsize[memctrl & ADM5120_MEMCTRL_SDRAM_MASK]; - add_memory_region(base, size-base, BOOT_MEM_RAM); + if (size != maxsize) + /* 2nd bank is not supported */ + goto out; + + if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0) + /* 2nd bank is disabled */ + goto out; + + /* + * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip + * are missing. + */ + mem_dbg("check presence of 2nd bank\n"); + + p = (u8 *)KSEG1ADDR(maxsize+size-4); + if (mem_check_pattern(p, 0)) { + adm5120_memsize += size; + } + + if (maxsize != size) { + /* adjusting MECTRL register */ + memctrl &= ~(MEMCTRL_SDRS_MASK); + switch (size>>20) { + case 4: + memctrl |= MEMCTRL_SDRS_4M; + break; + case 8: + memctrl |= MEMCTRL_SDRS_8M; + break; + case 16: + memctrl |= MEMCTRL_SDRS_16M; + break; + default: + memctrl |= MEMCTRL_SDRS_64M; + break; + } + SWITCH_WRITE(SWITCH_REG_MEMCTRL, memctrl); + } + +out: + /* reenable buffer for both SDRAM banks */ + mem_dbg("enable buffers for both banks\n"); + MPMC_WRITE(MPMC_REG_DC0, MPMC_READ(MPMC_REG_DC0) | DC_BE); + MPMC_WRITE(MPMC_REG_DC1, MPMC_READ(MPMC_REG_DC1) | DC_BE); + + mem_dbg("%dx%uMB memory found\n", (adm5120_memsize == size) ? 1 : 2 , + size >>20); } -#endif -void __init prom_free_prom_memory(void) +void __init adm5120_mem_init(void) { - /* We do not have to prom memory to free */ + adm5120_detect_memsize(); + add_memory_region(0, adm5120_memsize, BOOT_MEM_RAM); }