1/*
2 * Initialization and support routines for self-booting compressed
3 * image.
4 *
5 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * $Id: min_osl.c,v 1.28 2009/07/10 22:43:40 Exp $
20 */
21
22#include <typedefs.h>
23#include <bcmdefs.h>
24#include <osl.h>
25#include <bcmdevs.h>
26#include <bcmutils.h>
27#include <siutils.h>
28#include <hndcpu.h>
29#include <sbchipc.h>
30#include <hndchipc.h>
31
32/* Global ASSERT type */
33uint32 g_assert_type = 0;
34
35#ifdef	mips
36/* Cache support */
37
38/* Cache and line sizes */
39uint __icache_size, __ic_lsize, __dcache_size, __dc_lsize;
40
41static void
42_change_cachability(uint32 cm)
43{
44	uint32 prid, c0reg;
45
46	c0reg = MFC0(C0_CONFIG, 0);
47	c0reg &= ~CONF_CM_CMASK;
48	c0reg |= (cm & CONF_CM_CMASK);
49	MTC0(C0_CONFIG, 0, c0reg);
50	prid = MFC0(C0_PRID, 0);
51	if (BCM330X(prid)) {
52		c0reg = MFC0(C0_BROADCOM, 0);
53		/* Enable icache & dcache */
54		c0reg |= BRCM_IC_ENABLE | BRCM_DC_ENABLE;
55		MTC0(C0_BROADCOM, 0, c0reg);
56	}
57}
58static void (*change_cachability)(uint32);
59
60void
61caches_on(void)
62{
63	uint32 config, config1, r2, tmp;
64	uint start, end, size, lsize;
65
66	config = MFC0(C0_CONFIG, 0);
67	r2 = config & CONF_AR;
68	config1 = MFC0(C0_CONFIG, 1);
69
70	icache_probe(config1, &size, &lsize);
71	__icache_size = size;
72	__ic_lsize = lsize;
73
74	dcache_probe(config1, &size, &lsize);
75	__dcache_size = size;
76	__dc_lsize = lsize;
77
78	/* If caches are not in the default state then
79	 * presume that caches are already init'd
80	 */
81	if ((config & CONF_CM_CMASK) != CONF_CM_UNCACHED) {
82		blast_dcache();
83		blast_icache();
84		return;
85	}
86
87	tmp = R_REG(NULL, (uint32 *)(OSL_UNCACHED(SI_ENUM_BASE + CC_CHIPID)));
88	if (((tmp & CID_PKG_MASK) >> CID_PKG_SHIFT) != HDLSIM_PKG_ID) {
89		/* init icache */
90		start = KSEG0ADDR(caches_on) & 0xff800000;
91		end = (start + __icache_size);
92		MTC0(C0_TAGLO, 0, 0);
93		MTC0(C0_TAGHI, 0, 0);
94		while (start < end) {
95			cache_op(start, Index_Store_Tag_I);
96			start += __ic_lsize;
97		}
98
99		/* init dcache */
100		start = KSEG0ADDR(caches_on) & 0xff800000;
101		end = (start + __dcache_size);
102		if (r2) {
103			/* mips32r2 has the data tags in select 2 */
104			MTC0(C0_TAGLO, 2, 0);
105			MTC0(C0_TAGHI, 2, 0);
106		} else {
107			MTC0(C0_TAGLO, 0, 0);
108			MTC0(C0_TAGHI, 0, 0);
109		}
110		while (start < end) {
111			cache_op(start, Index_Store_Tag_D);
112			start += __dc_lsize;
113		}
114	}
115
116	/* Must be in KSEG1 to change cachability */
117	change_cachability = (void (*)(uint32))KSEG1ADDR(_change_cachability);
118	change_cachability(CONF_CM_CACHABLE_NONCOHERENT);
119}
120
121
122void
123blast_dcache(void)
124{
125	uint32 start, end;
126
127	start = KSEG0ADDR(blast_dcache) & 0xff800000;
128	end = start + __dcache_size;
129
130	while (start < end) {
131		cache_op(start, Index_Writeback_Inv_D);
132		start += __dc_lsize;
133	}
134}
135
136void
137blast_icache(void)
138{
139	uint32 start, end;
140
141	start = KSEG0ADDR(blast_icache) & 0xff800000;
142	end = start + __icache_size;
143
144	while (start < end) {
145		cache_op(start, Index_Invalidate_I);
146		start += __ic_lsize;
147	}
148}
149#endif	/* mips */
150
151/* uart output */
152
153struct serial_struct {
154	unsigned char	*reg_base;
155	unsigned short	reg_shift;
156	int	irq;
157	int	baud_base;
158};
159
160static struct serial_struct min_uart;
161
162#define LOG_BUF_LEN	(1024)
163#define LOG_BUF_MASK	(LOG_BUF_LEN-1)
164static unsigned long log_idx;
165static char log_buf[LOG_BUF_LEN];
166
167
168static inline int
169serial_in(struct serial_struct *info, int offset)
170{
171	return ((int)R_REG(NULL, (uint8 *)(info->reg_base + (offset << info->reg_shift))));
172}
173
174static inline void
175serial_out(struct serial_struct *info, int offset, int value)
176{
177	W_REG(NULL, (uint8 *)(info->reg_base + (offset << info->reg_shift)), value);
178}
179
180void
181putc(int c)
182{
183	uint32 idx;
184
185	/* CR before LF */
186	if (c == '\n')
187		putc('\r');
188
189	/* Store in log buffer */
190	idx = *((uint32 *)OSL_UNCACHED((uintptr)&log_idx));
191	*((char *)OSL_UNCACHED(&log_buf[idx])) = (char)c;
192	*((uint32 *)OSL_UNCACHED((uintptr)&log_idx)) = (idx + 1) & LOG_BUF_MASK;
193
194	/* No UART */
195	if (!min_uart.reg_base)
196		return;
197
198	while (!(serial_in(&min_uart, UART_LSR) & UART_LSR_THRE));
199	serial_out(&min_uart, UART_TX, c);
200}
201
202/* assert & debugging */
203
204#ifdef BCMDBG_ASSERT
205void
206assfail(char *exp, char *file, int line)
207{
208	printf("ASSERT %s file %s line %d\n", exp, file, line);
209}
210#endif /* BCMDBG_ASSERT */
211
212/* general purpose memory allocation */
213
214extern char text_start[], text_end[];
215extern char data_start[], data_end[];
216extern char bss_start[], bss_end[];
217
218static ulong free_mem_ptr = 0;
219static ulong free_mem_ptr_end = 0;
220
221void *
222malloc(uint size)
223{
224	void *p;
225
226	/* Sanity check */
227	if (size < 0)
228		printf("Malloc error\n");
229	if (free_mem_ptr == 0)
230		printf("Memory error\n");
231
232	/* Align */
233	free_mem_ptr = (free_mem_ptr + 3) & ~3;
234
235	p = (void *) free_mem_ptr;
236	free_mem_ptr += size;
237
238	if (free_mem_ptr >= free_mem_ptr_end)
239		printf("Out of memory\n");
240
241	return p;
242}
243
244int
245free(void *where)
246{
247	return 0;
248}
249
250/* get processor cycle count */
251
252#if defined(mips)
253#define	get_cycle_count	get_c0_count
254#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
255#define	get_cycle_count	get_arm_cyclecount
256#endif
257
258uint32
259osl_getcycles(void)
260{
261	return get_cycle_count();
262}
263
264/* microsecond delay */
265
266/* Default to 125 MHz */
267static uint32 cpu_clock = 125000000;
268static uint32 c0counts_per_us = 125000000 / 2000000;
269static uint32 c0counts_per_ms = 125000000 / 2000;
270
271void
272udelay(uint32 us)
273{
274	uint32 curr, lim;
275
276	curr = get_cycle_count();
277	lim = curr + (us * c0counts_per_us);
278
279	if (lim < curr)
280		while (get_cycle_count() > curr)
281			;
282
283	while (get_cycle_count() < lim)
284		;
285}
286
287#ifndef	MIN_DO_TRAP
288
289/* No trap handling in self-decompressing boots */
290extern void trap_init(void);
291
292void
293trap_init(void)
294{
295}
296
297#endif	/* !MIN_DO_TRAP */
298
299static void
300serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
301{
302	int quot;
303
304	if (min_uart.reg_base)
305		return;
306
307	min_uart.reg_base = regs;
308	min_uart.irq = irq;
309	min_uart.baud_base = baud_base / 16;
310	min_uart.reg_shift = reg_shift;
311
312	/* Set baud and 8N1 */
313	quot = (min_uart.baud_base + 57600) / 115200;
314	serial_out(&min_uart, UART_LCR, UART_LCR_DLAB);
315	serial_out(&min_uart, UART_DLL, quot & 0xff);
316	serial_out(&min_uart, UART_DLM, quot >> 8);
317	serial_out(&min_uart, UART_LCR, UART_LCR_WLEN8);
318
319	/* According to the Synopsys website: "the serial clock
320	 * modules must have time to see new register values
321	 * and reset their respective state machines. This
322	 * total time is guaranteed to be no more than
323	 * (2 * baud divisor * 16) clock cycles of the slower
324	 * of the two system clocks. No data should be transmitted
325	 * or received before this maximum time expires."
326	 */
327	udelay(1000);
328}
329
330
331void *
332osl_init()
333{
334	uint32 c0counts_per_cycle;
335	si_t *sih;
336
337	/* Scan backplane */
338	sih = si_kattach(SI_OSH);
339
340	if (sih == NULL)
341		return NULL;
342
343#if defined(mips)
344	si_mips_init(sih, 0);
345	c0counts_per_cycle = 2;
346#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
347	si_arm_init(sih);
348	c0counts_per_cycle = 1;
349#else
350#error "Unknow CPU"
351#endif
352	cpu_clock = si_cpu_clock(sih);
353	c0counts_per_us = cpu_clock / (1000000 * c0counts_per_cycle);
354	c0counts_per_ms = si_cpu_clock(sih) / (1000 * c0counts_per_cycle);
355
356	/* Don't really need to talk to the uart in simulation */
357	if ((sih->chippkg != HDLSIM_PKG_ID) && (sih->chippkg != HWSIM_PKG_ID))
358		si_serial_init(sih, serial_add);
359
360	/* Init malloc */
361	free_mem_ptr = (ulong) bss_end;
362	free_mem_ptr_end = ((ulong)&sih) - 8192;	/* Enough stack? */
363
364	return ((void *)sih);
365}
366
367/* translate bcmerros */
368int
369osl_error(int bcmerror)
370{
371	if (bcmerror)
372		return -1;
373	else
374		return 0;
375}
376