]>
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 | ||
30 | /* reset CPU (jump to 0, without reset) */ | |
31 | void start(void); | |
32 | ||
1e9a164e | 33 | ambapp_dev_irqmp *irqmp = NULL; |
1e9a164e DH |
34 | ambapp_dev_gptimer *gptimer = NULL; |
35 | unsigned int gptimer_irq = 0; | |
36 | int leon3_snooping_avail = 0; | |
37 | ||
38 | struct { | |
39 | gd_t gd_area; | |
40 | bd_t bd; | |
41 | } global_data; | |
42 | ||
43 | /* | |
44 | * Breath some life into the CPU... | |
45 | * | |
1e9a164e | 46 | * Run from FLASH/PROM: |
6052cbab | 47 | * - until memory controller is set up, only registers available |
898cc81d | 48 | * - memory controller has already been setup up, stack can be used |
1e9a164e | 49 | * - no global variables available for writing |
6052cbab | 50 | * - constants available |
1e9a164e | 51 | */ |
1e9a164e DH |
52 | void cpu_init_f(void) |
53 | { | |
e43ce3fc FR |
54 | #ifdef CONFIG_DEBUG_UART |
55 | debug_uart_init(); | |
56 | #endif | |
1e9a164e DH |
57 | } |
58 | ||
898cc81d DH |
59 | /* Routine called from start.S, |
60 | * | |
61 | * Run from FLASH/PROM: | |
62 | * - memory controller has already been setup up, stack can be used | |
63 | * - global variables available for read/writing | |
64 | * - constants avaiable | |
65 | */ | |
1e9a164e DH |
66 | void cpu_init_f2(void) |
67 | { | |
898cc81d DH |
68 | /* Initialize the AMBA Plug & Play bus structure, the bus |
69 | * structure represents the AMBA bus that the CPU is located at. | |
70 | */ | |
71 | ambapp_bus_init(CONFIG_AMBAPP_IOAREA, CONFIG_SYS_CLK_FREQ, &ambapp_plb); | |
1e9a164e DH |
72 | } |
73 | ||
74 | /* | |
75 | * initialize higher level parts of CPU like time base and timers | |
76 | */ | |
77 | int cpu_init_r(void) | |
78 | { | |
79 | ambapp_apbdev apbdev; | |
898cc81d DH |
80 | int index, cpu; |
81 | ambapp_dev_gptimer *timer = NULL; | |
82 | unsigned int bus_freq; | |
1e9a164e DH |
83 | |
84 | /* | |
85 | * Find AMBA APB IRQMP Controller, | |
1e9a164e | 86 | */ |
898cc81d DH |
87 | if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, |
88 | GAISLER_IRQMP, 0, &apbdev) != 1) { | |
89 | panic("%s: IRQ controller not found\n", __func__); | |
90 | return -1; | |
1e9a164e | 91 | } |
898cc81d | 92 | irqmp = (ambapp_dev_irqmp *)apbdev.address; |
1e9a164e | 93 | |
898cc81d DH |
94 | /* initialize the IRQMP */ |
95 | irqmp->ilevel = 0xf; /* all IRQ off */ | |
96 | irqmp->iforce = 0; | |
97 | irqmp->ipend = 0; | |
98 | irqmp->iclear = 0xfffe; /* clear all old pending interrupts */ | |
99 | for (cpu = 0; cpu < 16; cpu++) { | |
100 | /* mask and clear force for all IRQs on CPU[N] */ | |
101 | irqmp->cpu_mask[cpu] = 0; | |
102 | irqmp->cpu_force[cpu] = 0; | |
1e9a164e DH |
103 | } |
104 | ||
898cc81d DH |
105 | /* timer */ |
106 | index = 0; | |
107 | while (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_GPTIMER, | |
108 | index, &apbdev) == 1) { | |
109 | timer = (ambapp_dev_gptimer *)apbdev.address; | |
110 | if (gptimer == NULL) { | |
111 | gptimer = timer; | |
112 | gptimer_irq = apbdev.irq; | |
113 | } | |
114 | ||
115 | /* Different buses may have different frequency, the | |
116 | * frequency of the bus tell in which frequency the timer | |
117 | * prescaler operates. | |
118 | */ | |
119 | bus_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index); | |
1e9a164e | 120 | |
898cc81d DH |
121 | /* initialize prescaler common to all timers to 1MHz */ |
122 | timer->scalar = timer->scalar_reload = | |
123 | (((bus_freq / 1000) + 500) / 1000) - 1; | |
1e9a164e | 124 | |
898cc81d | 125 | index++; |
1e9a164e | 126 | } |
898cc81d DH |
127 | if (!gptimer) { |
128 | printf("%s: gptimer not found!\n", __func__); | |
129 | return 1; | |
1e9a164e | 130 | } |
898cc81d | 131 | return 0; |
1e9a164e DH |
132 | } |
133 | ||
134 | /* Uses Timer 0 to get accurate | |
135 | * pauses. Max 2 raised to 32 ticks | |
136 | * | |
137 | */ | |
138 | void cpu_wait_ticks(unsigned long ticks) | |
139 | { | |
140 | unsigned long start = get_timer(0); | |
141 | while (get_timer(start) < ticks) ; | |
142 | } | |
143 | ||
1c1c7506 | 144 | /* initiate and setup timer0 interrupt to configured HZ. Base clock is 1MHz. |
1e9a164e DH |
145 | * Return irq number for timer int or a negative number for |
146 | * dealing with self | |
147 | */ | |
148 | int timer_interrupt_init_cpu(void) | |
149 | { | |
1c1c7506 | 150 | /* SYS_HZ ticks per second */ |
1e9a164e | 151 | gptimer->e[0].val = 0; |
1c1c7506 | 152 | gptimer->e[0].rld = (TIMER_BASE_CLK / CONFIG_SYS_HZ) - 1; |
1e9a164e | 153 | gptimer->e[0].ctrl = |
f2879f59 DH |
154 | (GPTIMER_CTRL_EN | GPTIMER_CTRL_RS | |
155 | GPTIMER_CTRL_LD | GPTIMER_CTRL_IE); | |
1e9a164e DH |
156 | |
157 | return gptimer_irq; | |
158 | } | |
159 | ||
4148b3d0 DH |
160 | ulong get_tbclk(void) |
161 | { | |
162 | return TIMER_BASE_CLK; | |
163 | } | |
164 | ||
1e9a164e DH |
165 | /* |
166 | * This function is intended for SHORT delays only. | |
167 | */ | |
168 | unsigned long cpu_usec2ticks(unsigned long usec) | |
169 | { | |
1c1c7506 | 170 | if (usec < US_PER_TICK) |
1e9a164e | 171 | return 1; |
1c1c7506 | 172 | return usec / US_PER_TICK; |
1e9a164e DH |
173 | } |
174 | ||
175 | unsigned long cpu_ticks2usec(unsigned long ticks) | |
176 | { | |
1c1c7506 | 177 | return ticks * US_PER_TICK; |
1e9a164e | 178 | } |