From bda0d303afc65811bf32e5067d3fb92306004186 Mon Sep 17 00:00:00 2001 From: bigmagic Date: Sat, 28 Nov 2020 18:27:24 +0800 Subject: [PATCH] add raspi4 driver --- bsp/raspberry-pi/raspi4-32/.config | 15 +- bsp/raspberry-pi/raspi4-32/driver/Kconfig | 28 +- bsp/raspberry-pi/raspi4-32/driver/board.c | 2 +- bsp/raspberry-pi/raspi4-32/driver/drv_i2c.c | 368 ++++++++++++++++++++ bsp/raspberry-pi/raspi4-32/driver/drv_i2c.h | 59 ++++ bsp/raspberry-pi/raspi4-32/driver/raspi4.h | 17 + bsp/raspberry-pi/raspi4-32/rtconfig.h | 4 + 7 files changed, 490 insertions(+), 3 deletions(-) create mode 100644 bsp/raspberry-pi/raspi4-32/driver/drv_i2c.c create mode 100644 bsp/raspberry-pi/raspi4-32/driver/drv_i2c.h diff --git a/bsp/raspberry-pi/raspi4-32/.config b/bsp/raspberry-pi/raspi4-32/.config index 041075c70e..dc8b2ab72b 100644 --- a/bsp/raspberry-pi/raspi4-32/.config +++ b/bsp/raspberry-pi/raspi4-32/.config @@ -151,7 +151,10 @@ CONFIG_RT_SERIAL_RB_BUFSZ=64 # CONFIG_RT_USING_CAN is not set # CONFIG_RT_USING_HWTIMER is not set # CONFIG_RT_USING_CPUTIME is not set -# CONFIG_RT_USING_I2C is not set +CONFIG_RT_USING_I2C=y +# CONFIG_RT_I2C_DEBUG is not set +CONFIG_RT_USING_I2C_BITOPS=y +# CONFIG_RT_I2C_BITOPS_DEBUG is not set # CONFIG_RT_USING_PHY is not set CONFIG_RT_USING_PIN=y # CONFIG_RT_USING_ADC is not set @@ -502,6 +505,8 @@ CONFIG_RT_LWIP_USING_PING=y # CONFIG_PKG_USING_AD7746 is not set # CONFIG_PKG_USING_PCA9685 is not set # CONFIG_PKG_USING_I2C_TOOLS is not set +# CONFIG_PKG_USING_I2C_TOOLS_V100 is not set +# CONFIG_PKG_USING_I2C_TOOLS_LATEST_VERSION is not set # CONFIG_PKG_USING_NRF24L01 is not set # CONFIG_PKG_USING_TOUCH_DRIVERS is not set # CONFIG_PKG_USING_MAX17048 is not set @@ -526,6 +531,7 @@ CONFIG_RT_LWIP_USING_PING=y # CONFIG_PKG_USING_LY68L6400 is not set # CONFIG_PKG_USING_DM9051 is not set # CONFIG_PKG_USING_SSD1306 is not set +# CONFIG_PKG_USING_SSD1306_LATEST_VERSION is not set # CONFIG_PKG_USING_QKEY is not set # @@ -634,6 +640,13 @@ CONFIG_BSP_USING_SPI=y CONFIG_BSP_USING_SPI0_BUS=y CONFIG_BSP_USING_SPI0_DEVICE0=y CONFIG_BSP_USING_SPI0_DEVICE1=y +CONFIG_BSP_USING_I2C=y +# CONFIG_BSP_USING_I2C0 is not set +# CONFIG_BSP_USING_I2C1 is not set +CONFIG_BSP_USING_I2C3=y +# CONFIG_BSP_USING_I2C4 is not set +# CONFIG_BSP_USING_I2C5 is not set +# CONFIG_BSP_USING_I2C6 is not set CONFIG_BSP_USING_CORETIMER=y # CONFIG_BSP_USING_SYSTIMER is not set CONFIG_BSP_USING_WDT=y diff --git a/bsp/raspberry-pi/raspi4-32/driver/Kconfig b/bsp/raspberry-pi/raspi4-32/driver/Kconfig index 42a1045e60..8d3f4f2399 100644 --- a/bsp/raspberry-pi/raspi4-32/driver/Kconfig +++ b/bsp/raspberry-pi/raspi4-32/driver/Kconfig @@ -50,7 +50,7 @@ menu "Hardware Drivers Config" select RT_USING_PIN default y - menuconfig BSP_USING_SPI + menuconfig BSP_USING_SPI bool "Enable SPI" select RT_USING_SPI default n @@ -69,6 +69,32 @@ menu "Hardware Drivers Config" default n endif + menuconfig BSP_USING_I2C + bool "Enable I2C" + select RT_USING_I2C + default n + + if BSP_USING_I2C + config BSP_USING_I2C0 + bool "Enable I2C0 BUS" + default n + config BSP_USING_I2C1 + bool "Enable I2C1 BUS" + default n + config BSP_USING_I2C3 + bool "Enable I2C3 BUS" + default n + config BSP_USING_I2C4 + bool "Enable I2C4 BUS" + default n + config BSP_USING_I2C5 + bool "Enable I2C5 BUS" + default n + config BSP_USING_I2C6 + bool "Enable I2C6 BUS" + default n + endif + config BSP_USING_CORETIMER bool "Using core timer" select RT_USING_CORETIMER diff --git a/bsp/raspberry-pi/raspi4-32/driver/board.c b/bsp/raspberry-pi/raspi4-32/driver/board.c index 3e81b2e537..01b3a79882 100644 --- a/bsp/raspberry-pi/raspi4-32/driver/board.c +++ b/bsp/raspberry-pi/raspi4-32/driver/board.c @@ -24,7 +24,7 @@ struct mem_desc platform_mem_desc[] = { {0x0E000000, 0x0EE00000, 0x0E000000, DEVICE_MEM}, //framebuffer {0x0F400000, 0x0FA00000, 0x0F400000, DEVICE_MEM}, //dsi_touch {0xFD500000, 0xFDA00000, 0xFD500000, DEVICE_MEM}, //gmac - {0xFE000000, 0xFE400000, 0xFE000000, DEVICE_MEM}, //peripheral + {0xFE000000, 0xFEA00000, 0xFE000000, DEVICE_MEM}, //peripheral {0xFF800000, 0xFFA00000, 0xFF800000, DEVICE_MEM} //gic }; diff --git a/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.c b/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.c new file mode 100644 index 0000000000..f596eccc89 --- /dev/null +++ b/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-11-28 bigmagic first version + */ + +#include "drv_i2c.h" +#include "drv_gpio.h" +#include "raspi4.h" +#include "mbox.h" + +/* +* (3.3v) -1 2- +* (SDA1/SDA3) -3 4- +* (SCL1/SCL3) -5 6- +* (SDA3) -7 8- +* -9 10- +* -11 12- +* -13 14- +* -15 16- +* -17 18- +* -19 20- +* (SCL4) -21 22- +* -23 24- (SDA4) +* -25 26- (SCL4) +* -27 28- +* (SCL3) -29 30- +* (SDA4) -31 32- +*/ + +#define DBG_TAG "drv.i2c" +#define DBG_LVL DBG_INFO +#include + +struct raspi_i2c_hw_config +{ + rt_uint32_t bsc_num; + rt_uint32_t bsc_rate; + rt_uint32_t bsc_address; + rt_uint32_t sda_pin; + rt_uint32_t scl_pin; + rt_uint32_t sda_mode; + rt_uint32_t scl_mode; +}; + +rt_uint8_t i2c_read_or_write(volatile rt_uint32_t base, rt_uint8_t* buf, rt_uint32_t len, rt_uint8_t flag) +{ + rt_uint32_t status; + rt_uint32_t remaining = len; + rt_uint32_t i = 0; + rt_uint8_t reason = I2C_REASON_OK; + + /* Clear FIFO */ + BSC_C(base) |= (BSC_C_CLEAR_1 & BSC_C_CLEAR_1); + /* Clear Status */ + BSC_S(base) = BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE; + /* Set Data Length */ + BSC_DLEN(base) = len; + if (flag) + { + /* Start read */ + BSC_C(base) = BSC_C_I2CEN | BSC_C_ST | BSC_C_READ; + /* wait for transfer to complete */ + while (!(BSC_S(base) & BSC_S_DONE)) + { + /* we must empty the FIFO as it is populated and not use any delay */ + while (remaining && (BSC_S(base) & BSC_S_RXD)) + { + /* Read from FIFO, no barrier */ + buf[i] = BSC_FIFO(base); + i++; + remaining--; + } + } + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (BSC_S(base) & BSC_S_RXD)) + { + /* Read from FIFO, no barrier */ + buf[i] = BSC_FIFO(base); + i++; + remaining--; + } + } + else + { + LOG_D("i2c%d write start", flag); + /* pre populate FIFO with max buffer */ + while (remaining && (i < BSC_FIFO_SIZE)) + { + BSC_FIFO(base) = buf[i]; + i++; + remaining--; + } + + /* Enable device and start transfer */ + BSC_C(base) = BSC_C_I2CEN | BSC_C_ST; + + /* Transfer is over when BCM2835_BSC_S_DONE */ + while (!(BSC_S(base) & BSC_S_DONE)) + { + while (remaining && (BSC_S(base) & BSC_S_TXD)) + { + /* Write to FIFO */ + BSC_FIFO(base) = buf[i]; + i++; + remaining--; + } + } + LOG_D("i2c%d write end", flag); + } + + status = BSC_S(base); + if (status & BSC_S_ERR) + { + reason = I2C_REASON_ERROR_NACK; + } + else if (status & BSC_S_CLKT) + { + reason = I2C_REASON_ERROR_CLKT; + } + else if (remaining) + { + reason = I2C_REASON_ERROR_DATA; + } + BSC_C(base) |= (BSC_S_DONE & BSC_S_DONE); + + return reason; +} + +static rt_size_t raspi_i2c_mst_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num) +{ + rt_size_t i; + rt_uint8_t reason; + RT_ASSERT(bus != RT_NULL); + + struct raspi_i2c_hw_config *i2c_hw_config = (struct raspi_i2c_hw_config*)(bus->priv); + + //Slave Address + BSC_A(i2c_hw_config->bsc_address) = msgs->addr; + + for (i = 0; i < num; i++) + { + if (msgs[i].flags & RT_I2C_RD) + reason = i2c_read_or_write(i2c_hw_config->bsc_address, msgs->buf, msgs->len, 1); + else + reason = i2c_read_or_write(i2c_hw_config->bsc_address, msgs->buf, msgs->len, 0); + } + return (reason == 0)? i : 0; +} + +static rt_size_t raspi_i2c_slv_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num) +{ + return 0; +} + +static rt_err_t raspi_i2c_bus_control(struct rt_i2c_bus_device *bus, + rt_uint32_t cmd, + rt_uint32_t arg) +{ + return RT_EOK; +} + + +static rt_err_t raspi_i2c_configure(struct raspi_i2c_hw_config *cfg) +{ + RT_ASSERT(cfg != RT_NULL); + rt_uint32_t apb_clock = 0; + prev_raspi_pin_mode(cfg->sda_pin, cfg->sda_mode);//sda + prev_raspi_pin_mode(cfg->scl_pin, cfg->scl_mode);//scl + /* use 0xFFFE mask to limit a max value and round down any odd number */ + apb_clock = bcm271x_mbox_clock_get_rate(CORE_CLK_ID); + rt_uint32_t divider = (apb_clock / cfg->bsc_rate) & 0xFFFE; + + BSC_DIV(cfg->bsc_address) = (rt_uint16_t)divider; + + return RT_EOK; +} + +static const struct rt_i2c_bus_device_ops raspi_i2c_ops = +{ + .master_xfer = raspi_i2c_mst_xfer, + .slave_xfer = raspi_i2c_slv_xfer, + .i2c_bus_control = raspi_i2c_bus_control, +}; + +#if defined (BSP_USING_I2C0) +#define I2C0_BUS_NAME "i2c0" +static struct raspi_i2c_hw_config hw_device0 = +{ + .bsc_num = 0, + .bsc_rate = 100000,//100k + .bsc_address = BSC0_BASE, + .sda_pin = GPIO_PIN_0, + .scl_pin = GPIO_PIN_1, + .sda_mode = ALT0, + .scl_mode = ALT0, +}; + +struct rt_i2c_bus_device device0 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device0, +}; +#endif + +#if defined (BSP_USING_I2C1) +#define I2C1_BUS_NAME "i2c1" +static struct raspi_i2c_hw_config hw_device1 = +{ + .bsc_num = 1, + .bsc_rate = 100000,//100k + .bsc_address = BSC1_BASE, + .sda_pin = GPIO_PIN_2, + .scl_pin = GPIO_PIN_3, + .sda_mode = ALT0, + .scl_mode = ALT0, +}; + +struct rt_i2c_bus_device device1 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device1, +}; +#endif + +#if defined (BSP_USING_I2C3) +#define I2C3_BUS_NAME "i2c3" +static struct raspi_i2c_hw_config hw_device3 = +{ + .bsc_num = 3, + .bsc_rate = 100000,//100k + .bsc_address = BSC3_BASE, +#ifndef BSP_USING_I2C3_0 + .sda_pin = GPIO_PIN_2, + .scl_pin = GPIO_PIN_3, +#else + .sda_pin = GPIO_PIN_4, + .scl_pin = GPIO_PIN_5, +#endif + .sda_mode = ALT5, + .scl_mode = ALT5, +}; + +struct rt_i2c_bus_device device3 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device3, +}; +#endif + +#if defined (BSP_USING_I2C4) +#define I2C4_BUS_NAME "i2c4" +static struct raspi_i2c_hw_config hw_device4 = +{ + .bsc_num = 4, + .bsc_rate = 100000,//100k + .bsc_address = BSC4_BASE, +#ifdef BSP_USING_I2C4_0 + .sda_pin = GPIO_PIN_6, + .scl_pin = GPIO_PIN_7, +#else + .sda_pin = GPIO_PIN_8, + .scl_pin = GPIO_PIN_9, +#endif + .sda_mode = ALT5, + .scl_mode = ALT5, +}; + +struct rt_i2c_bus_device device4 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device4, +}; +#endif + +#if defined (BSP_USING_I2C5) +#define I2C5_BUS_NAME "i2c5" +static struct raspi_i2c_hw_config hw_device5 = +{ + .bsc_num = 5, + .bsc_rate = 100000,//100k + .bsc_address = BSC5_BASE, +#ifdef BSP_USING_I2C5_0 + .sda_pin = GPIO_PIN_10, + .scl_pin = GPIO_PIN_11, +#else + .sda_pin = GPIO_PIN_12, + .scl_pin = GPIO_PIN_13, +#endif + .sda_mode = ALT5, + .scl_mode = ALT5, +}; + +struct rt_i2c_bus_device device5 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device5, +}; +#endif + +#if defined (BSP_USING_I2C6) +#define I2C6_BUS_NAME "i2c6" +static struct raspi_i2c_hw_config hw_device6 = +{ + .bsc_num = 6, + .bsc_rate = 100000,//100k + .bsc_address = BSC6_BASE, +#ifdef BSP_USING_I2C5_0 + .sda_pin = GPIO_PIN_0, + .scl_pin = GPIO_PIN_1, +#else + .sda_pin = GPIO_PIN_22, + .scl_pin = GPIO_PIN_23, +#endif + .sda_mode = ALT5, + .scl_mode = ALT5, +}; + +struct rt_i2c_bus_device device6 = +{ + .ops = &raspi_i2c_ops, + .priv = (void *)&hw_device6, +}; +#endif + +int rt_hw_i2c_init(void) +{ +#if defined(BSP_USING_I2C0) + raspi_i2c_configure(&hw_device0); + rt_i2c_bus_device_register(&device0, I2C0_BUS_NAME); +#endif + +#if defined(BSP_USING_I2C1) + raspi_i2c_configure(&hw_device1); + rt_i2c_bus_device_register(&device1, I2C1_BUS_NAME); +#endif + +#if defined(BSP_USING_I2C3) + raspi_i2c_configure(&hw_device3); + rt_i2c_bus_device_register(&device3, I2C3_BUS_NAME); +#endif + +#if defined(BSP_USING_I2C4) + raspi_i2c_configure(&hw_device4); + rt_i2c_bus_device_register(&device4, I2C4_BUS_NAME); +#endif + +#if defined(BSP_USING_I2C5) + raspi_i2c_configure(&hw_device5); + rt_i2c_bus_device_register(&device5, I2C5_BUS_NAME); +#endif + +#if defined(BSP_USING_I2C6) + raspi_i2c_configure(&hw_device6); + rt_i2c_bus_device_register(&device6, I2C6_BUS_NAME); +#endif + return 0; +} + +INIT_DEVICE_EXPORT(rt_hw_i2c_init); diff --git a/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.h b/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.h new file mode 100644 index 0000000000..e02c8887f0 --- /dev/null +++ b/bsp/raspberry-pi/raspi4-32/driver/drv_i2c.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-11-28 bigmagic first version + */ + +#ifndef __DRV_I2C_H__ +#define __DRV_I2C_H__ + +#include + +#define BSC_C(BASE) __REG32(BASE + 0x0000) /* BSC Master Control */ +#define BSC_S(BASE) __REG32(BASE + 0x0004) /* BSC Master Status */ +#define BSC_DLEN(BASE) __REG32(BASE + 0x0008) /* BSC Master Data Length */ +#define BSC_A(BASE) __REG32(BASE + 0x000c) /* BSC Master Slave Address */ +#define BSC_FIFO(BASE) __REG32(BASE + 0x0010) /* BSC Master Data FIFO */ +#define BSC_DIV(BASE) __REG32(BASE + 0x0014) /* BSC Master Clock Divider */ +#define BSC_DEL(BASE) __REG32(BASE + 0x0018) /* BSC Master Data Delay */ +#define BSC_CLKT(BASE) __REG32(BASE + 0x001c) /* BSC Master Clock Stretch Timeout */ + +/* Register masks for C Register */ +#define BSC_C_I2CEN (0x00008000) /* I2C Enable, 0 = disabled, 1 = enabled */ +#define BSC_C_INTR (0x00000400) /* Interrupt on RX */ +#define BSC_C_INTT (0x00000200) /* Interrupt on TX */ +#define BSC_C_INTD (0x00000100) /* Interrupt on DONE */ +#define BSC_C_ST (0x00000080) /* Start transfer, 1 = Start a new transfer */ +#define BSC_C_CLEAR_1 (0x00000020) /* Clear FIFO Clear */ +#define BSC_C_CLEAR_2 (0x00000010) /* Clear FIFO Clear */ +#define BSC_C_READ (0x00000001) /* Read transfer */ + +/* Register masks for S Register */ +#define BSC_S_CLKT (0x00000200) /* Clock stretch timeout */ +#define BSC_S_ERR (0x00000100) /* ACK error */ +#define BSC_S_RXF (0x00000080) /* RXF FIFO full, 0 = FIFO is not full, 1 = FIFO is full */ +#define BSC_S_TXE (0x00000040) /* TXE FIFO full, 0 = FIFO is not full, 1 = FIFO is full */ +#define BSC_S_RXD (0x00000020) /* RXD FIFO contains data */ +#define BSC_S_TXD (0x00000010) /* TXD FIFO can accept data */ +#define BSC_S_RXR (0x00000008) /* RXR FIFO needs reading (full) */ +#define BSC_S_TXW (0x00000004) /* TXW FIFO needs writing (full) */ +#define BSC_S_DONE (0x00000002) /* Transfer DONE */ +#define BSC_S_TA (0x00000001) /* Transfer Active */ + +#define BSC_FIFO_SIZE (16) /* BSC FIFO size */ + +typedef enum +{ + I2C_REASON_OK = 0x00, /* Success */ + I2C_REASON_ERROR_NACK = 0x01, /* Received a NACK */ + I2C_REASON_ERROR_CLKT = 0x02, /* Received Clock Stretch Timeout */ + I2C_REASON_ERROR_DATA = 0x04 /* Not all data is sent / received */ +} i2c_reason_codes; + +int rt_hw_i2c_init(void); + +#endif diff --git a/bsp/raspberry-pi/raspi4-32/driver/raspi4.h b/bsp/raspberry-pi/raspi4-32/driver/raspi4.h index 9db1252bc0..72e212ff85 100644 --- a/bsp/raspberry-pi/raspi4-32/driver/raspi4.h +++ b/bsp/raspberry-pi/raspi4-32/driver/raspi4.h @@ -154,6 +154,23 @@ typedef enum { #define ETH_IRQ (160+29) +//I2C +#define BSC0_BASE_OFFSET (0x205000) +#define BSC1_BASE_OFFSET (0x804000) +#define BSC3_BASE_OFFSET (0x205600) +#define BSC4_BASE_OFFSET (0x205800) +#define BSC5_BASE_OFFSET (0x205A80) +#define BSC6_BASE_OFFSET (0x205C00) + +//BSC2 and BSC7 masters are dedicated for use by the +//HDMI interfaces and should not be accessed byuser programs. +#define BSC0_BASE (PER_BASE + BSC0_BASE_OFFSET) +#define BSC1_BASE (PER_BASE + BSC1_BASE_OFFSET) +#define BSC3_BASE (PER_BASE + BSC3_BASE_OFFSET) +#define BSC4_BASE (PER_BASE + BSC4_BASE_OFFSET) +#define BSC5_BASE (PER_BASE + BSC5_BASE_OFFSET) +#define BSC6_BASE (PER_BASE + BSC6_BASE_OFFSET) + /* the basic constants and interfaces needed by gic */ rt_inline rt_uint32_t platform_get_gic_dist_base(void) { diff --git a/bsp/raspberry-pi/raspi4-32/rtconfig.h b/bsp/raspberry-pi/raspi4-32/rtconfig.h index 031b5c43ba..a6078b7b1e 100644 --- a/bsp/raspberry-pi/raspi4-32/rtconfig.h +++ b/bsp/raspberry-pi/raspi4-32/rtconfig.h @@ -100,6 +100,8 @@ #define RT_USING_SERIAL #define RT_SERIAL_USING_DMA #define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS #define RT_USING_PIN #define RT_USING_SDIO #define RT_SDIO_STACK_SIZE 512 @@ -258,6 +260,8 @@ #define BSP_USING_SPI0_BUS #define BSP_USING_SPI0_DEVICE0 #define BSP_USING_SPI0_DEVICE1 +#define BSP_USING_I2C +#define BSP_USING_I2C3 #define BSP_USING_CORETIMER #define BSP_USING_WDT #define BSP_USING_ETH