Blame view

RIOT/boards/mulle/board.c 5.69 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  /*
   * Copyright (C) 2014-2017 Eistec AB
   *
   * This file is subject to the terms and conditions of the GNU Lesser General
   * Public License v2.1. See the file LICENSE in the top level directory for more
   * details.
   */
  
  /**
   * @ingroup     boards_mulle
   * @{
   *
   * @file
   * @brief       Board specific implementations for the Mulle board
   *
   * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
   *
   * @}
   */
  
  #include <stddef.h> /* for NULL */
  #include <stdio.h>
  #include "board.h"
  #include "cpu.h"
  #include "mcg.h"
  #include "periph/gpio.h"
  #include "periph/rtt.h"
  #include "periph/spi.h"
  #include "nvram-spi.h"
  #include "nvram.h"
  #include "xtimer.h"
  #include "vfs.h"
  #include "fs/devfs.h"
  #include "mtd_spi_nor.h"
  
  static nvram_t mulle_nvram_dev;
  nvram_t *mulle_nvram = &mulle_nvram_dev;
  static nvram_spi_params_t nvram_spi_params = {
          .spi = MULLE_NVRAM_SPI_DEV,
          .clk = MULLE_NVRAM_SPI_CLK,
          .cs = MULLE_NVRAM_SPI_CS,
          .address_count = MULLE_NVRAM_SPI_ADDRESS_COUNT,
  };
  
  static devfs_t mulle_nvram_devfs = {
      .path = "/fram0",
      .f_op = &nvram_vfs_ops,
      .private_data = &mulle_nvram_dev,
  };
  
  static mtd_spi_nor_t mulle_nor_dev = {
      .base = {
          .driver = &mtd_spi_nor_driver,
          .page_size = 256,
          .pages_per_sector = 256,
          .sector_count = 32,
      },
      .opcode = &mtd_spi_nor_opcode_default,
      .spi = MULLE_NOR_SPI_DEV,
      .cs = MULLE_NOR_SPI_CS,
      .addr_width = 3,
      .mode = SPI_MODE_3,
      .clk = SPI_CLK_10MHZ,
  };
  
  mtd_dev_t *mtd0 = (mtd_dev_t *)&mulle_nor_dev;
  
  static devfs_t mulle_nor_devfs = {
      .path = "/mtd0",
      .f_op = &mtd_vfs_ops,
      .private_data = &mulle_nor_dev,
  };
  
  /** @brief Initialize the GPIO pins controlling the power switches. */
  static inline void power_pins_init(void);
  
  static void increase_boot_count(void);
  static int mulle_nvram_init(void);
  
  int mulle_nor_init(void);
  
  void board_init(void)
  {
      int status;
  
      /* initialize the boards LEDs */
      gpio_init(LED0_PIN, GPIO_OUT);
      gpio_init(LED1_PIN, GPIO_OUT);
      gpio_init(LED2_PIN, GPIO_OUT);
  
      /* Initialize power control pins */
      power_pins_init();
  
      /* Turn on Vperiph for peripherals */
      /*
       * By turning on Vperiph first, and before waiting for the clocks to
       * stabilize, we will have used enough time to have let the FRAM start up
       * properly when we want to access it later without having to add any extra
       * delays.
       */
      gpio_set(MULLE_POWER_VPERIPH);
  
      /* Turn on AVDD for reading voltages */
      gpio_set(MULLE_POWER_AVDD);
  
      /* Initialize RTC oscillator as early as possible since we are using it as a
       * base clock for the FLL.
       * It takes a while to stabilize the oscillator, therefore we do this as
       * soon as possible during boot in order to let it stabilize while other
       * stuff is initializing. */
      /* If the clock is not stable then the UART will have the wrong baud rate
       * for debug prints as well */
      rtt_init();
  
      /* Set 32 kHz clock source */
      SIM->SOPT1 = (SIM->SOPT1 & ~(SIM_SOPT1_OSC32KSEL_MASK)) | SIM_SOPT1_OSC32KSEL(2);
  
      /* At this point we need to wait for 1 ms until the clock is stable.
       * Since the clock is not yet stable we can only guess how long we must
       * wait. I have tried to make this as short as possible but still being able
       * to read the initialization messages written on the UART.
       * (If the clock is not stable all UART output is garbled until it has
       * stabilized) */
      for (int i = 0; i < 100000; ++i) {
          __asm__ volatile("nop\n");
      }
  
      /* initialize the CPU */
      cpu_init();
  
      /* NVRAM requires xtimer for timing */
      xtimer_init();
  
      /* Initialize NVRAM */
      status = mulle_nvram_init();
      if (status == 0) {
          /* Increment boot counter */
          increase_boot_count();
      }
  
      /* Initialize NOR flash */
      mulle_nor_init();
  }
  
  static inline void power_pins_init(void)
  {
      gpio_init(MULLE_POWER_AVDD, GPIO_OUT);
      gpio_init(MULLE_POWER_VPERIPH, GPIO_OUT);
      gpio_init(MULLE_POWER_VSEC, GPIO_OUT);
      gpio_clear(MULLE_POWER_AVDD);
      gpio_clear(MULLE_POWER_VPERIPH);
      gpio_clear(MULLE_POWER_VSEC);
  }
  
  static int mulle_nvram_init(void)
  {
      union {
          uint32_t u32;
          uint8_t  u8[sizeof(uint32_t)];
      } rec;
      rec.u32 = 0;
  
      if (nvram_spi_init(mulle_nvram, &nvram_spi_params, MULLE_NVRAM_CAPACITY) != 0) {
          return -2;
      }
  
      if (mulle_nvram->read(mulle_nvram, &rec.u8[0], MULLE_NVRAM_MAGIC, sizeof(rec.u32)) != sizeof(rec.u32)) {
          return -3;
      }
  
      if (rec.u32 != MULLE_NVRAM_MAGIC_EXPECTED) {
          int i;
          union {
              uint64_t u64;
              uint8_t  u8[sizeof(uint64_t)];
          } zero;
          zero.u64 = 0;
          for (i = 0; i < MULLE_NVRAM_CAPACITY; i += sizeof(zero)) {
              if (mulle_nvram->write(mulle_nvram, &zero.u8[0], i, sizeof(zero.u64)) != sizeof(zero.u64)) {
                  return -4;
              }
          }
          rec.u32 = MULLE_NVRAM_MAGIC_EXPECTED;
          if (mulle_nvram->write(mulle_nvram, &rec.u8[0], MULLE_NVRAM_MAGIC, sizeof(rec.u32)) != sizeof(rec.u32)) {
              return -5;
          }
      }
  
      /* Register DevFS node */
      devfs_register(&mulle_nvram_devfs);
  
      return 0;
  }
  
  static void increase_boot_count(void)
  {
      union {
          uint32_t u32;
          uint8_t  u8[sizeof(uint32_t)];
      } rec;
      rec.u32 = 0;
      if (mulle_nvram->read(mulle_nvram, &rec.u8[0], MULLE_NVRAM_BOOT_COUNT, sizeof(rec.u32)) != sizeof(rec.u32)) {
          return;
      }
      ++rec.u32;
      mulle_nvram->write(mulle_nvram, &rec.u8[0], MULLE_NVRAM_BOOT_COUNT, sizeof(rec.u32));
  }
  
  int mulle_nor_init(void)
  {
      int res = mtd_init(mtd0);
  
      if (res >= 0) {
          /* Register DevFS node */
          devfs_register(&mulle_nor_devfs);
      }
  
      return res;
  }