File indexing completed on 2025-05-11 08:22:49
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 #include <bsp.h>
0029 #include <bsp/fdt.h>
0030 #include <bsp/imx-gpio.h>
0031 #include <bsp/imx-iomux.h>
0032 #include <libfdt.h>
0033 #include <arm/freescale/imx/imx_ccmvar.h>
0034 #include <arm/freescale/imx/imx_ecspireg.h>
0035 #include <dev/spi/spi.h>
0036 #include <rtems/irq-extension.h>
0037 #include <sys/param.h>
0038 #include <sys/endian.h>
0039
0040 #define IMX_ECSPI_FIFO_SIZE 64
0041 #define IMX_ECSPI_MAX_CHIPSELECTS 4
0042 #define IMX_ECSPI_CS_NONE IMX_ECSPI_MAX_CHIPSELECTS
0043
0044 typedef struct imx_ecspi_bus imx_ecspi_bus;
0045
0046 struct imx_ecspi_bus {
0047 spi_bus base;
0048 volatile imx_ecspi *regs;
0049 uint32_t conreg;
0050 uint32_t speed_hz;
0051 uint32_t mode;
0052 uint8_t bits_per_word;
0053 uint8_t cs;
0054 uint32_t msg_todo;
0055 const spi_ioc_transfer *msg;
0056 uint32_t todo;
0057 uint32_t in_transfer;
0058 uint8_t *rx_buf;
0059 const uint8_t *tx_buf;
0060 void (*push)(imx_ecspi_bus *, volatile imx_ecspi *);
0061 void (*pop)(imx_ecspi_bus *, volatile imx_ecspi *);
0062 rtems_id task_id;
0063 rtems_vector_number irq;
0064 struct {
0065 struct imx_gpio_pin pin;
0066 bool valid;
0067 } cspins[IMX_ECSPI_MAX_CHIPSELECTS];
0068 };
0069
0070 static bool imx_ecspi_is_rx_fifo_not_empty(volatile imx_ecspi *regs)
0071 {
0072 return (regs->statreg & IMX_ECSPI_RR) != 0;
0073 }
0074
0075 static void imx_ecspi_reset(volatile imx_ecspi *regs)
0076 {
0077 while (imx_ecspi_is_rx_fifo_not_empty(regs)) {
0078 regs->rxdata;
0079 }
0080 }
0081
0082 static void imx_ecspi_done(imx_ecspi_bus *bus)
0083 {
0084 rtems_event_transient_send(bus->task_id);
0085 }
0086
0087 #define IMC_ECSPI_PUSH(type) \
0088 static void imx_ecspi_push_##type(imx_ecspi_bus *bus, volatile imx_ecspi *regs) \
0089 { \
0090 type val = 0; \
0091 if (bus->tx_buf != NULL) { \
0092 val = *(type *)bus->tx_buf; \
0093 bus->tx_buf += sizeof(type); \
0094 } \
0095 bus->todo -= sizeof(type); \
0096 regs->txdata = val; \
0097 }
0098
0099 #define IMX_ECSPI_POP(type) \
0100 static void imx_ecspi_pop_##type(imx_ecspi_bus *bus, volatile imx_ecspi *regs) \
0101 { \
0102 uint32_t val = regs->rxdata; \
0103 if (bus->rx_buf != NULL) { \
0104 *(type *)bus->rx_buf = val; \
0105 bus->rx_buf += sizeof(type); \
0106 } \
0107 }
0108
0109 IMC_ECSPI_PUSH(uint8_t)
0110 IMX_ECSPI_POP(uint8_t)
0111 IMC_ECSPI_PUSH(uint16_t)
0112 IMX_ECSPI_POP(uint16_t)
0113 IMC_ECSPI_PUSH(uint32_t)
0114 IMX_ECSPI_POP(uint32_t)
0115
0116 static void imx_ecspi_push_uint32_t_swap(
0117 imx_ecspi_bus *bus,
0118 volatile imx_ecspi *regs
0119 )
0120 {
0121 uint32_t val = 0;
0122
0123 if (bus->tx_buf != NULL) {
0124 val = bswap32(*(uint32_t *)bus->tx_buf);
0125 bus->tx_buf += sizeof(uint32_t);
0126 }
0127
0128 bus->todo -= sizeof(uint32_t);
0129 regs->txdata = val;
0130 }
0131
0132 static void imx_ecspi_pop_uint32_t_swap(
0133 imx_ecspi_bus *bus,
0134 volatile imx_ecspi *regs
0135 )
0136 {
0137 uint32_t val = regs->rxdata;
0138
0139 if (bus->rx_buf != NULL) {
0140 *(uint32_t *)bus->rx_buf = bswap32(val);
0141 bus->rx_buf += sizeof(uint32_t);
0142 }
0143 }
0144
0145 static void imx_ecspi_push(imx_ecspi_bus *bus, volatile imx_ecspi *regs)
0146 {
0147 while (bus->todo > 0 && bus->in_transfer < IMX_ECSPI_FIFO_SIZE) {
0148 (*bus->push)(bus, regs);
0149 ++bus->in_transfer;
0150 }
0151 }
0152
0153
0154 static void
0155 imx_ecspi_set_chipsel(imx_ecspi_bus *bus, uint32_t cs)
0156 {
0157 size_t i;
0158
0159
0160 static const uint32_t idle = 1;
0161 static const uint32_t select = 0;
0162
0163 for (i = 0; i < IMX_ECSPI_MAX_CHIPSELECTS; ++i) {
0164 if (bus->cspins[i].valid) {
0165 if (i != cs) {
0166 imx_gpio_set_output(&bus->cspins[i].pin, idle);
0167 } else {
0168 imx_gpio_set_output(&bus->cspins[cs].pin, select);
0169 }
0170 }
0171 }
0172 }
0173
0174 static uint32_t imx_ecspi_conreg_divider(imx_ecspi_bus *bus, uint32_t speed_hz)
0175 {
0176 uint32_t post;
0177 uint32_t pre;
0178 uint32_t clk_in;
0179
0180 clk_in = bus->base.max_speed_hz;
0181
0182 if (clk_in > speed_hz) {
0183 post = fls((int) clk_in) - fls((int) speed_hz);
0184
0185 if (clk_in > (speed_hz << post)) {
0186 ++post;
0187 }
0188
0189
0190 post = MAX(4, post) - 4;
0191
0192 if (post <= 0xf) {
0193 pre = howmany(clk_in, speed_hz << post) - 1;
0194 } else {
0195 post = 0xf;
0196 pre = 0xf;
0197 }
0198 } else {
0199 post = 0;
0200 pre = 0;
0201 }
0202
0203 return IMX_ECSPI_CONREG_POST_DIVIDER(post)
0204 | IMX_ECSPI_CONREG_PRE_DIVIDER(pre);
0205 }
0206
0207 static void imx_ecspi_config(
0208 imx_ecspi_bus *bus,
0209 volatile imx_ecspi *regs,
0210 uint32_t speed_hz,
0211 uint8_t bits_per_word,
0212 uint32_t mode,
0213 uint8_t cs
0214 )
0215 {
0216 uint32_t conreg;
0217 uint32_t testreg;
0218 uint32_t configreg;
0219 uint32_t dmareg;
0220 uint32_t cs_bit;
0221
0222 conreg = IMX_ECSPI_CONREG_CHANNEL_MODE(0xf)
0223 | IMX_ECSPI_CONREG_SMC | IMX_ECSPI_CONREG_EN;
0224 testreg = regs->testreg;
0225 configreg = regs->configreg;
0226 dmareg = regs->dmareg;
0227 cs_bit = 1U << cs;
0228
0229 conreg |= imx_ecspi_conreg_divider(bus, speed_hz);
0230 conreg |= IMX_ECSPI_CONREG_CHANNEL_SELECT(cs);
0231
0232 configreg |= IMX_ECSPI_CONFIGREG_SS_CTL(cs_bit);
0233
0234 if ((mode & SPI_CPHA) != 0) {
0235 configreg |= IMX_ECSPI_CONFIGREG_SCLK_PHA(cs_bit);
0236 } else {
0237 configreg &= ~IMX_ECSPI_CONFIGREG_SCLK_PHA(cs_bit);
0238 }
0239
0240 if ((mode & SPI_CPOL) != 0) {
0241 configreg |= IMX_ECSPI_CONFIGREG_SCLK_POL(cs_bit);
0242 configreg |= IMX_ECSPI_CONFIGREG_SCLK_CTL(cs_bit);
0243 } else {
0244 configreg &= ~IMX_ECSPI_CONFIGREG_SCLK_POL(cs_bit);
0245 configreg &= ~IMX_ECSPI_CONFIGREG_SCLK_CTL(cs_bit);
0246 }
0247
0248 if ((mode & SPI_CS_HIGH) != 0) {
0249 configreg |= IMX_ECSPI_CONFIGREG_SS_POL(cs_bit);
0250 } else {
0251 configreg &= ~IMX_ECSPI_CONFIGREG_SS_POL(cs_bit);
0252 }
0253
0254 if ((mode & SPI_LOOP) != 0) {
0255 testreg |= IMX_ECSPI_TESTREG_LBC;
0256 } else {
0257 testreg &= ~IMX_ECSPI_TESTREG_LBC;
0258 }
0259
0260 dmareg = IMX_ECSPI_DMAREG_TX_THRESHOLD_SET(dmareg, IMX_ECSPI_FIFO_SIZE/2);
0261
0262 regs->conreg = conreg;
0263 regs->testreg = testreg;
0264 regs->dmareg = dmareg;
0265 regs->configreg = configreg;
0266
0267 bus->conreg = conreg;
0268 bus->speed_hz = speed_hz;
0269 bus->bits_per_word = bits_per_word;
0270 bus->mode = mode;
0271 bus->cs = cs;
0272
0273
0274 }
0275
0276 static void imx_ecspi_set_push_pop(
0277 imx_ecspi_bus *bus,
0278 uint32_t len,
0279 uint8_t bits_per_word
0280 )
0281 {
0282 uint32_t conreg;
0283
0284 conreg = bus->conreg;
0285
0286 if (len % 4 == 0 && len <= IMX_ECSPI_FIFO_SIZE) {
0287 conreg |= IMX_ECSPI_CONREG_BURST_LENGTH((len * 8) - 1);
0288
0289 bus->push = imx_ecspi_push_uint32_t_swap;
0290 bus->pop = imx_ecspi_pop_uint32_t_swap;
0291 } else {
0292 conreg |= IMX_ECSPI_CONREG_BURST_LENGTH(bits_per_word - 1);
0293
0294 if (bits_per_word <= 8) {
0295 bus->push = imx_ecspi_push_uint8_t;
0296 bus->pop = imx_ecspi_pop_uint8_t;
0297 } else if (bits_per_word <= 16) {
0298 bus->push = imx_ecspi_push_uint16_t;
0299 bus->pop = imx_ecspi_pop_uint16_t;
0300 } else {
0301 bus->push = imx_ecspi_push_uint32_t;
0302 bus->pop = imx_ecspi_pop_uint32_t;
0303 }
0304 }
0305
0306 bus->regs->conreg = conreg;
0307 }
0308
0309 static void imx_ecspi_next_msg(imx_ecspi_bus *bus, volatile imx_ecspi *regs)
0310 {
0311 if (bus->msg_todo > 0) {
0312 const spi_ioc_transfer *msg;
0313
0314 msg = bus->msg;
0315
0316 if (
0317 msg->speed_hz != bus->speed_hz
0318 || msg->bits_per_word != bus->bits_per_word
0319 || msg->mode != bus->mode
0320 || msg->cs != bus->cs
0321 ) {
0322 imx_ecspi_config(
0323 bus,
0324 regs,
0325 msg->speed_hz,
0326 msg->bits_per_word,
0327 msg->mode,
0328 msg->cs
0329 );
0330 }
0331 if ((msg->mode & SPI_NO_CS) != 0) {
0332 imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
0333 } else {
0334 imx_ecspi_set_chipsel(bus, msg->cs);
0335 }
0336
0337 bus->todo = msg->len;
0338 bus->rx_buf = msg->rx_buf;
0339 bus->tx_buf = msg->tx_buf;
0340 imx_ecspi_set_push_pop(bus, msg->len, msg->bits_per_word);
0341 imx_ecspi_push(bus, regs);
0342 regs->intreg = IMX_ECSPI_TE | IMX_ECSPI_TDR;
0343 } else {
0344 regs->intreg = 0;
0345 imx_ecspi_done(bus);
0346 }
0347 }
0348
0349 static void imx_ecspi_interrupt(void *arg)
0350 {
0351 imx_ecspi_bus *bus;
0352 volatile imx_ecspi *regs;
0353
0354 bus = arg;
0355 regs = bus->regs;
0356
0357 while (imx_ecspi_is_rx_fifo_not_empty(regs)) {
0358 (*bus->pop)(bus, regs);
0359 --bus->in_transfer;
0360 }
0361
0362 if (bus->todo > 0) {
0363 imx_ecspi_push(bus, regs);
0364 } else if (bus->in_transfer > 0) {
0365 regs->intreg = IMX_ECSPI_RR;
0366 } else {
0367 if (bus->msg->cs_change) {
0368 imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
0369 }
0370 --bus->msg_todo;
0371 ++bus->msg;
0372 imx_ecspi_next_msg(bus, regs);
0373 }
0374 }
0375
0376 static int imx_ecspi_check_messages(
0377 imx_ecspi_bus *bus,
0378 const spi_ioc_transfer *msg,
0379 uint32_t size)
0380 {
0381 while(size > 0) {
0382 if (msg->delay_usecs != 0) {
0383 return -EINVAL;
0384 }
0385 if (msg->bits_per_word > 32) {
0386 return -EINVAL;
0387 }
0388 if ((msg->mode &
0389 ~(SPI_CPHA | SPI_CPOL | SPI_LOOP | SPI_NO_CS)) != 0) {
0390 return -EINVAL;
0391 }
0392 if ((msg->mode & SPI_NO_CS) == 0 &&
0393 (msg->cs > IMX_ECSPI_MAX_CHIPSELECTS || !bus->cspins[msg->cs].valid)) {
0394 return -EINVAL;
0395 }
0396
0397 ++msg;
0398 --size;
0399 }
0400
0401 return 0;
0402 }
0403
0404 static int imx_ecspi_transfer(
0405 spi_bus *base,
0406 const spi_ioc_transfer *msgs,
0407 uint32_t n
0408 )
0409 {
0410 imx_ecspi_bus *bus;
0411 int rv;
0412
0413 bus = (imx_ecspi_bus *) base;
0414
0415 rv = imx_ecspi_check_messages(bus, msgs, n);
0416
0417 if (rv == 0) {
0418 bus->msg_todo = n;
0419 bus->msg = &msgs[0];
0420 bus->task_id = rtems_task_self();
0421
0422 imx_ecspi_next_msg(bus, bus->regs);
0423 rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0424 if (msgs[n-1].cs_change) {
0425 imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
0426 }
0427 }
0428 return rv;
0429 }
0430
0431 static void imx_ecspi_destroy(spi_bus *base)
0432 {
0433 imx_ecspi_bus *bus;
0434
0435 bus = (imx_ecspi_bus *) base;
0436 rtems_interrupt_handler_remove(bus->irq, imx_ecspi_interrupt, bus);
0437 spi_bus_destroy_and_free(&bus->base);
0438 }
0439
0440 static int imx_ecspi_init(imx_ecspi_bus *bus, const void *fdt, int node)
0441 {
0442 rtems_status_code sc;
0443 int len;
0444 const uint32_t *val;
0445 size_t i;
0446
0447 for (i = 0; i < IMX_ECSPI_MAX_CHIPSELECTS; ++i) {
0448 rtems_status_code sc_gpio = imx_gpio_init_from_fdt_property(
0449 &bus->cspins[i].pin, node, "cs-gpios", IMX_GPIO_MODE_OUTPUT, i);
0450 bus->cspins[i].valid = (sc_gpio == RTEMS_SUCCESSFUL);
0451 }
0452 imx_ecspi_set_chipsel(bus, IMX_ECSPI_CS_NONE);
0453
0454 imx_ecspi_config(
0455 bus,
0456 bus->regs,
0457 bus->base.max_speed_hz,
0458 8,
0459 0,
0460 0
0461 );
0462 imx_ecspi_reset(bus->regs);
0463
0464 sc = rtems_interrupt_handler_install(
0465 bus->irq,
0466 "ECSPI",
0467 RTEMS_INTERRUPT_UNIQUE,
0468 imx_ecspi_interrupt,
0469 bus
0470 );
0471 if (sc != RTEMS_SUCCESSFUL) {
0472 return EAGAIN;
0473 }
0474
0475 val = fdt_getprop(fdt, node, "pinctrl-0", &len);
0476 if (len == 4) {
0477 imx_iomux_configure_pins(fdt, fdt32_to_cpu(val[0]));
0478 }
0479
0480 return 0;
0481 }
0482
0483 static int imx_ecspi_setup(spi_bus *base)
0484 {
0485 imx_ecspi_bus *bus;
0486
0487 bus = (imx_ecspi_bus *) base;
0488
0489 if (
0490 bus->base.speed_hz > imx_ccm_ipg_hz()
0491 || bus->base.bits_per_word > 32
0492 ) {
0493 return -EINVAL;
0494 }
0495
0496 imx_ecspi_config(
0497 bus,
0498 bus->regs,
0499 bus->base.speed_hz,
0500 bus->base.bits_per_word,
0501 bus->base.mode,
0502 bus->base.cs
0503 );
0504 return 0;
0505 }
0506
0507 int spi_bus_register_imx(const char *bus_path, const char *alias_or_path)
0508 {
0509 const void *fdt;
0510 const char *path;
0511 int node;
0512 imx_ecspi_bus *bus;
0513 int eno;
0514
0515 fdt = bsp_fdt_get();
0516 path = fdt_get_alias(fdt, alias_or_path);
0517
0518 if (path == NULL) {
0519 path = alias_or_path;
0520 }
0521
0522 node = fdt_path_offset(fdt, path);
0523 if (node < 0) {
0524 rtems_set_errno_and_return_minus_one(ENXIO);
0525 }
0526
0527 bus = (imx_ecspi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
0528 if (bus == NULL){
0529 return -1;
0530 }
0531
0532 bus->base.max_speed_hz = imx_ccm_ecspi_hz();
0533 bus->base.delay_usecs = 0;
0534 bus->regs = imx_get_reg_of_node(fdt, node);
0535 bus->irq = imx_get_irq_of_node(fdt, node, 0);
0536
0537 eno = imx_ecspi_init(bus, fdt, node);
0538 if (eno != 0) {
0539 (*bus->base.destroy)(&bus->base);
0540 rtems_set_errno_and_return_minus_one(eno);
0541 }
0542
0543 bus->base.transfer = imx_ecspi_transfer;
0544 bus->base.destroy = imx_ecspi_destroy;
0545 bus->base.setup = imx_ecspi_setup;
0546
0547 return spi_bus_register(&bus->base, bus_path);
0548 }