diff --git a/bsps/aarch64/raspberrypi/i2c/raspberrypi-i2c.c b/bsps/aarch64/raspberrypi/i2c/raspberrypi-i2c.c index 191f437921..6d43277ce6 100644 --- a/bsps/aarch64/raspberrypi/i2c/raspberrypi-i2c.c +++ b/bsps/aarch64/raspberrypi/i2c/raspberrypi-i2c.c @@ -65,6 +65,7 @@ typedef struct { i2c_bus base; + rtems_binary_semaphore sem; uint32_t input_clock; uintptr_t base_address; raspberrypi_bsc_masters device; @@ -75,65 +76,54 @@ typedef struct { bool read_transfer; } raspberrypi_i2c_bus; -static int i2c_polling_read( raspberrypi_i2c_bus *bus ) +static int rpi_i2c_bus_transfer( raspberrypi_i2c_bus *bus ) { - while ( !( S_REG( bus ) & S_DONE ) && ( bus->remaining_bytes > 0 ) ) { - while ( ( S_REG( bus ) & S_RXD ) && ( bus->remaining_bytes > 0 ) ) { + while ( bus->remaining_bytes > 0 ) { + if ( bus->read_transfer ) { + while ( ( S_REG( bus ) & ( S_RXD | S_CLKT ) ) == 0 ) { + } + if ( S_REG( bus ) & S_CLKT ) { + return -EIO; + } *bus->current_buffer = BCM2835_REG( bus->base_address + BCM2711_I2C_FIFO ) & BCM2711_I2C_FIFO_MASK; - bus->current_buffer++; - bus->remaining_bytes--; - /* Check for errors */ - if ( S_REG( bus ) & ( S_CLKT | S_ERR ) ) { + ++bus->current_buffer; + if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) ) { + return -EIO; + } + } else { +#ifdef BSP_I2C_USE_INTERRUPTS + C_REG( bus ) |= C_INTT; + + if ( rtems_binary_semaphore_wait_timed_ticks( + &bus->sem, + bus->base.timeout + ) != RTEMS_SUCCESSFUL ) { + rtems_binary_semaphore_try_wait( &bus->sem ); + return -ETIMEDOUT; + } +#else + while ( ( S_REG( bus ) & ( S_TXW | S_CLKT ) ) == 0 ) { + } + if ( S_REG( bus ) & S_CLKT ) { + return -EIO; + } +#endif + BCM2835_REG( + bus->base_address + BCM2711_I2C_FIFO + ) = *bus->current_buffer; + + ++bus->current_buffer; + if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) ) { return -EIO; } } - } - return 0; -} - -static int i2c_polling_write( raspberrypi_i2c_bus *bus ) -{ - while ( !( S_REG( bus ) & S_DONE ) && ( bus->remaining_bytes > 0 ) ) { - while ( bus->remaining_bytes > 0 && ( S_REG( bus ) & S_TXD ) ) { - BCM2835_REG( bus->base_address + BCM2711_I2C_FIFO ) = *( - bus->current_buffer - ); - bus->current_buffer++; - bus->remaining_bytes--; - - /* Check for errors */ - if ( S_REG( bus ) & ( S_CLKT | S_ERR ) ) { - return -EIO; - } - } - } - return 0; -} - -static int rpi_i2c_bus_transfer( raspberrypi_i2c_bus *bus ) -{ - int rv; - if ( bus->read_transfer ) { - rv = i2c_polling_read( bus ); - if ( rv < 0 ) { - return rv; - } - } else { - rv = i2c_polling_write( bus ); - if ( rv < 0 ) { - return rv; - } - } - if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) || - ( bus->remaining_bytes != 0 ) ) { - return -EIO; + --bus->remaining_bytes; } - S_REG( bus ) = S_DONE; return 0; } @@ -172,9 +162,10 @@ static int rpi_i2c_setup_and_transfer( raspberrypi_i2c_bus *bus ) BCM2711_I2C_DLEN_MASK : ( bus->current_buffer_size & BCM2711_I2C_DLEN_MASK ); - BCM2835_REG( bus->base_address + BCM2711_I2C_DLEN ) = bus->remaining_bytes; + BCM2835_REG( bus->base_address + BCM2711_I2C_DLEN ) = bus->remaining_bytes; /* Clear the error bits before starting new transfer */ - S_REG( bus ) = S_ERROR; + S_REG( bus ) = S_ERROR; + C_REG( bus ) |= C_ST; rv = rpi_i2c_bus_transfer( bus ); @@ -182,11 +173,41 @@ static int rpi_i2c_setup_and_transfer( raspberrypi_i2c_bus *bus ) return rv; } +#ifdef BSP_I2C_USE_INTERRUPTS + C_REG( bus ) |= C_INTD; + if ( rtems_binary_semaphore_wait_timed_ticks( + &bus->sem, + bus->base.timeout + ) != 0 ) { + rtems_binary_semaphore_try_wait( &bus->sem ); + return -ETIMEDOUT; + } +#else + while ( ( S_REG( bus ) & ( S_DONE | S_CLKT ) ) == 0 ) { + } + if ( S_REG( bus ) & S_CLKT ) { + return -EIO; + } +#endif + --bus->remaining_transfers; } return 0; } +#ifdef BSP_I2C_USE_INTERRUPTS +static void i2c_handler( void *args ) +{ + raspberrypi_i2c_bus *bus = (raspberrypi_i2c_bus *) args; + if ( C_REG( bus ) & C_INTT ) { + C_REG( bus ) &= ~C_INTT; + } else if ( C_REG( bus ) & C_INTD ) { + C_REG( bus ) &= ~C_INTD; + } + rtems_binary_semaphore_post( &bus->sem ); +} +#endif + static int rpi_i2c_transfer( i2c_bus *base, i2c_msg *msgs, uint32_t msg_count ) { raspberrypi_i2c_bus *bus = (raspberrypi_i2c_bus *) base; @@ -231,10 +252,11 @@ static int rpi_i2c_transfer( i2c_bus *base, i2c_msg *msgs, uint32_t msg_count ) } if ( msgs[ i ].flags & I2C_M_RD ) { - C_REG( bus ) |= C_CLEAR | C_READ | C_ST; // Read packet transfer + C_REG( bus ) |= C_CLEAR | C_READ; bus->read_transfer = true; } else { - C_REG( bus ) |= C_CLEAR | C_ST; // Write packet transfer + C_REG( bus ) |= C_CLEAR; + C_REG( bus ) &= ~C_READ; bus->read_transfer = false; } /* Disable clock stretch timeout */ @@ -346,6 +368,20 @@ rtems_status_code rpi_i2c_init( C_REG( bus ) = C_CLEAR; C_REG( bus ) = C_I2CEN; +#ifdef BSP_I2C_USE_INTERRUPTS + sc = rtems_interrupt_handler_install( + BCM2711_IRQ_I2C, + "I2C", + RTEMS_INTERRUPT_SHARED, + (rtems_interrupt_handler) i2c_handler, + bus + ); + rtems_binary_semaphore_init( &bus->sem, "RPII2C" ); + if ( sc != RTEMS_SUCCESSFUL ) { + return -EIO; + } +#endif + sc = rpi_i2c_set_clock( &bus->base, bus_clock ); if ( sc != RTEMS_SUCCESSFUL ) { i2c_bus_destroy_and_free( &bus->base ); diff --git a/bsps/aarch64/raspberrypi/include/bsp/irq.h b/bsps/aarch64/raspberrypi/include/bsp/irq.h index ad22d7f42f..35eef23e7c 100644 --- a/bsps/aarch64/raspberrypi/include/bsp/irq.h +++ b/bsps/aarch64/raspberrypi/include/bsp/irq.h @@ -71,6 +71,9 @@ extern "C" { /* Interrupt Vectors: SPI */ #define BCM2711_IRQ_SPI (BCM2711_IRQ_VC_PERIPHERAL_BASE + 54) +/* Interrupt Vectors: I2C */ +#define BCM2711_IRQ_I2C ( BCM2711_IRQ_VC_PERIPHERAL_BASE + 53 ) + /* Interrupt Vectors: Videocore */ #define BCM2711_IRQ_VC_PERIPHERAL_BASE 96 #define BCM2711_IRQ_AUX (BCM2711_IRQ_VC_PERIPHERAL_BASE + 29) diff --git a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml index d73cec5075..1f5b18d4c4 100644 --- a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml +++ b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml @@ -23,6 +23,8 @@ links: uid: optcorerate - role: build-dependency uid: optspiirq +- role: build-dependency + uid: opti2cirq - role: build-dependency uid: objclock - role: build-dependency diff --git a/spec/build/bsps/aarch64/raspberrypi/opti2cirq.yml b/spec/build/bsps/aarch64/raspberrypi/opti2cirq.yml new file mode 100644 index 0000000000..be39e580e2 --- /dev/null +++ b/spec/build/bsps/aarch64/raspberrypi/opti2cirq.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-boolean: null +- define-condition: null +build-type: option +copyrights: +- Copyright (C) 2025 Shaunak Datar +default: +- enabled-by: true + value: true +description: | + Use interrupt mode in the I2C driver. +enabled-by: true +format: '{}' +links: [] +name: BSP_I2C_USE_INTERRUPTS +type: build