]>
Commit | Line | Data |
---|---|---|
1e9a164e DH |
1 | /* Initializes CPU and basic hardware such as memory |
2 | * controllers, IRQ controller and system timer 0. | |
3 | * | |
898cc81d DH |
4 | * (C) Copyright 2007, 2015 |
5 | * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com | |
1e9a164e | 6 | * |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
1e9a164e DH |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <asm/asi.h> | |
12 | #include <asm/leon.h> | |
13 | #include <ambapp.h> | |
f2879f59 DH |
14 | #include <grlib/irqmp.h> |
15 | #include <grlib/gptimer.h> | |
e43ce3fc | 16 | #include <debug_uart.h> |
1e9a164e DH |
17 | |
18 | #include <config.h> | |
19 | ||
898cc81d DH |
20 | /* Default Plug&Play I/O area */ |
21 | #ifndef CONFIG_AMBAPP_IOAREA | |
22 | #define CONFIG_AMBAPP_IOAREA AMBA_DEFAULT_IOAREA | |
23 | #endif | |
24 | ||
1c1c7506 DH |
25 | #define TIMER_BASE_CLK 1000000 |
26 | #define US_PER_TICK (1000000 / CONFIG_SYS_HZ) | |
27 | ||
1e9a164e DH |
28 | DECLARE_GLOBAL_DATA_PTR; |
29 | ||
1e9a164e | 30 | ambapp_dev_irqmp *irqmp = NULL; |
1e9a164e DH |
31 | ambapp_dev_gptimer *gptimer = NULL; |
32 | unsigned int gptimer_irq = 0; | |
1e9a164e | 33 | |
1e9a164e DH |
34 | /* |
35 | * Breath some life into the CPU... | |
36 | * | |
1e9a164e | 37 | * Run from FLASH/PROM: |
6052cbab | 38 | * - until memory controller is set up, only registers available |
898cc81d | 39 | * - memory controller has already been setup up, stack can be used |
1e9a164e | 40 | * - no global variables available for writing |
6052cbab | 41 | * - constants available |
1e9a164e | 42 | */ |
1e9a164e DH |
43 | void cpu_init_f(void) |
44 | { | |
e43ce3fc FR |
45 | #ifdef CONFIG_DEBUG_UART |
46 | debug_uart_init(); | |
47 | #endif | |
1e9a164e DH |
48 | } |
49 | ||
898cc81d DH |
50 | /* Routine called from start.S, |
51 | * | |
52 | * Run from FLASH/PROM: | |
53 | * - memory controller has already been setup up, stack can be used | |
54 | * - global variables available for read/writing | |
55 | * - constants avaiable | |
56 | */ | |
1e9a164e DH |
57 | void cpu_init_f2(void) |
58 | { | |
898cc81d DH |
59 | /* Initialize the AMBA Plug & Play bus structure, the bus |
60 | * structure represents the AMBA bus that the CPU is located at. | |
61 | */ | |
62 | ambapp_bus_init(CONFIG_AMBAPP_IOAREA, CONFIG_SYS_CLK_FREQ, &ambapp_plb); | |
1e9a164e DH |
63 | } |
64 | ||
d67269ba FR |
65 | /* If cache snooping is available in hardware the result will be set |
66 | * to 0x800000, otherwise 0. | |
67 | */ | |
68 | static unsigned int snoop_detect(void) | |
69 | { | |
70 | unsigned int result; | |
71 | asm("lda [%%g0] 2, %0" : "=r"(result)); | |
72 | return result & 0x00800000; | |
73 | } | |
74 | ||
e17c5200 FR |
75 | int arch_cpu_init(void) |
76 | { | |
77 | gd->cpu_clk = CONFIG_SYS_CLK_FREQ; | |
78 | gd->bus_clk = CONFIG_SYS_CLK_FREQ; | |
79 | gd->ram_size = CONFIG_SYS_SDRAM_SIZE; | |
80 | ||
d67269ba FR |
81 | gd->arch.snooping_available = snoop_detect(); |
82 | ||
e17c5200 FR |
83 | return 0; |
84 | } | |
85 | ||
1e9a164e DH |
86 | /* |
87 | * initialize higher level parts of CPU like time base and timers | |
88 | */ | |
89 | int cpu_init_r(void) | |
90 | { | |
91 | ambapp_apbdev apbdev; | |
898cc81d DH |
92 | int index, cpu; |
93 | ambapp_dev_gptimer *timer = NULL; | |
94 | unsigned int bus_freq; | |
1e9a164e DH |
95 | |
96 | /* | |
97 | * Find AMBA APB IRQMP Controller, | |
1e9a164e | 98 | */ |
898cc81d DH |
99 | if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, |
100 | GAISLER_IRQMP, 0, &apbdev) != 1) { | |
101 | panic("%s: IRQ controller not found\n", __func__); | |
102 | return -1; | |
1e9a164e | 103 | } |
898cc81d | 104 | irqmp = (ambapp_dev_irqmp *)apbdev.address; |
1e9a164e | 105 | |
898cc81d DH |
106 | /* initialize the IRQMP */ |
107 | irqmp->ilevel = 0xf; /* all IRQ off */ | |
108 | irqmp->iforce = 0; | |
109 | irqmp->ipend = 0; | |
110 | irqmp->iclear = 0xfffe; /* clear all old pending interrupts */ | |
111 | for (cpu = 0; cpu < 16; cpu++) { | |
112 | /* mask and clear force for all IRQs on CPU[N] */ | |
113 | irqmp->cpu_mask[cpu] = 0; | |
114 | irqmp->cpu_force[cpu] = 0; | |
1e9a164e DH |
115 | } |
116 | ||
898cc81d DH |
117 | /* timer */ |
118 | index = 0; | |
119 | while (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, | |
120 | index, &apbdev) == 1) { | |
121 | timer = (ambapp_dev_gptimer *)apbdev.address; | |
122 | if (gptimer == NULL) { | |
123 | gptimer = timer; | |
124 | gptimer_irq = apbdev.irq; | |
125 | } | |
126 | ||
127 | /* Different buses may have different frequency, the | |
128 | * frequency of the bus tell in which frequency the timer | |
129 | * prescaler operates. | |
130 | */ | |
131 | bus_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index); | |
1e9a164e | 132 | |
898cc81d DH |
133 | /* initialize prescaler common to all timers to 1MHz */ |
134 | timer->scalar = timer->scalar_reload = | |
135 | (((bus_freq / 1000) + 500) / 1000) - 1; | |
1e9a164e | 136 | |
898cc81d | 137 | index++; |
1e9a164e | 138 | } |
898cc81d DH |
139 | if (!gptimer) { |
140 | printf("%s: gptimer not found!\n", __func__); | |
141 | return 1; | |
1e9a164e | 142 | } |
898cc81d | 143 | return 0; |
1e9a164e DH |
144 | } |
145 | ||
146 | /* Uses Timer 0 to get accurate | |
147 | * pauses. Max 2 raised to 32 ticks | |
148 | * | |
149 | */ | |
150 | void cpu_wait_ticks(unsigned long ticks) | |
151 | { | |
152 | unsigned long start = get_timer(0); | |
153 | while (get_timer(start) < ticks) ; | |
154 | } | |
155 | ||
1c1c7506 | 156 | /* initiate and setup timer0 interrupt to configured HZ. Base clock is 1MHz. |
1e9a164e DH |
157 | * Return irq number for timer int or a negative number for |
158 | * dealing with self | |
159 | */ | |
160 | int timer_interrupt_init_cpu(void) | |
161 | { | |
1c1c7506 | 162 | /* SYS_HZ ticks per second */ |
1e9a164e | 163 | gptimer->e[0].val = 0; |
1c1c7506 | 164 | gptimer->e[0].rld = (TIMER_BASE_CLK / CONFIG_SYS_HZ) - 1; |
1e9a164e | 165 | gptimer->e[0].ctrl = |
f2879f59 DH |
166 | (GPTIMER_CTRL_EN | GPTIMER_CTRL_RS | |
167 | GPTIMER_CTRL_LD | GPTIMER_CTRL_IE); | |
1e9a164e DH |
168 | |
169 | return gptimer_irq; | |
170 | } | |
171 | ||
4148b3d0 DH |
172 | ulong get_tbclk(void) |
173 | { | |
174 | return TIMER_BASE_CLK; | |
175 | } | |
176 | ||
1e9a164e DH |
177 | /* |
178 | * This function is intended for SHORT delays only. | |
179 | */ | |
180 | unsigned long cpu_usec2ticks(unsigned long usec) | |
181 | { | |
1c1c7506 | 182 | if (usec < US_PER_TICK) |
1e9a164e | 183 | return 1; |
1c1c7506 | 184 | return usec / US_PER_TICK; |
1e9a164e DH |
185 | } |
186 | ||
187 | unsigned long cpu_ticks2usec(unsigned long ticks) | |
188 | { | |
1c1c7506 | 189 | return ticks * US_PER_TICK; |
1e9a164e | 190 | } |