source: rtems/bsps/arm/lpc24xx/start/io.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

  • Property mode set to 100644
File size: 15.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSBSPsARMLPC24XX_io
5 *
6 * @brief Input and output module.
7 */
8
9/*
10 * Copyright (c) 2009-2012 embedded brains GmbH.  All rights reserved.
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.org/license/LICENSE.
15 */
16
17#include <bsp.h>
18#include <bsp/io.h>
19#include <bsp/start.h>
20#include <bsp/system-clocks.h>
21
22#define LPC24XX_PIN_SELECT(index) ((index) >> 4U)
23
24#define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U)
25
26#define LPC24XX_PIN_SELECT_MASK 0x3U
27
28rtems_status_code lpc24xx_gpio_config(
29  unsigned index,
30  lpc24xx_gpio_settings settings
31)
32{
33  if (index <= LPC24XX_IO_INDEX_MAX) {
34    rtems_interrupt_level level;
35    uint32_t port = LPC24XX_IO_PORT(index);
36    uint32_t port_bit = LPC24XX_IO_PORT_BIT(index);
37    uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
38    uint32_t resistor = settings & 0x3U;
39    #ifdef ARM_MULTILIB_ARCH_V4
40      uint32_t select = LPC24XX_PIN_SELECT(index);
41      uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
42
43      /* Get resistor flags */
44      switch (resistor) {
45        case LPC24XX_GPIO_RESISTOR_PULL_UP:
46          resistor = 0x0U;
47          break;
48        case LPC24XX_GPIO_RESISTOR_NONE:
49          resistor = 0x2U;
50          break;
51        case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
52          resistor = 0x3U;
53          break;
54        default:
55          return RTEMS_INVALID_NUMBER;
56      }
57    #else
58      uint32_t iocon_mask = IOCON_HYS | IOCON_INV
59        | IOCON_SLEW | IOCON_OD | IOCON_FILTER;
60      uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE;
61      uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT);
62
63      /* Get resistor flags */
64      switch (resistor) {
65        case LPC24XX_GPIO_RESISTOR_NONE:
66          resistor = IOCON_MODE(0);
67          break;
68        case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
69          resistor = IOCON_MODE(1);
70          break;
71        case LPC24XX_GPIO_RESISTOR_PULL_UP:
72          resistor = IOCON_MODE(2);
73          break;
74        case LPC17XX_GPIO_HYSTERESIS:
75          resistor = IOCON_MODE(3);
76          break;
77      }
78      iocon |= resistor;
79
80      if (iocon_invalid != 0) {
81        return RTEMS_INVALID_NUMBER;
82      }
83
84      if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) {
85        return RTEMS_INVALID_NUMBER;
86      }
87
88      if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) {
89        iocon |= IOCON_FILTER;
90      } else {
91        iocon &= ~IOCON_FILTER;
92      }
93    #endif
94
95    rtems_interrupt_disable(level);
96
97    #ifdef ARM_MULTILIB_ARCH_V4
98      /* Resistor */
99      LPC24XX_PINMODE [select] =
100        (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift))
101          | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift);
102    #else
103      LPC17XX_IOCON [index] = iocon;
104    #endif
105
106    rtems_interrupt_flash(level);
107
108    /* Input or output */
109    LPC24XX_FIO [port].dir =
110      (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit);
111
112    rtems_interrupt_enable(level);
113  } else {
114    return RTEMS_INVALID_ID;
115  }
116
117  return RTEMS_SUCCESSFUL;
118}
119
120#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
121  [mod] = { \
122    .power = pwr, \
123    .clock = clk, \
124    .index = idx \
125  }
126
127typedef struct {
128  unsigned char power : 1;
129  unsigned char clock : 1;
130  unsigned char index : 6;
131} lpc24xx_module_entry;
132
133static const lpc24xx_module_entry lpc24xx_module_table [] = {
134  #ifdef ARM_MULTILIB_ARCH_V4
135    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
136  #endif
137  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
138  #ifdef ARM_MULTILIB_ARCH_V4
139    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
140  #endif
141  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
142  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
143  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
144  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
145  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
146  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
147  #ifdef ARM_MULTILIB_ARCH_V4
148    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
149  #else
150    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15),
151  #endif
152  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
153  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
154  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
155  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
156  #ifdef ARM_MULTILIB_ARCH_V4
157    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
158  #else
159    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0),
160  #endif
161  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
162  #ifdef ARM_MULTILIB_ARCH_V7M
163    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17),
164  #endif
165  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
166  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
167  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
168  #ifdef ARM_MULTILIB_ARCH_V7M
169    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18),
170  #endif
171  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
172  #ifdef ARM_MULTILIB_ARCH_V4
173    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
174  #endif
175  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
176  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
177  #ifdef ARM_MULTILIB_ARCH_V7M
178    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20),
179  #endif
180  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
181  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
182  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
183  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
184  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
185  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
186  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
187  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
188  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
189  #ifdef ARM_MULTILIB_ARCH_V7M
190    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8),
191  #endif
192  #ifdef ARM_MULTILIB_ARCH_V4
193    LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0),
194  #endif
195  LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31)
196};
197
198static rtems_status_code lpc24xx_module_do_enable(
199  lpc24xx_module module,
200  lpc24xx_module_clock clock,
201  bool enable
202)
203{
204  rtems_interrupt_level level;
205  bool has_power = false;
206  bool has_clock = false;
207  unsigned index = 0;
208  #ifdef ARM_MULTILIB_ARCH_V7M
209    volatile lpc17xx_scb *scb = &LPC17XX_SCB;
210  #endif
211
212  if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
213      return RTEMS_INVALID_ID;
214  }
215
216  #ifdef ARM_MULTILIB_ARCH_V4
217    if (clock == LPC24XX_MODULE_PCLK_DEFAULT) {
218      #if LPC24XX_PCLKDIV == 1U
219        clock = LPC24XX_MODULE_CCLK;
220      #elif LPC24XX_PCLKDIV == 2U
221        clock = LPC24XX_MODULE_CCLK_2;
222      #elif LPC24XX_PCLKDIV == 4U
223        clock = LPC24XX_MODULE_CCLK_4;
224      #elif LPC24XX_PCLKDIV == 8U
225        clock = LPC24XX_MODULE_CCLK_8;
226      #endif
227    }
228
229    if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
230      return RTEMS_INVALID_CLOCK;
231    }
232  #else
233    if (clock != LPC24XX_MODULE_PCLK_DEFAULT) {
234      return RTEMS_INVALID_CLOCK;
235    }
236  #endif
237
238  has_power = lpc24xx_module_table [module].power;
239  has_clock = lpc24xx_module_table [module].clock;
240  index = lpc24xx_module_table [module].index;
241
242  /* Enable or disable module */
243  if (enable) {
244    if (has_power) {
245      rtems_interrupt_disable(level);
246      #ifdef ARM_MULTILIB_ARCH_V4
247        PCONP |= 1U << index;
248      #else
249        scb->pconp |= 1U << index;
250      #endif
251      rtems_interrupt_enable(level);
252    }
253
254    if (module != LPC24XX_MODULE_USB) {
255      if (has_clock) {
256        #ifdef ARM_MULTILIB_ARCH_V4
257          unsigned clock_shift = 2U * index;
258
259          rtems_interrupt_disable(level);
260          if (clock_shift < 32U) {
261            PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
262                | (clock << clock_shift);
263          } else {
264            clock_shift -= 32U;
265            PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
266                | (clock << clock_shift);
267          }
268          rtems_interrupt_enable(level);
269        #endif
270      }
271    } else {
272      #ifdef ARM_MULTILIB_ARCH_V4
273        unsigned pllclk = lpc24xx_pllclk();
274        unsigned usbsel = pllclk / 48000000U - 1U;
275
276        if (
277          usbsel > 15U
278            || (usbsel % 2U != 1U)
279            || (pllclk % 48000000U) != 0U
280        ) {
281          return RTEMS_INCORRECT_STATE;
282        }
283
284        USBCLKCFG = usbsel;
285      #else
286        uint32_t pllclk = lpc24xx_pllclk();
287        uint32_t usbclk = 48000000U;
288
289        if (pllclk % usbclk == 0U) {
290          uint32_t usbdiv = pllclk / usbclk;
291
292          scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv)
293            | LPC17XX_SCB_USBCLKSEL_USBSEL(1);
294        } else {
295          return RTEMS_INCORRECT_STATE;
296        }
297      #endif
298    }
299  } else {
300    if (has_power) {
301      rtems_interrupt_disable(level);
302      #ifdef ARM_MULTILIB_ARCH_V4
303        PCONP &= ~(1U << index);
304      #else
305        scb->pconp &= ~(1U << index);
306      #endif
307      rtems_interrupt_enable(level);
308    }
309  }
310
311  return RTEMS_SUCCESSFUL;
312}
313
314rtems_status_code lpc24xx_module_enable(
315  lpc24xx_module module,
316  lpc24xx_module_clock clock
317)
318{
319  return lpc24xx_module_do_enable(module, clock, true);
320}
321
322rtems_status_code lpc24xx_module_disable(
323  lpc24xx_module module
324)
325{
326  return lpc24xx_module_do_enable(
327    module,
328    LPC24XX_MODULE_PCLK_DEFAULT,
329    false
330  );
331}
332
333bool lpc24xx_module_is_enabled(lpc24xx_module module)
334{
335  bool enabled = false;
336
337  if ((unsigned) module < LPC24XX_MODULE_COUNT) {
338    bool has_power = lpc24xx_module_table [module].power;
339
340    if (has_power) {
341      unsigned index = lpc24xx_module_table [module].index;
342      #ifdef ARM_MULTILIB_ARCH_V4
343        uint32_t pconp = PCONP;
344      #else
345        uint32_t pconp = LPC17XX_SCB.pconp;
346      #endif
347
348      enabled = (pconp & (1U << index)) != 0;
349    } else {
350      enabled = true;
351    }
352  }
353
354  return enabled;
355}
356
357typedef rtems_status_code (*lpc24xx_pin_visitor)(
358  #ifdef ARM_MULTILIB_ARCH_V4
359    volatile uint32_t *pinsel,
360    uint32_t pinsel_mask,
361    uint32_t pinsel_value,
362  #else
363    volatile uint32_t *iocon,
364    lpc24xx_pin_range pin_range,
365  #endif
366  volatile uint32_t *fio_dir,
367  uint32_t fio_bit
368);
369
370static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
371lpc24xx_pin_set_function(
372  #ifdef ARM_MULTILIB_ARCH_V4
373    volatile uint32_t *pinsel,
374    uint32_t pinsel_mask,
375    uint32_t pinsel_value,
376  #else
377    volatile uint32_t *iocon,
378    lpc24xx_pin_range pin_range,
379  #endif
380  volatile uint32_t *fio_dir,
381  uint32_t fio_bit
382)
383{
384  #ifdef ARM_MULTILIB_ARCH_V4
385    rtems_interrupt_level level;
386
387    rtems_interrupt_disable(level);
388    *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value;
389    rtems_interrupt_enable(level);
390  #else
391    uint32_t iocon_extra = 0;
392    uint32_t iocon_not_analog = IOCON_ADMODE;
393
394    /* TODO */
395    switch (pin_range.fields.type) {
396      case LPC17XX_PIN_TYPE_ADC:
397      case LPC17XX_PIN_TYPE_DAC:
398        iocon_not_analog = 0;
399        break;
400      case LPC17XX_PIN_TYPE_I2C_FAST_PLUS:
401        iocon_extra |= IOCON_HS;
402        break;
403      case LPC17XX_PIN_TYPE_OPEN_DRAIN:
404        iocon_extra |= IOCON_OD;
405        break;
406      case LPC17XX_PIN_TYPE_FAST_SLEW_RATE:
407        iocon_extra |= IOCON_SLEW;
408        break;
409      default:
410        break;
411    }
412
413    *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog;
414  #endif
415
416  return RTEMS_SUCCESSFUL;
417}
418
419static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
420  #ifdef ARM_MULTILIB_ARCH_V4
421    volatile uint32_t *pinsel,
422    uint32_t pinsel_mask,
423    uint32_t pinsel_value,
424  #else
425    volatile uint32_t *iocon,
426    lpc24xx_pin_range pin_range,
427  #endif
428  volatile uint32_t *fio_dir,
429  uint32_t fio_bit
430)
431{
432  #ifdef ARM_MULTILIB_ARCH_V4
433    if ((*pinsel & pinsel_mask) == pinsel_value) {
434      return RTEMS_SUCCESSFUL;
435    } else {
436      return RTEMS_IO_ERROR;
437    }
438  #else
439    /* TODO */
440    return RTEMS_IO_ERROR;
441  #endif
442}
443
444static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
445lpc24xx_pin_set_input(
446  #ifdef ARM_MULTILIB_ARCH_V4
447    volatile uint32_t *pinsel,
448    uint32_t pinsel_mask,
449    uint32_t pinsel_value,
450  #else
451    volatile uint32_t *iocon,
452    lpc24xx_pin_range pin_range,
453  #endif
454  volatile uint32_t *fio_dir,
455  uint32_t fio_bit
456)
457{
458  rtems_interrupt_level level;
459
460  rtems_interrupt_disable(level);
461  *fio_dir &= ~fio_bit;
462  #ifdef ARM_MULTILIB_ARCH_V4
463    *pinsel &= ~pinsel_mask;
464  #else
465    *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER;
466  #endif
467  rtems_interrupt_enable(level);
468
469  return RTEMS_SUCCESSFUL;
470}
471
472static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
473  #ifdef ARM_MULTILIB_ARCH_V4
474    volatile uint32_t *pinsel,
475    uint32_t pinsel_mask,
476    uint32_t pinsel_value,
477  #else
478    volatile uint32_t *iocon,
479    lpc24xx_pin_range pin_range,
480  #endif
481  volatile uint32_t *fio_dir,
482  uint32_t fio_bit
483)
484{
485  rtems_status_code sc = RTEMS_IO_ERROR;
486  bool is_input = (*fio_dir & fio_bit) == 0;
487
488  if (is_input) {
489    #ifdef ARM_MULTILIB_ARCH_V4
490      bool is_gpio = (*pinsel & pinsel_mask) == 0;
491    #else
492      bool is_gpio = IOCON_FUNC_GET(*iocon) == 0;
493    #endif
494
495    if (is_gpio) {
496      sc = RTEMS_SUCCESSFUL;
497    }
498  }
499
500  return sc;
501}
502
503static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
504  lpc24xx_pin_visitors [] = {
505  [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
506  [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
507  [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
508  [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
509};
510
511BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
512  const lpc24xx_pin_range *pins,
513  lpc24xx_pin_action action
514)
515{
516  rtems_status_code sc = RTEMS_SUCCESSFUL;
517
518  if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
519    lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
520    lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
521    lpc24xx_pin_range pin_range = *pins;
522    uint32_t previous_port_bit = pin_range.fields.port_bit;
523
524    while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
525      uint32_t port = pin_range.fields.port;
526      uint32_t port_bit = pin_range.fields.port_bit;
527      uint32_t port_bit_last = port_bit;
528      uint32_t range = pin_range.fields.range;
529      #ifdef ARM_MULTILIB_ARCH_V4
530        uint32_t function = pin_range.fields.function;
531      #endif
532      volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
533
534      if (range) {
535        port_bit = previous_port_bit;
536      }
537
538      while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
539        uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
540        uint32_t fio_bit = 1U << port_bit;
541        #ifdef ARM_MULTILIB_ARCH_V4
542          uint32_t select = LPC24XX_PIN_SELECT(index);
543          uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
544          volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
545          uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
546          uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
547
548          sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
549        #else
550          volatile uint32_t *iocon = &LPC17XX_IOCON [index];
551
552          sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit);
553        #endif
554
555        ++port_bit;
556      }
557
558      ++pins;
559      previous_port_bit = port_bit;
560      pin_range = *pins;
561    }
562  } else {
563    sc = RTEMS_NOT_DEFINED;
564  }
565
566  return sc;
567}
Note: See TracBrowser for help on using the repository browser.