• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/brcm-boards/bcm947xx/
1/*
2 * Early initialization code for BCM94710 boards
3 *
4 * Copyright (C) 2011, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: prom.c,v 1.8 2010-07-09 06:00:16 $
19 */
20
21#include <linux/version.h>
22#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
23#include <linux/config.h>
24#endif
25#include <linux/init.h>
26#include <linux/kernel.h>
27#include <linux/types.h>
28#include <asm/bootinfo.h>
29#include <asm/cpu.h>
30#include <typedefs.h>
31#include <osl.h>
32#include <bcmutils.h>
33#include <bcmnvram.h>
34#include <bcmendian.h>
35#include <hndsoc.h>
36#include <siutils.h>
37#include <hndcpu.h>
38#include <mipsinc.h>
39#include <mips74k_core.h>
40#ifdef	CONFIG_CFE
41#include <asm/fw/cfe/cfe_api.h>
42#endif
43
44#include "bcm947xx.h"
45
46/* Global SB handle */
47extern si_t *bcm947xx_sih;
48
49/* Convenience */
50#define sih bcm947xx_sih
51
52#define MB      << 20
53
54#ifdef  CONFIG_HIGHMEM
55
56#define EXTVBASE        0xc0000000
57#define ENTRYLO(x)      ((pte_val(pfn_pte((x) >> PAGE_SHIFT, PAGE_KERNEL_UNCACHED)) >> 6) | 1)
58#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
59
60static unsigned long tmp_tlb_ent __initdata;
61#ifdef	CONFIG_CFE
62static int cfe_cons_handle;
63#endif
64
65#if defined(CONFIG_CFE) && defined(CONFIG_EARLY_PRINTK)
66void prom_putchar(char c)
67{
68	while (cfe_write(cfe_cons_handle, &c, 1) == 0)
69		;
70}
71#endif
72
73#ifdef	CONFIG_CFE
74
75static __init void prom_init_cfe(void)
76{
77	uint32_t cfe_ept;
78	uint32_t cfe_handle;
79	uint32_t cfe_eptseal;
80	int argc = fw_arg0;
81	char **envp = (char **) fw_arg2;
82	int *prom_vec = (int *) fw_arg3;
83
84	/*
85	 * Check if a loader was used; if NOT, the 4 arguments are
86	 * what CFE gives us (handle, 0, EPT and EPTSEAL)
87	 */
88	if (argc < 0) {
89		cfe_handle = (uint32_t)argc;
90		cfe_ept = (uint32_t)envp;
91		cfe_eptseal = (uint32_t)prom_vec;
92	} else {
93		if ((int)prom_vec < 0) {
94			/*
95			 * Old loader; all it gives us is the handle,
96			 * so use the "known" entrypoint and assume
97			 * the seal.
98			 */
99			cfe_handle = (uint32_t)prom_vec;
100			cfe_ept = 0xBFC00500;
101			cfe_eptseal = CFE_EPTSEAL;
102		} else {
103			/*
104			 * Newer loaders bundle the handle/ept/eptseal
105			 * Note: prom_vec is in the loader's useg
106			 * which is still alive in the TLB.
107			 */
108			cfe_handle = prom_vec[0];
109			cfe_ept = prom_vec[2];
110			cfe_eptseal = prom_vec[3];
111		}
112	}
113
114	if (cfe_eptseal != CFE_EPTSEAL) {
115		/* too early for panic to do any good */
116		printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
117		while (1) ;
118	}
119
120	cfe_init(cfe_handle, cfe_ept);
121}
122
123static __init void prom_init_console(void)
124{
125	/* Initialize CFE console */
126	cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
127}
128
129static __init void prom_init_cmdline(void)
130{
131	static char buf[COMMAND_LINE_SIZE] __initdata;
132
133	/* Get the kernel command line from CFE */
134	if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
135		buf[COMMAND_LINE_SIZE - 1] = 0;
136		strcpy(arcs_cmdline, buf);
137	}
138
139	/* Force a console handover by adding a console= argument if needed,
140	 * as CFE is not available anymore later in the boot process. */
141	if ((strstr(arcs_cmdline, "console=")) == NULL) {
142		/* Try to read the default serial port used by CFE */
143		if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
144		    || (strncmp("uart", buf, 4)))
145			/* Default to uart0 */
146			strcpy(buf, "uart0");
147
148		/* Compute the new command line */
149		snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
150			 arcs_cmdline, buf[4]);
151	}
152}
153#endif	/* CONFIG_CFE */
154
155/* Initialize the wired register and all tlb entries to
156 * known good state.
157 */
158void __init
159early_tlb_init(void)
160{
161	unsigned long  index;
162	struct cpuinfo_mips *c = &current_cpu_data;
163
164	tmp_tlb_ent = c->tlbsize;
165
166	/* printk(KERN_ALERT "%s: tlb size %ld\n", __FUNCTION__, c->tlbsize); */
167
168	/*
169	* initialize entire TLB to uniqe virtual addresses
170	* but with the PAGE_VALID bit not set
171	*/
172	write_c0_wired(0);
173	write_c0_pagemask(PM_DEFAULT_MASK);
174
175	write_c0_entrylo0(0);   /* not _PAGE_VALID */
176	write_c0_entrylo1(0);
177
178	for (index = 0; index < c->tlbsize; index++) {
179		/* Make sure all entries differ. */
180		write_c0_entryhi(UNIQUE_ENTRYHI(index+32));
181		write_c0_index(index);
182		mtc0_tlbw_hazard();
183		tlb_write_indexed();
184	}
185
186	tlbw_use_hazard();
187
188}
189
190void __init
191add_tmptlb_entry(unsigned long entrylo0, unsigned long entrylo1,
192		 unsigned long entryhi, unsigned long pagemask)
193{
194/* write one tlb entry */
195	--tmp_tlb_ent;
196	write_c0_index(tmp_tlb_ent);
197	write_c0_pagemask(pagemask);
198	write_c0_entryhi(entryhi);
199	write_c0_entrylo0(entrylo0);
200	write_c0_entrylo1(entrylo1);
201	mtc0_tlbw_hazard();
202	tlb_write_indexed();
203	tlbw_use_hazard();
204}
205#endif  /* CONFIG_HIGHMEM */
206
207extern char ram_nvram_buf[];
208
209void __init
210prom_init(void)
211{
212	unsigned long mem, extmem = 0, off, data;
213	unsigned long off1, data1;
214	struct nvram_header *header;
215
216#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
217	/* These are not really being used anywhere - LR */
218	mips_machgroup = MACH_GROUP_BRCM;
219	mips_machtype = MACH_BCM947XX;
220#endif
221
222#ifdef	CONFIG_CFE
223	prom_init_cfe();
224	prom_init_console();
225	prom_init_cmdline();
226#endif
227
228	off = (unsigned long)prom_init;
229	data = *(unsigned long *)prom_init;
230	off1 = off + 4;
231	data1 = *(unsigned long *)off1;
232
233	/* Figure out memory size by finding aliases */
234	for (mem = (1 MB); mem < (128 MB); mem <<= 1) {
235		if ((*(unsigned long *)(off + mem) == data) &&
236			(*(unsigned long *)(off1 + mem) == data1))
237			break;
238	}
239
240#if CONFIG_RAM_SIZE
241	{
242		unsigned long config_mem;
243		config_mem = CONFIG_RAM_SIZE * 0x100000;
244		if (config_mem < mem)
245			mem = config_mem;
246	}
247#endif
248#ifdef  CONFIG_HIGHMEM
249	if (mem == 128 MB) {
250		bool highmem_region = FALSE;
251		int idx;
252
253		sih = si_kattach(SI_OSH);
254		/* save current core index */
255		idx = si_coreidx(sih);
256		if ((si_setcore(sih, DMEMC_CORE_ID, 0) != NULL) ||
257			(si_setcore(sih, DMEMS_CORE_ID, 0) != NULL)) {
258			uint32 addr, size;
259			uint asidx = 0;
260
261			do {
262				si_coreaddrspaceX(sih, asidx, &addr, &size);
263				if (size == 0)
264					break;
265				if (addr == SI_SDRAM_R2) {
266					highmem_region = TRUE;
267					break;
268				}
269				asidx++;
270			} while (1);
271		}
272		/* switch back to previous core */
273		si_setcoreidx(sih, idx);
274
275		if (highmem_region) {
276			early_tlb_init();
277			/* Add one temporary TLB entries to map SDRAM Region 2.
278			*      Physical        Virtual
279			*      0x80000000      0xc0000000      (1st: 256MB)
280			*      0x90000000      0xd0000000      (2nd: 256MB)
281			*/
282			add_tmptlb_entry(ENTRYLO(SI_SDRAM_R2),
283					 ENTRYLO(SI_SDRAM_R2 + (256 MB)),
284					 EXTVBASE, PM_256M);
285
286			off = EXTVBASE + __pa(off);
287			for (extmem = (128 MB); extmem < (512 MB); extmem <<= 1) {
288				if (*(unsigned long *)(off + extmem) == data)
289					break;
290			}
291
292			extmem -= mem;
293			/* Keep tlb entries back in consistent state */
294			early_tlb_init();
295		}
296	}
297#endif  /* CONFIG_HIGHMEM */
298	/* Ignoring the last page when ddr size is 128M. Cached
299	 * accesses to last page is causing the processor to prefetch
300	 * using address above 128M stepping out of the ddr address
301	 * space.
302	 */
303	if (MIPS74K(current_cpu_data.processor_id) && (mem == (128 MB)))
304		mem -= 0x1000;
305
306	/* CFE could have loaded nvram during netboot
307	 * to top 32KB of RAM, Just check for nvram signature
308	 * and copy it to nvram space embedded in linux
309	 * image for later use by nvram driver.
310	 */
311	header = (struct nvram_header *)(KSEG0ADDR(mem - NVRAM_SPACE));
312	if (ltoh32(header->magic) == NVRAM_MAGIC) {
313		uint32 *src = (uint32 *)header;
314		uint32 *dst = (uint32 *)ram_nvram_buf;
315		uint32 i;
316
317		printk("Copying NVRAM bytes: %d from: 0x%p To: 0x%p\n", ltoh32(header->len),
318			src, dst);
319		for (i = 0; i < ltoh32(header->len) && i < NVRAM_SPACE; i += 4)
320			*dst++ = ltoh32(*src++);
321	}
322
323#ifdef CONFIG_BLK_DEV_RAM
324	init_ramdisk(mem);
325#endif
326	add_memory_region(SI_SDRAM_BASE, mem, BOOT_MEM_RAM);
327
328#ifdef  CONFIG_HIGHMEM
329	if (extmem) {
330		/* We should deduct 0x1000 from the second memory
331		 * region, because of the fact that processor does prefetch.
332		 * Now that we are deducting a page from second memory
333		 * region, we could add the earlier deducted 4KB (from first bank)
334		 * to the second region (the fact that 0x80000000 -> 0x88000000
335		 * shadows 0x0 -> 0x8000000)
336		 */
337		if (MIPS74K(current_cpu_data.processor_id) && (mem == (128 MB)))
338			extmem -= 0x1000;
339		add_memory_region(SI_SDRAM_R2 + (128 MB) - 0x1000, extmem, BOOT_MEM_RAM);
340	}
341#endif  /* CONFIG_HIGHMEM */
342}
343
344void __init
345prom_free_prom_memory(void)
346{
347}
348