source: rtems/bsps/arm/imx/start/bspstart.c @ 7b2d569

Last change on this file since 7b2d569 was 7b2d569, checked in by Sebastian Huber <sebastian.huber@…>, on 07/09/21 at 08:39:01

bsp/imx: Fix SMP start

Flush imx_gic_dist_base so that secondary processors can use the right
address.

  • Property mode set to 100644
File size: 4.0 KB
Line 
1/*
2 * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@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 <bsp.h>
16#include <bsp/bootcard.h>
17#include <bsp/fatal.h>
18#include <bsp/fdt.h>
19#include <bsp/irq-generic.h>
20#include <bsp/linker-symbols.h>
21#include <dev/clock/arm-generic-timer.h>
22#include <libcpu/arm-cp15.h>
23
24#include <libfdt.h>
25
26#define MAGIC_IRQ_OFFSET 32
27
28void *imx_get_reg_of_node(const void *fdt, int node)
29{
30  int len;
31  const uint32_t *val;
32
33  val = fdt_getprop(fdt, node, "reg", &len);
34  if (val == NULL || len < 4) {
35    return NULL;
36  }
37
38  return (void *) fdt32_to_cpu(val[0]);
39}
40
41rtems_vector_number imx_get_irq_of_node(
42  const void *fdt,
43  int node,
44  size_t index
45)
46{
47  int len;
48  const uint32_t *val;
49
50  val = fdt_getprop(fdt, node, "interrupts", &len);
51  if (val == NULL || len < (int) ((index + 1) * 12)) {
52    return BSP_INTERRUPT_VECTOR_INVALID;
53  }
54
55  return fdt32_to_cpu(val[index * 3 + 1]) + MAGIC_IRQ_OFFSET;
56}
57
58uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
59{
60  return intr[1] + MAGIC_IRQ_OFFSET;
61}
62
63static bool imx_is_imx6(const void *fdt)
64{
65  /*
66   * At the moment: Check for some compatible strings that should be there
67   * somewhere in every fdt.
68   *
69   * FIXME: It would be nice if some CPU-ID could be used instead. But I didn't
70   * find one.
71   */
72  int node;
73
74  node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul");
75  if (node >= 0) {
76    return true;
77  }
78
79  node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ull");
80  if (node >= 0) {
81    return true;
82  }
83
84  return false;
85}
86
87#define SYSCNT_CNTCR          (0x0)
88#define SYSCNT_CNTCR_ENABLE   (1 << 0)
89#define SYSCNT_CNTCR_HDBG     (1 << 1)
90#define SYSCNT_CNTCR_FCREQ(n) (1 << (8 + (n)))
91#define SYSCNT_CNTFID(n)      (0x20 + 4 * (n))
92
93static uint32_t imx_syscnt_enable_and_return_frequency(const void *fdt)
94{
95  uint32_t freq;
96  volatile void *syscnt_base;
97
98  /* That's not in the usual FDTs. Sorry for falling back to a magic value. */
99  if (imx_is_imx6(fdt)) {
100    syscnt_base = (void *)0x021dc000;
101  } else {
102    syscnt_base = (void *)0x306c0000;
103  }
104
105  freq = *(uint32_t *)(syscnt_base + SYSCNT_CNTFID(0));
106
107  arm_cp15_set_counter_frequency(freq);
108
109  *(uint32_t *)(syscnt_base + SYSCNT_CNTCR) =
110    SYSCNT_CNTCR_ENABLE |
111    SYSCNT_CNTCR_HDBG |
112    SYSCNT_CNTCR_FCREQ(0);
113
114  return freq;
115}
116
117void arm_generic_timer_get_config(
118  uint32_t *frequency,
119  uint32_t *irq
120)
121{
122  const void *fdt;
123  int node;
124  int len;
125  const uint32_t *val;
126
127  fdt = bsp_fdt_get();
128  node = fdt_path_offset(fdt, "/timer");
129
130  val = fdt_getprop(fdt, node, "clock-frequency", &len);
131  if (val != NULL && len >= 4) {
132    *frequency = fdt32_to_cpu(val[0]);
133  } else {
134    /*
135     * Normally clock-frequency would be provided by the boot loader. If it
136     * didn't add one, we have to initialize the system counter ourself.
137     */
138    *frequency = imx_syscnt_enable_and_return_frequency(fdt);
139  }
140
141  /* FIXME: Figure out how Linux gets a proper IRQ number */
142  *irq = imx_get_irq_of_node(fdt, node, 0) - 16;
143}
144
145uintptr_t imx_gic_dist_base;
146
147static void imx_find_gic(const void *fdt)
148{
149  int node;
150
151  node = fdt_path_offset(fdt, "/interrupt-controller");
152  if (node < 0) {
153    node = fdt_path_offset(fdt, "/soc/interrupt-controller");
154  }
155  imx_gic_dist_base = (uintptr_t) imx_get_reg_of_node(fdt, node);
156
157#if defined(RTEMS_SMP)
158  /*
159   * Secondary processors start with a disabled data cache and use the GIC to
160   * deterine if they can continue the initialization, see
161   * arm_gic_irq_initialize_secondary_cpu().
162   */
163  rtems_cache_flush_multiple_data_lines(
164    &imx_gic_dist_base,
165    sizeof(imx_gic_dist_base)
166  );
167#endif
168}
169
170void bsp_start(void)
171{
172  imx_find_gic(bsp_fdt_get());
173  bsp_interrupt_initialize();
174  rtems_cache_coherent_add_area(
175    bsp_section_nocacheheap_begin,
176    (uintptr_t) bsp_section_nocacheheap_size
177  );
178}
Note: See TracBrowser for help on using the repository browser.