source: rtems/c/src/lib/libbsp/powerpc/qoriq/startup/bspsmp.c @ f2e6c3e

4.115
Last change on this file since f2e6c3e was f2e6c3e, checked in by Sebastian Huber <sebastian.huber@…>, on 01/13/15 at 10:38:18

bsp/qoriq: Add T2080RDB and T4240RDB variants

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 * Copyright (c) 2013-2015 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <rtems/score/smpimpl.h>
16
17#include <libcpu/powerpc-utility.h>
18
19#include <bsp.h>
20#include <bsp/mmu.h>
21#include <bsp/fatal.h>
22#include <bsp/qoriq.h>
23#include <bsp/vectors.h>
24#include <bsp/bootcard.h>
25#include <bsp/irq-generic.h>
26#include <bsp/linker-symbols.h>
27
28LINKER_SYMBOL(bsp_exc_vector_base);
29
30#if QORIQ_THREAD_COUNT > 1
31void _start_thread(void);
32#endif
33
34void _start_secondary_processor(void);
35
36#define IPI_INDEX 0
37
38#define TLB_BEGIN (3 * QORIQ_TLB1_ENTRY_COUNT / 4)
39
40#define TLB_END QORIQ_TLB1_ENTRY_COUNT
41
42#define TLB_COUNT (TLB_END - TLB_BEGIN)
43
44/*
45 * These values can be obtained with the debugger or a look into the
46 * U-Boot sources (arch/powerpc/cpu/mpc85xx/release.S).
47 */
48#define BOOT_BEGIN U_BOOT_BOOT_PAGE_BEGIN
49#define BOOT_LAST U_BOOT_BOOT_PAGE_LAST
50#define SPIN_TABLE (BOOT_BEGIN + U_BOOT_BOOT_PAGE_SPIN_OFFSET)
51
52typedef struct {
53  uint32_t addr_upper;
54  uint32_t addr_lower;
55  uint32_t r3_upper;
56  uint32_t r3_lower;
57  uint32_t reserved_0;
58  uint32_t pir;
59  uint32_t r6_upper;
60  uint32_t r6_lower;
61  uint32_t reserved_1[8];
62} uboot_spin_table;
63
64#if QORIQ_THREAD_COUNT > 1
65static bool is_started_by_u_boot(uint32_t cpu_index)
66{
67  return cpu_index % QORIQ_THREAD_COUNT == 0;
68}
69
70void qoriq_start_thread(void)
71{
72  const Per_CPU_Control *cpu_self = _Per_CPU_Get();
73
74  ppc_exc_initialize_interrupt_stack(
75    (uintptr_t) cpu_self->interrupt_stack_low,
76    rtems_configuration_get_interrupt_stack_size()
77  );
78
79  bsp_interrupt_facility_initialize();
80
81  _SMP_Start_multitasking_on_secondary_processor();
82}
83#endif
84
85static void start_thread_if_necessary(uint32_t cpu_index_self)
86{
87#if QORIQ_THREAD_COUNT > 1
88  uint32_t i;
89
90  for (i = 1; i < QORIQ_THREAD_COUNT; ++i) {
91    uint32_t cpu_index_next = cpu_index_self + i;
92
93    if (
94      is_started_by_u_boot(cpu_index_self)
95        && cpu_index_next < rtems_configuration_get_maximum_processors()
96        && _SMP_Should_start_processor(cpu_index_next)
97    ) {
98      /* Thread Initial Next Instruction Address (INIA) */
99      PPC_SET_THREAD_MGMT_REGISTER(321, (uint32_t) _start_thread);
100
101      /* Thread Initial Machine State (IMSR) */
102      PPC_SET_THREAD_MGMT_REGISTER(289, QORIQ_INITIAL_MSR);
103
104      /* Thread Enable Set (TENS) */
105      PPC_SET_SPECIAL_PURPOSE_REGISTER(438, 1U << i);
106    }
107  }
108#endif
109}
110
111void bsp_start_on_secondary_processor(void)
112{
113  uint32_t cpu_index_self = _SMP_Get_current_processor();
114  const Per_CPU_Control *cpu_self = _Per_CPU_Get_by_index(cpu_index_self);
115
116  ppc_exc_initialize_with_vector_base(
117    (uintptr_t) cpu_self->interrupt_stack_low,
118    rtems_configuration_get_interrupt_stack_size(),
119    bsp_exc_vector_base
120  );
121
122  /* Now it is possible to make the code execute only */
123  qoriq_mmu_change_perm(
124    FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SX,
125    FSL_EIS_MAS3_SX,
126    FSL_EIS_MAS3_SR
127  );
128
129  bsp_interrupt_facility_initialize();
130
131  start_thread_if_necessary(cpu_index_self);
132
133  _SMP_Start_multitasking_on_secondary_processor();
134}
135
136static void bsp_inter_processor_interrupt(void *arg)
137{
138  _SMP_Inter_processor_interrupt_handler();
139}
140
141uint32_t _CPU_SMP_Initialize(void)
142{
143  if (rtems_configuration_get_maximum_processors() > 0) {
144    qoriq_mmu_context mmu_context;
145
146    qoriq_mmu_context_init(&mmu_context);
147    qoriq_mmu_add(
148      &mmu_context,
149      BOOT_BEGIN,
150      BOOT_LAST,
151      0,
152      0,
153      FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
154      0
155    );
156    qoriq_mmu_partition(&mmu_context, TLB_COUNT);
157    qoriq_mmu_write_to_tlb1(&mmu_context, TLB_BEGIN);
158  }
159
160  start_thread_if_necessary(0);
161
162  return QORIQ_CPU_COUNT;
163}
164
165static void release_processor(uboot_spin_table *spin_table, uint32_t cpu_index)
166{
167  const Per_CPU_Control *cpu = _Per_CPU_Get_by_index(cpu_index);
168
169  spin_table->pir = cpu_index;
170  spin_table->r3_lower = (uint32_t) cpu->interrupt_stack_high;
171  spin_table->addr_upper = 0;
172  rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
173  ppc_synchronize_data();
174  spin_table->addr_lower = (uint32_t) _start_secondary_processor;
175  rtems_cache_flush_multiple_data_lines(spin_table, sizeof(*spin_table));
176}
177
178bool _CPU_SMP_Start_processor(uint32_t cpu_index)
179{
180#if QORIQ_THREAD_COUNT > 1
181  if (is_started_by_u_boot(cpu_index)) {
182    uboot_spin_table *spin_table =
183      &((uboot_spin_table *) SPIN_TABLE)[cpu_index / 2 - 1];
184
185    release_processor(spin_table, cpu_index);
186
187    return true;
188  } else {
189    return _SMP_Should_start_processor(cpu_index - 1);
190  }
191#else
192  uboot_spin_table *spin_table = (uboot_spin_table *) SPIN_TABLE;
193
194  release_processor(spin_table, cpu_index);
195
196  return true;
197#endif
198}
199
200static void mmu_config_undo(void)
201{
202  int i;
203
204  for (i = TLB_BEGIN; i < TLB_END; ++i) {
205    qoriq_tlb1_invalidate(i);
206  }
207}
208
209void _CPU_SMP_Finalize_initialization(uint32_t cpu_count)
210{
211  if (rtems_configuration_get_maximum_processors() > 0) {
212    mmu_config_undo();
213  }
214
215  if (cpu_count > 1) {
216    rtems_status_code sc;
217
218    sc = rtems_interrupt_handler_install(
219      QORIQ_IRQ_IPI_0,
220      "IPI",
221      RTEMS_INTERRUPT_UNIQUE,
222      bsp_inter_processor_interrupt,
223      NULL
224    );
225    if (sc != RTEMS_SUCCESSFUL) {
226      bsp_fatal(QORIQ_FATAL_SMP_IPI_HANDLER_INSTALL);
227    }
228  }
229}
230
231void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
232{
233  qoriq.pic.ipidr [IPI_INDEX].reg = 1U << target_processor_index;
234}
Note: See TracBrowser for help on using the repository browser.