diff --git a/Makefile b/Makefile index 6e95a59..4472704 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,11 @@ bootstrap: .PHONY: toolchain #H Build and install the toolchain. toolchain: +ifeq ($(UNAME),Darwin) + mkdir -p $(PREFIX)/bin + [ ! -e "$(PREFIX)/bin/python" ] && \ + ln -s `which python3` $(PREFIX)/bin/python +endif mkdir -p $(BUILD_LOGS) rm -rf $(RSB)/rtems/build cd $(RSB)/rtems && ../source-builder/sb-set-builder \ diff --git a/demo/init.c b/demo/init.c index c545e56..561c5f1 100644 --- a/demo/init.c +++ b/demo/init.c @@ -57,6 +57,7 @@ #define IS_GRISP2 1 #endif +#include #ifdef IS_GRISP1 #include #include @@ -69,6 +70,7 @@ #include "sd-card-test.h" #include "1wire.h" #include "pmod_rfid.h" +#include "pmod_dio.h" #define STACK_SIZE_INIT_TASK (64 * 1024) #define STACK_SIZE_SHELL (64 * 1024) @@ -79,7 +81,6 @@ #define PRIO_WPA (RTEMS_MAXIMUM_PRIORITY - 1) #define SPI_FDT_NAME "spi0" -#define SPI_BUS "/dev/spibus" #define CMD_SPI_MAX_LEN 32 @@ -249,14 +250,30 @@ Init(rtems_task_argument arg) assert(rv == 0); #endif #ifdef IS_GRISP2 - rv = spi_bus_register_imx(SPI_BUS, SPI_FDT_NAME); - assert(rv == 0); + if (grisp_is_industrialgrisp()) { + /* Industrial GRiSP */ + rv = spi_bus_register_imx(GRISP_SPI_DEVICE, + GRISP_INDUSTRIAL_SPI_ONBOARD_FDT_ALIAS); + assert(rv == 0); + rv = spi_bus_register_imx(GRISP_SPI_DEVICE "-pmod", + GRISP_INDUSTRIAL_SPI_PMOD_FDT_ALIAS); + assert(rv == 0); + + rv = i2c_bus_register_imx(GRISP_I2C0_DEVICE, + GRISP_INDUSTRIAL_I2C_FDT_ALIAS); + assert(rv == 0); + } else { + /* GRiSP2 */ + rv = spi_bus_register_imx(GRISP_SPI_DEVICE, + GRISP_SPI_FDT_ALIAS); + assert(rv == 0); - rv = i2c_bus_register_imx("/dev/i2c-1", "i2c0"); - assert(rv == 0); + rv = i2c_bus_register_imx("/dev/i2c-1", "i2c0"); + assert(rv == 0); - rv = i2c_bus_register_imx("/dev/i2c-2", "i2c1"); - assert(rv == 0); + rv = i2c_bus_register_imx("/dev/i2c-2", "i2c1"); + assert(rv == 0); + } #endif /* IS_GRISP2 */ printf("Init EEPROM\n"); @@ -289,8 +306,11 @@ Init(rtems_task_argument arg) grisp_init_dhcpcd(PRIO_DHCP); grisp_led_set2(false, false, true); - sleep(3); - grisp_init_wpa_supplicant(wpa_supplicant_conf, PRIO_WPA, create_wlandev); + if (!grisp_is_industrialgrisp()) { + sleep(3); + grisp_init_wpa_supplicant(wpa_supplicant_conf, PRIO_WPA, + create_wlandev); + } #ifdef EVENT_RECORDING rtems_record_start_server(10, 1234, 10); @@ -299,8 +319,13 @@ Init(rtems_task_argument arg) init_led(); #ifdef IS_GRISP2 - // uncomment for testing RFID - //pmod_rfid_init(SPI_BUS, 1); + if (grisp_is_industrialgrisp()) { + pmod_rfid_init(GRISP_SPI_DEVICE, 0); + pmod_dio_init(GRISP_SPI_DEVICE); + } else { + // uncomment for testing RFID + //pmod_rfid_init(GRISP_SPI_DEVICE, 1); + } #endif /* IS_GRISP2 */ start_shell(); diff --git a/demo/pmod_dio.c b/demo/pmod_dio.c new file mode 100644 index 0000000..0f3d474 --- /dev/null +++ b/demo/pmod_dio.c @@ -0,0 +1,487 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#ifdef GRISP_PLATFORM_GRISP2 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmod_rfid.h" + +#define MAX14906_SetOUT 0x00 +#define MAX14906_SetLED 0x01 +#define MAX14906_DoiLevel 0x02 +#define MAX14906_Interrupt 0x03 +#define MAX14906_OvrLdChF 0x04 +#define MAX14906_OpnWirChF 0x05 +#define MAX14906_ShtVDDChF 0x06 +#define MAX14906_GlobalErr 0x07 +#define MAX14906_OpnWrEn 0x08 +#define MAX14906_ShtVDDEn 0x09 +#define MAX14906_Config1 0x0A +#define MAX14906_Config2 0x0B +#define MAX14906_ConfigDI 0x0C +#define MAX14906_ConfigDO 0x0D +#define MAX14906_CurrLim 0x0E +#define MAX14906_Mask 0x0F + +#define MAX14906_REGISTERS 0x10 + +#define MAX_CASCADED_BOARDS 4 + +#define CLEAR_BIT(x, bit) (x &= (uint8_t)~(1u << (bit))) +#define SET_BIT(x, bit) (x |= (uint8_t)(1u << (bit))) + +struct pmod_dio_ctx { + rtems_shell_cmd_t shell_cmd; + int bus; + uint8_t cs; + struct imx_gpio_pin fault; + struct imx_gpio_pin ready; + bool initialized; + uint8_t regs[MAX_CASCADED_BOARDS][MAX14906_REGISTERS]; +}; + +static uint8_t +max14906_build_addr(int board, uint8_t addr, uint8_t write) +{ + return (uint8_t)((board << 6) + (addr << 1) + write); +} + +/* + * Calculate the CRC from first_bit to last_bit. According to AN 6633, the + * checksum from CPU to MAX14915 is calculated from bit 0 to bit 18 and the + * checksum from MAX14915 to CPU is calculated from bit 2 to bit 18. + */ +static uint8_t +max14906_crc5encode(uint8_t *buf, size_t first_bit, size_t last_bit) +{ + uint8_t crc5_start = 0x1f; + uint8_t crc5_poly = 0x15; + uint8_t crc_result = crc5_start; + size_t i; + + for (i = first_bit; i <= last_bit; ++i) { + uint8_t bit = (buf[i/8] >> (7-(i%8))) & 0x01; + uint8_t crc_result_bit4 = (crc_result >> 4) & 0x01; + + if (bit ^ crc_result_bit4) { + crc_result = + (uint8_t)(crc5_poly ^ ((crc_result<<1) & 0x1f)); + } else { + crc_result = (uint8_t)((crc_result<<1) & 0x1f); + } + } + + return crc_result; +} + +/* + * Return returned second byte on success or -1 on error. + */ +static int +pmod_dio_register_rw( + struct pmod_dio_ctx *ctx, + int board, + uint8_t addr, + uint8_t write, + uint8_t value +) +{ + uint8_t tx_buf[] = { + max14906_build_addr(board, addr, write), + value, + 0 + }; + uint8_t rx_buf[sizeof(tx_buf)]; + spi_ioc_transfer msg = { + .len = sizeof(tx_buf), + .rx_buf = rx_buf, + .tx_buf = tx_buf, + .speed_hz = 200000, + .bits_per_word = 8, + .mode = SPI_MODE_0, + .cs = ctx->cs, + .cs_change = true, + }; + int error; + uint8_t crc; + + tx_buf[sizeof(tx_buf)-1] = max14906_crc5encode(tx_buf, 0, + sizeof(tx_buf) * 8 - 6); + + error = ioctl(ctx->bus, SPI_IOC_MESSAGE(1), &msg); + if (error != 0) { + return -1; + } + crc = max14906_crc5encode(rx_buf, 2, sizeof(rx_buf) * 8 - 6); + if (crc != (rx_buf[sizeof(rx_buf)-1] & 0x1F)) { + return -1; + } + return rx_buf[1]; +} + +static int +pmod_dio_register_write( + struct pmod_dio_ctx *ctx, + int board, + uint8_t addr +) +{ + return pmod_dio_register_rw(ctx, board, addr, 1, + ctx->regs[board][addr]); +} + +static int +pmod_dio_register_read( + struct pmod_dio_ctx *ctx, + int board, + uint8_t addr +) +{ + return pmod_dio_register_rw(ctx, board, addr, 0, 0); +} + +static int +pmod_dio_set_op_mode_func( + struct pmod_dio_ctx *ctx, + int board, + int chan, + int op_mode +) +{ + int rv; + + if (chan < 0 || chan > 3 || op_mode < 0 || op_mode > 6) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + }; + + if (op_mode < 4) { + CLEAR_BIT(ctx->regs[board][MAX14906_SetOUT], chan+4); + + if (op_mode == 0) { /* High-side */ + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2); + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2+1); + } else if (op_mode == 1) { /* High-side with 2x inrush current */ + SET_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2); + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2+1); + } else if (op_mode == 2) { /* Active-clamp push-pull */ + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2); + SET_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2+1); + } else { /* Simple push-pull */ + SET_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2); + SET_BIT(ctx->regs[board][MAX14906_ConfigDO], chan*2+1); + } + + rv = pmod_dio_register_write(ctx, board, MAX14906_SetOUT); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + + rv = pmod_dio_register_write(ctx, board, MAX14906_ConfigDO); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + } else { + SET_BIT(ctx->regs[board][MAX14906_SetOUT], chan+4); + + if (op_mode == 4) { /* Low-leakage, High-impedance */ + SET_BIT(ctx->regs[board][MAX14906_ConfigDO], (chan*2+1)); + } else if (op_mode == 5) { /* DI Mode, Type 1 and 3 */ + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDI], 7); + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], (chan*2+1)); + } else if (op_mode == 6) { /* DI Mode, Type 2 */ + SET_BIT(ctx->regs[board][MAX14906_ConfigDI], 7); + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDO], (chan*2+1)); + } + + rv = pmod_dio_register_write(ctx, board, MAX14906_SetOUT); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + + rv = pmod_dio_register_write(ctx, board, MAX14906_ConfigDO); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + + rv = pmod_dio_register_write(ctx, board, MAX14906_ConfigDI); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + } + + return 0; +} + +static int +pmod_dio_read_input_func(struct pmod_dio_ctx *ctx, int board, int chan) +{ + int rv; + + if (chan < 0 || chan > 3) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + }; + + /* VDDFaultSe = 0 */ + CLEAR_BIT(ctx->regs[board][MAX14906_ConfigDI], 4); + rv = pmod_dio_register_write(ctx, board, MAX14906_ConfigDI); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(500)); + + /* Read input */ + rv = pmod_dio_register_read(ctx, board, MAX14906_DoiLevel); + assert(rv >= 0); + ctx->regs[board][MAX14906_DoiLevel] = (uint8_t) rv; + + if ((rv & (1 << chan)) != 0) { + printf("input is high\n"); + } else { + printf("input is low\n"); + } + + return 0; +} + +static int +pmod_dio_write_output_func( + struct pmod_dio_ctx *ctx, + int board, + int chan, + int lvl +) +{ + int rv; + + /* FIXME: Better error handling instead of asserts */ + + if (chan < 0 || chan > 3 || lvl < 0 || lvl > 1) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + }; + + if (lvl == 0) { + CLEAR_BIT(ctx->regs[board][MAX14906_SetOUT], chan); + } else { + SET_BIT(ctx->regs[board][MAX14906_SetOUT], chan); + } + + rv = pmod_dio_register_write(ctx, board, MAX14906_SetOUT); + assert(rv >= 0); + + return 0; +} + +static int +pmod_dio_init_board_func(struct pmod_dio_ctx *ctx, int board) +{ + size_t i; + int rv; + + /* FIXME: Better error handling instead of asserts */ + + /* copy all registers */ + for (i = 0; i < MAX14906_REGISTERS; ++i) { + rv = pmod_dio_register_read(ctx, board, (uint8_t)i); + assert(rv >= 0); + ctx->regs[board][i] = (uint8_t)rv; + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100)); + } + + /* Set LEDs which are controlled directly by the MAX14906 */ + CLEAR_BIT(ctx->regs[board][MAX14906_Config1], 0); + CLEAR_BIT(ctx->regs[board][MAX14906_Config1], 1); + rv = pmod_dio_register_write(ctx, board, MAX14906_Config1); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100)); + + /* Enable gate driver */ + SET_BIT(ctx->regs[board][MAX14906_OpnWrEn], 4); + SET_BIT(ctx->regs[board][MAX14906_OpnWrEn], 5); + SET_BIT(ctx->regs[board][MAX14906_OpnWrEn], 6); + SET_BIT(ctx->regs[board][MAX14906_OpnWrEn], 7); + rv = pmod_dio_register_write(ctx, board, MAX14906_OpnWrEn); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100)); + + /* current limit up to 1.2 A */ + ctx->regs[board][MAX14906_CurrLim] = 0xff; + rv = pmod_dio_register_write(ctx, board, MAX14906_CurrLim); + assert(rv >= 0); + rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(100)); + + return 0; +} + +static struct pmod_dio_ctx * +pmod_dio_get_ctx_from_shell(char **argv) +{ + rtems_shell_cmd_t *shell_cmd; + + shell_cmd = rtems_shell_lookup_cmd(argv[0]); + return RTEMS_CONTAINER_OF(shell_cmd, struct pmod_dio_ctx, shell_cmd); +} + +static int +pmod_dio_func(int argc, char **argv) +{ + struct pmod_dio_ctx *ctx = pmod_dio_get_ctx_from_shell(argv); + int board = 0; /* Number of the cascaded board */ + int second = -1; /* Second numeric argument */ + int third = -1; /* Third numeric argument */ + + if (argc < 2) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + } + + if (argc >= 3) { + errno = 0; + board = (uint8_t)strtol(argv[2], NULL, 0); + if (errno != 0 || board < 0 || board >= MAX_CASCADED_BOARDS) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + } + } + + if (argc >= 4) { + errno = 0; + second = (uint8_t)strtol(argv[3], NULL, 0); + if (errno != 0) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + } + } + + if (argc >= 5) { + errno = 0; + third = (uint8_t)strtol(argv[4], NULL, 0); + if (errno != 0) { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + } + } + + if (strcmp(argv[1], "set_op_mode") == 0) { + return pmod_dio_set_op_mode_func(ctx, board, second, third); + } else if (strcmp(argv[1], "init_board") == 0) { + return pmod_dio_init_board_func(ctx, board); + } else if (strcmp(argv[1], "read_input") == 0) { + return pmod_dio_read_input_func(ctx, board, second); + } else if (strcmp(argv[1], "write_output") == 0) { + return pmod_dio_write_output_func(ctx, board, second, third); + } else { + printf("Usage:\n%s", ctx->shell_cmd.usage); + return -1; + } +} + +static void +pmod_dio_do_init(const void *fdt, int node, const char *spi_bus) +{ + struct pmod_dio_ctx *ctx; + const void *prop; + const char *name; + static const char topic[] = "dio"; + static const char usage[] = "Call with:\n" + " dioX init_board \n" + " dioX set_op_mode \n" + " dioX read_input \n" + " dioX write_output \n" + "where:\n" + " Number of the cascaded board. [0..3]\n" + " Channel to read / write. [0..3]\n" + " Level to set. [0..1]\n" + " operational mode:\n" + " 0: High-side\n" + " 1: High-side with 2x inrush current\n" + " 2: Active-clamp push-pull\n" + " 3: Simple push-pull\n" + " 4: Low-leakage, High-impedance\n" + " 5: DI Mode, Type 1 and 3\n" + " 6: DI Mode, Type 2\n"; + rtems_status_code sc; + rtems_shell_cmd_t *cmd; + + /* FIXME: Should use better error handling than asserts! But it's only a + * test so let's use them for now. */ + + name = fdt_get_name(fdt, node, NULL); + assert(name != NULL); + + ctx = calloc(sizeof(*ctx), 1); + assert(ctx != NULL); + + ctx->shell_cmd.name = name; + ctx->shell_cmd.usage = usage; + ctx->shell_cmd.topic = topic; + ctx->shell_cmd.command = pmod_dio_func; + + ctx->bus = open(spi_bus, O_RDWR); + assert(ctx->bus >= 0); + + prop = fdt_getprop(fdt, node, "reg", NULL); + assert(prop != NULL); + ctx->cs = (uint8_t) fdt32_ld(prop); + + sc = imx_gpio_init_from_fdt_property( + &ctx->fault, node, "maxim,fault", IMX_GPIO_MODE_INPUT, 0); + assert(sc == RTEMS_SUCCESSFUL); + sc = imx_gpio_init_from_fdt_property( + &ctx->ready, node, "maxim,ready", IMX_GPIO_MODE_INPUT, 0); + assert(sc == RTEMS_SUCCESSFUL); + + cmd = rtems_shell_add_cmd_struct(&ctx->shell_cmd); + assert(cmd != NULL); +} + +void +pmod_dio_init(const char *spi_bus) +{ + const void *fdt = bsp_fdt_get(); + int node = -1; + + do { + node = fdt_node_offset_by_compatible(fdt, node, + "maxim,max14906"); + + if (node >= 0) { + pmod_dio_do_init(fdt, node, spi_bus); + } + } while (node >= 0); +} +#endif /* IS_GRISP2 */ diff --git a/demo/pmod_dio.h b/demo/pmod_dio.h new file mode 100644 index 0000000..afaa10c --- /dev/null +++ b/demo/pmod_dio.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEMO_PMOD_DIO_H +#define DEMO_PMOD_DIO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Initialize necessary stuff and add shell commands to work with PMOD_DIO. + * Note: This function will get most of the necessary information from FDT. + */ +void pmod_dio_init(const char *spi_bus); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DEMO_PMOD_RFID_H */ diff --git a/demo/pmod_rfid.c b/demo/pmod_rfid.c index 1468ba8..c64da27 100644 --- a/demo/pmod_rfid.c +++ b/demo/pmod_rfid.c @@ -228,6 +228,7 @@ pmod_rfid_transfer( .bits_per_word = 8, .mode = SPI_MODE_1, .cs = ctx->cs, + .cs_change = true, }; verb_print(ctx, VERBOSE_ALL, "Tx: "); @@ -620,19 +621,21 @@ pmod_rfid_init_pins(struct pmod_rfid_ctx *ctx) { rtems_status_code sc; int node; - const char *path; const void *fdt; fdt = bsp_fdt_get(); - path = fdt_get_alias(fdt, "spi0"); - if (path == 0) { + + node = fdt_node_offset_by_compatible(fdt, -1, "ti,trf7970a"); + if (node < 0) { return RTEMS_UNSATISFIED; } - node = fdt_path_offset(fdt, path); - /* LED is connected to SS3 */ + /* LED */ sc = imx_gpio_init_from_fdt_property(&ctx->led, - node, "cs-gpios", IMX_GPIO_MODE_OUTPUT, 3); + node, "grisp,led-gpios", IMX_GPIO_MODE_OUTPUT, 0); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } /* Interrupt pin */ /* FIXME: The interrupt pin isn't used yet. Initialization is done so it diff --git a/external/libgrisp b/external/libgrisp index f4efc23..5cb490e 160000 --- a/external/libgrisp +++ b/external/libgrisp @@ -1 +1 @@ -Subproject commit f4efc23aa3dbeb24f5c4626b618db386dab690ed +Subproject commit 5cb490ee48bafea95a02c0314f8c854df93c5d9d diff --git a/external/rtems b/external/rtems index 0fe6bd6..b99bfd6 160000 --- a/external/rtems +++ b/external/rtems @@ -1 +1 @@ -Subproject commit 0fe6bd64cf9943e1fe9afa14aa4b3185cbea0735 +Subproject commit b99bfd628ef0d825c8313bf1a860b4b7da9d4ee1 diff --git a/external/rtems-libbsd b/external/rtems-libbsd index 03c54a8..d038de8 160000 --- a/external/rtems-libbsd +++ b/external/rtems-libbsd @@ -1 +1 @@ -Subproject commit 03c54a87f18937085c06e868a2490cca2710771d +Subproject commit d038de8bef933a6a89945719d203403d1c358be5 diff --git a/fdt/Makefile b/fdt/Makefile index 38df5cc..46b3d3b 100644 --- a/fdt/Makefile +++ b/fdt/Makefile @@ -1,7 +1,7 @@ # Note: $(PWD) doesn't work together with -C option of make MAKEFILE_DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) -BOARD = imx6ul-grisp2 +DTS = imx6ul-grisp2.dts imx6ull-industrialgrisp.dts SRC_FDT = $(MAKEFILE_DIR)/../external/fdt FDT_SYS = $(SRC_FDT)/sys FDT_SCRIPTS = $(FDT_SYS)/tools/fdt @@ -11,19 +11,19 @@ BUILDDIR = $(MAKEFILE_DIR)/b-dtb export DTC = dtc export MACHINE = arm -DTB = $(BUILDDIR)/$(BOARD).dtb +DTB = $(DTS:%.dts=$(BUILDDIR)/%.dtb) all: $(DTB) install: all mkdir -p $(PREFIX)/fdt - cp $(BOARD).dts $(PREFIX)/fdt/ + cp $(DTS) $(PREFIX)/fdt/ cp $(DTB) $(PREFIX)/fdt/ $(BUILDDIR): mkdir $(BUILDDIR) -$(DTB): $(BOARD).dts $(BUILDDIR) +$(BUILDDIR)/%.dtb: %.dts $(BUILDDIR) sh -x $(FDT_SCRIPTS)/make_dtb.sh $(FDT_SYS) $< $(BUILDDIR) clean: diff --git a/fdt/imx6ull-industrialgrisp.dts b/fdt/imx6ull-industrialgrisp.dts new file mode 100644 index 0000000..d0262bf --- /dev/null +++ b/fdt/imx6ull-industrialgrisp.dts @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause) +/* + * Copyright (C) 2020 embedded brains GmbH. + */ + +/dts-v1/; +#include "custom-imx6ul.dtsi" +#include "imx6ul-phytec-phycore-som.dtsi" + +/ { + model = "IndustrialGRiSP"; + compatible = "embeddedbrains,industrialgrisp", "phytec,imx6ul-pcl063-emmc", "fsl,imx6ull"; + + gpio_leds_grisp2: leds { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpioleds_grisp2>; + compatible = "gpio-leds"; + + igrisp-mcu-led { + gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>; + }; + igrisp-rfid-led { + gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>; + }; + }; + + pmod_spi: pmod-spi { + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_spi3>; + pinctrl-1 = <&pinctrl_spi3_gpio>; + status = "okay"; + + /* SPI mode */ + grisp,spi-alias = "spi2"; /* use with spi_bus_register_imx */ + grisp,int-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + + /* GPIO mode */ + grisp,gpios = + <&gpio1 20 GPIO_ACTIVE_HIGH>, /* X803.1 */ + <&gpio1 22 GPIO_ACTIVE_HIGH>, /* X803.2 */ + <&gpio1 23 GPIO_ACTIVE_HIGH>, /* X803.3 */ + <&gpio1 21 GPIO_ACTIVE_HIGH>, /* X803.4 */ + <&gpio1 3 GPIO_ACTIVE_HIGH>, /* X803.7 */ + <&gpio5 0 GPIO_ACTIVE_HIGH>, /* X803.8 */ + <&gpio1 1 GPIO_ACTIVE_HIGH>, /* X803.9 */ + <&gpio1 18 GPIO_ACTIVE_HIGH>; /* X803.10 */ + }; +}; + +&fec1 { + status = "okay"; + pinctrl-0 = <&pinctrl_enet1_igrisp>; + + /delete-node/ mdio; +}; + +&fec2 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2>; + phy-mode = "rmii"; + phy-handle = <ðphy2>; + + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&gpio1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; + clocks = <&clks IMX6UL_CLK_ENET_REF>; + clock-names = "rmii-ref"; + status = "okay"; + }; + + ethphy2: ethernet-phy@2 { + reg = <2>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + micrel,led-mode = <1>; + clocks = <&clks IMX6UL_CLK_ENET_REF>; + clock-names = "rmii-ref"; + status = "okay"; + }; + }; +}; + +&i2c1 { + status = "okay"; + + at24mac402_eeprom: eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + status = "okay"; + }; + at24mac402_eui: eeprom@5f { + compatible = "atmel,at24mac402-eui"; + reg = <0x5f>; + status = "okay"; + }; + atecc608: cryptoauth@36 { + compatible = "microchip,atecc608", "atmel,at24c16"; + reg = <0x36>; + status = "okay"; + }; +}; + +&usdhc2 { + pinctrl-names = "default"; + status = "okay"; +}; + +&ecspi1 { + status = "okay"; + pinctrl-0 = <&pinctrl_spi1>; + + cs-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>, + <&gpio3 10 GPIO_ACTIVE_HIGH>, + <&gpio3 11 GPIO_ACTIVE_HIGH>; + + rfid: rfid@0 { + compatible = "ti,trf7970a"; + reg = <0>; + + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio4>; + interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + grisp,int-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; + grisp,led-gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>; + }; + + dio1: dio@2 { + compatible = "maxim,max14906"; + /* Really 2 for DIO1: The SS pins are numbered odd! */ + reg = <2>; + + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio3>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + maxim,fault = <&gpio3 0 GPIO_ACTIVE_HIGH>; + maxim,ready = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + dio2: dio@1 { + compatible = "maxim,max14906"; + /* Really 1 for DIO2: The SS pins are numbered odd! */ + reg = <1>; + + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio3>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + maxim,fault = <&gpio3 2 GPIO_ACTIVE_HIGH>; + maxim,ready = <&gpio3 3 GPIO_ACTIVE_HIGH>; + }; +}; + +&ecspi3 { + status = "okay"; + pinctrl-0 = <&pinctrl_spi3>; + + cs-gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>; + + grisp,int-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; +}; + +&iomuxc { + pinctrl_spi1: spi1grp { + fsl,pins = < + MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK 0x8 /* SPI_SCK */ + MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI 0x8 /* SPI_MOSI */ + MX6UL_PAD_CSI_DATA07__ECSPI1_MISO 0x2000 /* SPI_MISO */ + + MX6UL_PAD_CSI_DATA05__GPIO4_IO26 0x8 /* SPI_SS0 */ + MX6UL_PAD_LCD_DATA05__GPIO3_IO10 0x8 /* SPI_SS1 */ + MX6UL_PAD_LCD_DATA06__GPIO3_IO11 0x8 /* SPI_SS2/SPI_GPIO0 */ + MX6UL_PAD_LCD_RESET__GPIO3_IO04 0x8 /* SPI_GPIO1 */ + MX6UL_PAD_CSI_DATA03__GPIO4_IO24 0x8 /* SPI_RESET */ + MX6UL_PAD_CSI_VSYNC__GPIO4_IO19 0x8 /* SPI_INT */ + MX6UL_PAD_LCD_ENABLE__GPIO3_IO01 0x8 /* SPI_READY1 */ + MX6UL_PAD_LCD_CLK__GPIO3_IO00 0x8 /* SPI_FAULT1 */ + MX6UL_PAD_LCD_VSYNC__GPIO3_IO03 0x8 /* SPI_READY2 */ + MX6UL_PAD_LCD_HSYNC__GPIO3_IO02 0x8 /* SPI_FAULT2 */ + >; + }; + + pinctrl_spi3: spi3grp { + fsl,pins = < + MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x8 /* SPI3_SCK */ + MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x8 /* SPI3_MOSI */ + MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x2000 /* SPI3_MISO */ + + MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x8 /* SPI3_SS0 */ + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0x8 /* SPI3_GPIO0 */ + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x8 /* SPI3_INT */ + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x8 /* SPI3_RESET */ + MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x8 /* SPI3_GPIO1 */ + >; + }; + + pinctrl_spi3_gpio: spi3gpiogrp { + fsl,pins = < + MX6UL_PAD_UART2_RX_DATA__GPIO1_IO21 0x8 /* SPI3_SCK / X803.4 */ + MX6UL_PAD_UART2_CTS_B__GPIO1_IO22 0x8 /* SPI3_MOSI / X803.2 */ + MX6UL_PAD_UART2_RTS_B__GPIO1_IO23 0x8 /* SPI3_MISO / X803.3 */ + MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x8 /* SPI3_SS0 / X803.1 */ + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0x8 /* SPI3_GPIO0 / X803.9 */ + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x8 /* SPI3_INT / X803.7 */ + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x8 /* SPI3_RESET / X803.8 */ + MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x8 /* SPI3_GPIO1 / X803.10 */ + >; + }; + + pinctrl_version: versiongrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x8 /* */ + MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x8 /* */ + MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x8 /* */ + MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x8 /* */ + >; + }; + + /delete-node/ pinctrl_enet1; + + pinctrl_enet1_igrisp: enet1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b010 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b010 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b010 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b010 + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0x17059 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b010 /* ENET2_TX_D0 */ + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b010 /* ENET2_TX_D1 */ + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b010 /* ENET2_TX_EN */ + MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b010 /* ENET2_TX_CLK */ + + MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 /* ENET2_RX_D0 */ + MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 /* ENET2_RX_D1 */ + MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 /* ENET2_RX_EN */ + MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 /* ENET2_RX_ER */ + + MX6UL_PAD_NAND_DQS__GPIO4_IO16 0x8 /* ENET2_INT */ + + MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x10010 + MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x10010 + >; + }; + + pinctrl_gpioleds_grisp2: gpioledsgrisp2grp { + fsl,pins = < + MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25 0x00088 /* MCU_LED */ + MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x00088 /* RFId_LED */ + >; + }; +};