File indexing completed on 2025-05-11 08:23:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <bsp.h>
0037 #include <bsp/io.h>
0038 #include <bsp/start.h>
0039 #include <bsp/system-clocks.h>
0040
0041 #define LPC24XX_PIN_SELECT(index) ((index) >> 4U)
0042
0043 #define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U)
0044
0045 #define LPC24XX_PIN_SELECT_MASK 0x3U
0046
0047 rtems_status_code lpc24xx_gpio_config(
0048 unsigned index,
0049 lpc24xx_gpio_settings settings
0050 )
0051 {
0052 if (index <= LPC24XX_IO_INDEX_MAX) {
0053 rtems_interrupt_level level;
0054 uint32_t port = LPC24XX_IO_PORT(index);
0055 uint32_t port_bit = LPC24XX_IO_PORT_BIT(index);
0056 uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U;
0057 uint32_t resistor = settings & 0x3U;
0058 #ifdef ARM_MULTILIB_ARCH_V4
0059 uint32_t select = LPC24XX_PIN_SELECT(index);
0060 uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
0061
0062
0063 switch (resistor) {
0064 case LPC24XX_GPIO_RESISTOR_PULL_UP:
0065 resistor = 0x0U;
0066 break;
0067 case LPC24XX_GPIO_RESISTOR_NONE:
0068 resistor = 0x2U;
0069 break;
0070 case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
0071 resistor = 0x3U;
0072 break;
0073 default:
0074 return RTEMS_INVALID_NUMBER;
0075 }
0076 #else
0077 uint32_t iocon_mask = IOCON_HYS | IOCON_INV
0078 | IOCON_SLEW | IOCON_OD | IOCON_FILTER;
0079 uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE;
0080 uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT);
0081
0082
0083 switch (resistor) {
0084 case LPC24XX_GPIO_RESISTOR_NONE:
0085 resistor = IOCON_MODE(0);
0086 break;
0087 case LPC24XX_GPIO_RESISTOR_PULL_DOWN:
0088 resistor = IOCON_MODE(1);
0089 break;
0090 case LPC24XX_GPIO_RESISTOR_PULL_UP:
0091 resistor = IOCON_MODE(2);
0092 break;
0093 case LPC17XX_GPIO_HYSTERESIS:
0094 resistor = IOCON_MODE(3);
0095 break;
0096 }
0097 iocon |= resistor;
0098
0099 if (iocon_invalid != 0) {
0100 return RTEMS_INVALID_NUMBER;
0101 }
0102
0103 if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) {
0104 return RTEMS_INVALID_NUMBER;
0105 }
0106
0107 if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) {
0108 iocon |= IOCON_FILTER;
0109 } else {
0110 iocon &= ~IOCON_FILTER;
0111 }
0112 #endif
0113
0114 rtems_interrupt_disable(level);
0115
0116 #ifdef ARM_MULTILIB_ARCH_V4
0117
0118 LPC24XX_PINMODE [select] =
0119 (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift))
0120 | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift);
0121 #else
0122 LPC17XX_IOCON [index] = iocon;
0123 #endif
0124
0125 rtems_interrupt_flash(level);
0126
0127
0128 LPC24XX_FIO [port].dir =
0129 (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit);
0130
0131 rtems_interrupt_enable(level);
0132 } else {
0133 return RTEMS_INVALID_ID;
0134 }
0135
0136 return RTEMS_SUCCESSFUL;
0137 }
0138
0139 #define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \
0140 [mod] = { \
0141 .power = pwr, \
0142 .clock = clk, \
0143 .index = idx \
0144 }
0145
0146 typedef struct {
0147 unsigned char power : 1;
0148 unsigned char clock : 1;
0149 unsigned char index : 6;
0150 } lpc24xx_module_entry;
0151
0152 static const lpc24xx_module_entry lpc24xx_module_table [] = {
0153 #ifdef ARM_MULTILIB_ARCH_V4
0154 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15),
0155 #endif
0156 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12),
0157 #ifdef ARM_MULTILIB_ARCH_V4
0158 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16),
0159 #endif
0160 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13),
0161 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14),
0162 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11),
0163 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11),
0164 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30),
0165 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29),
0166 #ifdef ARM_MULTILIB_ARCH_V4
0167 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17),
0168 #else
0169 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15),
0170 #endif
0171 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7),
0172 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19),
0173 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26),
0174 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27),
0175 #ifdef ARM_MULTILIB_ARCH_V4
0176 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20),
0177 #else
0178 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0),
0179 #endif
0180 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28),
0181 #ifdef ARM_MULTILIB_ARCH_V7M
0182 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17),
0183 #endif
0184 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18),
0185 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5),
0186 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6),
0187 #ifdef ARM_MULTILIB_ARCH_V7M
0188 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18),
0189 #endif
0190 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9),
0191 #ifdef ARM_MULTILIB_ARCH_V4
0192 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8),
0193 #endif
0194 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21),
0195 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10),
0196 #ifdef ARM_MULTILIB_ARCH_V7M
0197 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20),
0198 #endif
0199 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30),
0200 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1),
0201 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2),
0202 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22),
0203 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23),
0204 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3),
0205 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4),
0206 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24),
0207 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25),
0208 #ifdef ARM_MULTILIB_ARCH_V7M
0209 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8),
0210 #endif
0211 #ifdef ARM_MULTILIB_ARCH_V4
0212 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0),
0213 #endif
0214 LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31)
0215 };
0216
0217 static rtems_status_code lpc24xx_module_do_enable(
0218 lpc24xx_module module,
0219 lpc24xx_module_clock clock,
0220 bool enable
0221 )
0222 {
0223 rtems_interrupt_level level;
0224 bool has_power = false;
0225 bool has_clock = false;
0226 unsigned index = 0;
0227 #ifdef ARM_MULTILIB_ARCH_V7M
0228 volatile lpc17xx_scb *scb = &LPC17XX_SCB;
0229 #endif
0230
0231 if ((unsigned) module >= LPC24XX_MODULE_COUNT) {
0232 return RTEMS_INVALID_ID;
0233 }
0234
0235 #ifdef ARM_MULTILIB_ARCH_V4
0236 if (clock == LPC24XX_MODULE_PCLK_DEFAULT) {
0237 #if LPC24XX_PCLKDIV == 1U
0238 clock = LPC24XX_MODULE_CCLK;
0239 #elif LPC24XX_PCLKDIV == 2U
0240 clock = LPC24XX_MODULE_CCLK_2;
0241 #elif LPC24XX_PCLKDIV == 4U
0242 clock = LPC24XX_MODULE_CCLK_4;
0243 #elif LPC24XX_PCLKDIV == 8U
0244 clock = LPC24XX_MODULE_CCLK_8;
0245 #endif
0246 }
0247
0248 if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) {
0249 return RTEMS_INVALID_CLOCK;
0250 }
0251 #else
0252 if (clock != LPC24XX_MODULE_PCLK_DEFAULT) {
0253 return RTEMS_INVALID_CLOCK;
0254 }
0255 #endif
0256
0257 has_power = lpc24xx_module_table [module].power;
0258 has_clock = lpc24xx_module_table [module].clock;
0259 index = lpc24xx_module_table [module].index;
0260
0261
0262 if (enable) {
0263 if (has_power) {
0264 rtems_interrupt_disable(level);
0265 #ifdef ARM_MULTILIB_ARCH_V4
0266 PCONP |= 1U << index;
0267 #else
0268 scb->pconp |= 1U << index;
0269 #endif
0270 rtems_interrupt_enable(level);
0271 }
0272
0273 if (module != LPC24XX_MODULE_USB) {
0274 if (has_clock) {
0275 #ifdef ARM_MULTILIB_ARCH_V4
0276 unsigned clock_shift = 2U * index;
0277
0278 rtems_interrupt_disable(level);
0279 if (clock_shift < 32U) {
0280 PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
0281 | (clock << clock_shift);
0282 } else {
0283 clock_shift -= 32U;
0284 PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift))
0285 | (clock << clock_shift);
0286 }
0287 rtems_interrupt_enable(level);
0288 #endif
0289 }
0290 } else {
0291 #ifdef ARM_MULTILIB_ARCH_V4
0292 unsigned pllclk = lpc24xx_pllclk();
0293 unsigned usbsel = pllclk / 48000000U - 1U;
0294
0295 if (
0296 usbsel > 15U
0297 || (usbsel % 2U != 1U)
0298 || (pllclk % 48000000U) != 0U
0299 ) {
0300 return RTEMS_INCORRECT_STATE;
0301 }
0302
0303 USBCLKCFG = usbsel;
0304 #else
0305 uint32_t pllclk = lpc24xx_pllclk();
0306 uint32_t usbclk = 48000000U;
0307
0308 if (pllclk % usbclk == 0U) {
0309 uint32_t usbdiv = pllclk / usbclk;
0310
0311 scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv)
0312 | LPC17XX_SCB_USBCLKSEL_USBSEL(1);
0313 } else {
0314 return RTEMS_INCORRECT_STATE;
0315 }
0316 #endif
0317 }
0318 } else {
0319 if (has_power) {
0320 rtems_interrupt_disable(level);
0321 #ifdef ARM_MULTILIB_ARCH_V4
0322 PCONP &= ~(1U << index);
0323 #else
0324 scb->pconp &= ~(1U << index);
0325 #endif
0326 rtems_interrupt_enable(level);
0327 }
0328 }
0329
0330 return RTEMS_SUCCESSFUL;
0331 }
0332
0333 rtems_status_code lpc24xx_module_enable(
0334 lpc24xx_module module,
0335 lpc24xx_module_clock clock
0336 )
0337 {
0338 return lpc24xx_module_do_enable(module, clock, true);
0339 }
0340
0341 rtems_status_code lpc24xx_module_disable(
0342 lpc24xx_module module
0343 )
0344 {
0345 return lpc24xx_module_do_enable(
0346 module,
0347 LPC24XX_MODULE_PCLK_DEFAULT,
0348 false
0349 );
0350 }
0351
0352 bool lpc24xx_module_is_enabled(lpc24xx_module module)
0353 {
0354 bool enabled = false;
0355
0356 if ((unsigned) module < LPC24XX_MODULE_COUNT) {
0357 bool has_power = lpc24xx_module_table [module].power;
0358
0359 if (has_power) {
0360 unsigned index = lpc24xx_module_table [module].index;
0361 #ifdef ARM_MULTILIB_ARCH_V4
0362 uint32_t pconp = PCONP;
0363 #else
0364 uint32_t pconp = LPC17XX_SCB.pconp;
0365 #endif
0366
0367 enabled = (pconp & (1U << index)) != 0;
0368 } else {
0369 enabled = true;
0370 }
0371 }
0372
0373 return enabled;
0374 }
0375
0376 typedef rtems_status_code (*lpc24xx_pin_visitor)(
0377 #ifdef ARM_MULTILIB_ARCH_V4
0378 volatile uint32_t *pinsel,
0379 uint32_t pinsel_mask,
0380 uint32_t pinsel_value,
0381 #else
0382 volatile uint32_t *iocon,
0383 lpc24xx_pin_range pin_range,
0384 #endif
0385 volatile uint32_t *fio_dir,
0386 uint32_t fio_bit
0387 );
0388
0389 static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
0390 lpc24xx_pin_set_function(
0391 #ifdef ARM_MULTILIB_ARCH_V4
0392 volatile uint32_t *pinsel,
0393 uint32_t pinsel_mask,
0394 uint32_t pinsel_value,
0395 #else
0396 volatile uint32_t *iocon,
0397 lpc24xx_pin_range pin_range,
0398 #endif
0399 volatile uint32_t *fio_dir,
0400 uint32_t fio_bit
0401 )
0402 {
0403 #ifdef ARM_MULTILIB_ARCH_V4
0404 rtems_interrupt_level level;
0405
0406 rtems_interrupt_disable(level);
0407 *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value;
0408 rtems_interrupt_enable(level);
0409 #else
0410 uint32_t iocon_extra = 0;
0411 uint32_t iocon_not_analog = IOCON_ADMODE;
0412
0413
0414 switch (pin_range.fields.type) {
0415 case LPC17XX_PIN_TYPE_ADC:
0416 case LPC17XX_PIN_TYPE_DAC:
0417 iocon_not_analog = 0;
0418 break;
0419 case LPC17XX_PIN_TYPE_I2C_FAST_PLUS:
0420 iocon_extra |= IOCON_HS;
0421 break;
0422 case LPC17XX_PIN_TYPE_OPEN_DRAIN:
0423 iocon_extra |= IOCON_OD;
0424 break;
0425 case LPC17XX_PIN_TYPE_FAST_SLEW_RATE:
0426 iocon_extra |= IOCON_SLEW;
0427 break;
0428 default:
0429 break;
0430 }
0431
0432 *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog;
0433 #endif
0434
0435 return RTEMS_SUCCESSFUL;
0436 }
0437
0438 static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function(
0439 #ifdef ARM_MULTILIB_ARCH_V4
0440 volatile uint32_t *pinsel,
0441 uint32_t pinsel_mask,
0442 uint32_t pinsel_value,
0443 #else
0444 volatile uint32_t *iocon,
0445 lpc24xx_pin_range pin_range,
0446 #endif
0447 volatile uint32_t *fio_dir,
0448 uint32_t fio_bit
0449 )
0450 {
0451 #ifdef ARM_MULTILIB_ARCH_V4
0452 if ((*pinsel & pinsel_mask) == pinsel_value) {
0453 return RTEMS_SUCCESSFUL;
0454 } else {
0455 return RTEMS_IO_ERROR;
0456 }
0457 #else
0458
0459 return RTEMS_IO_ERROR;
0460 #endif
0461 }
0462
0463 static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code
0464 lpc24xx_pin_set_input(
0465 #ifdef ARM_MULTILIB_ARCH_V4
0466 volatile uint32_t *pinsel,
0467 uint32_t pinsel_mask,
0468 uint32_t pinsel_value,
0469 #else
0470 volatile uint32_t *iocon,
0471 lpc24xx_pin_range pin_range,
0472 #endif
0473 volatile uint32_t *fio_dir,
0474 uint32_t fio_bit
0475 )
0476 {
0477 rtems_interrupt_level level;
0478
0479 rtems_interrupt_disable(level);
0480 *fio_dir &= ~fio_bit;
0481 #ifdef ARM_MULTILIB_ARCH_V4
0482 *pinsel &= ~pinsel_mask;
0483 #else
0484 *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER;
0485 #endif
0486 rtems_interrupt_enable(level);
0487
0488 return RTEMS_SUCCESSFUL;
0489 }
0490
0491 static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input(
0492 #ifdef ARM_MULTILIB_ARCH_V4
0493 volatile uint32_t *pinsel,
0494 uint32_t pinsel_mask,
0495 uint32_t pinsel_value,
0496 #else
0497 volatile uint32_t *iocon,
0498 lpc24xx_pin_range pin_range,
0499 #endif
0500 volatile uint32_t *fio_dir,
0501 uint32_t fio_bit
0502 )
0503 {
0504 rtems_status_code sc = RTEMS_IO_ERROR;
0505 bool is_input = (*fio_dir & fio_bit) == 0;
0506
0507 if (is_input) {
0508 #ifdef ARM_MULTILIB_ARCH_V4
0509 bool is_gpio = (*pinsel & pinsel_mask) == 0;
0510 #else
0511 bool is_gpio = IOCON_FUNC_GET(*iocon) == 0;
0512 #endif
0513
0514 if (is_gpio) {
0515 sc = RTEMS_SUCCESSFUL;
0516 }
0517 }
0518
0519 return sc;
0520 }
0521
0522 static BSP_START_DATA_SECTION const lpc24xx_pin_visitor
0523 lpc24xx_pin_visitors [] = {
0524 [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function,
0525 [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function,
0526 [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input,
0527 [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input
0528 };
0529
0530 BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config(
0531 const lpc24xx_pin_range *pins,
0532 lpc24xx_pin_action action
0533 )
0534 {
0535 rtems_status_code sc = RTEMS_SUCCESSFUL;
0536
0537 if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) {
0538 lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action];
0539 lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL;
0540 lpc24xx_pin_range pin_range = *pins;
0541 uint32_t previous_port_bit = pin_range.fields.port_bit;
0542
0543 while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) {
0544 uint32_t port = pin_range.fields.port;
0545 uint32_t port_bit = pin_range.fields.port_bit;
0546 uint32_t port_bit_last = port_bit;
0547 uint32_t range = pin_range.fields.range;
0548 #ifdef ARM_MULTILIB_ARCH_V4
0549 uint32_t function = pin_range.fields.function;
0550 #endif
0551 volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir;
0552
0553 if (range) {
0554 port_bit = previous_port_bit;
0555 }
0556
0557 while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) {
0558 uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit);
0559 uint32_t fio_bit = 1U << port_bit;
0560 #ifdef ARM_MULTILIB_ARCH_V4
0561 uint32_t select = LPC24XX_PIN_SELECT(index);
0562 uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index);
0563 volatile uint32_t *pinsel = &LPC24XX_PINSEL [select];
0564 uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift;
0565 uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift;
0566
0567 sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit);
0568 #else
0569 volatile uint32_t *iocon = &LPC17XX_IOCON [index];
0570
0571 sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit);
0572 #endif
0573
0574 ++port_bit;
0575 }
0576
0577 ++pins;
0578 previous_port_bit = port_bit;
0579 pin_range = *pins;
0580 }
0581 } else {
0582 sc = RTEMS_NOT_DEFINED;
0583 }
0584
0585 return sc;
0586 }