diff --git a/bsp/README.md b/bsp/README.md index 9fd1e080c2..5803d41fba 100644 --- a/bsp/README.md +++ b/bsp/README.md @@ -271,14 +271,14 @@ This document is based on the RT-Thread mainline repository and categorizes the #### 🟡 Raspberry Pi -| BSP Name | GPIO | UART | I2C | SPI | RTC | SD Card | SDIO | MailBox | WDT | SMP | HDMI | Timer | Bluetooth | Ethernet | MIPI DSI | ILI9486 SPI LCD | XPT2046 TOUCH | -|----------|------|------|-----|-----|-----|---------|------|---------|-----|-----|------|-------|-----------|----------|----------|-----------------|----------------| -| [raspi-dm2.0](raspberry-pi/raspi-dm2.0) | - | ✅ | - | - | - | ✅ | - | - | - | - | - | - | - | - | - | - | - | -| [raspi2](raspberry-pi/raspi2) | - | ✅ | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | -| [raspi3-32](raspberry-pi/raspi3-32) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | - | - | - | -| [raspi3-64](raspberry-pi/raspi3-64) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | - | ✅ | ✅ | - | - | - | - | - | -| [raspi4-32](raspberry-pi/raspi4-32) | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [raspi4-64](raspberry-pi/raspi4-64) | ✅ | ✅ | - | ✅ | - | - | ✅ | ✅ | ✅ | - | ✅ | ✅ | - | ✅ | - | - | - | +| BSP Name | GPIO | UART | I2C | SPI | RTC | SD Card | SDIO | MailBox | WDT | SMP | HDMI | Timer | Bluetooth | Ethernet | PCIe | DMA | ADC | PWM | MIPI DSI | ILI9486 SPI LCD | XPT2046 TOUCH | +|----------|------|------|-----|-----|-----|---------|------|---------|-----|-----|------|-------|-----------|----------|------|-----|-----|-----|----------|-----------------|----------------| +| [raspi2](raspberry-pi/raspi2) | - | ✅ | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | +| [raspi3-32](raspberry-pi/raspi3-32) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | - | - | - | - | - | - | - | +| [raspi3-64](raspberry-pi/raspi3-64) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | - | ✅ | - | ✅ | - | - | - | +| [raspi4-32](raspberry-pi/raspi4-32) | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - | - | - | ✅ | ✅ | ✅ | +| [raspi4-64](raspberry-pi/raspi4-64) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | - | ✅ | - | ✅ | ✅ | +| [raspi5](raspberry-pi/raspi5) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | #### 🟡 AT32 diff --git a/bsp/raspberry-pi/.gitignore b/bsp/raspberry-pi/.gitignore new file mode 100644 index 0000000000..b2033bca9f --- /dev/null +++ b/bsp/raspberry-pi/.gitignore @@ -0,0 +1,8 @@ +kernel*.img +rtthread.bin +*.dtb +*.qcow2 +flash.bin +rtt.asm +rtthread.map +build/ diff --git a/bsp/raspberry-pi/dm/Kconfig b/bsp/raspberry-pi/dm/Kconfig new file mode 100755 index 0000000000..2bb0202a03 --- /dev/null +++ b/bsp/raspberry-pi/dm/Kconfig @@ -0,0 +1,33 @@ +SOC_DM_ADC_DIR = $(SOC_DM_DIR)/adc +SOC_DM_AUDIO_DIR = $(SOC_DM_DIR)/audio +SOC_DM_CLK_DIR = $(SOC_DM_DIR)/clk +SOC_DM_DMA_DIR = $(SOC_DM_DIR)/dma +SOC_DM_DVFS_CPUFREQ_DIR = $(SOC_DM_DIR)/dvfs +SOC_DM_ETHERNET_DIR = $(SOC_DM_DIR)/ethernet +SOC_DM_FIRMWARE_DIR = $(SOC_DM_DIR)/firmware +SOC_DM_GRAPHIC_BACKLIGHT_DIR = $(SOC_DM_DIR)/graphic/backlight +SOC_DM_GRAPHIC_FB_DIR = $(SOC_DM_DIR)/graphic/framebuffer +SOC_DM_GRAPHIC_LOGO_DIR = $(SOC_DM_DIR)/graphic/logo +SOC_DM_HWCRYPTO_DIR = $(SOC_DM_DIR)/hwcrypto +SOC_DM_CLOCK_TIME_DIR = $(SOC_DM_DIR)/clock_time +SOC_DM_I2C_DIR = $(SOC_DM_DIR)/i2c +SOC_DM_INPUT_JOYSTICK_DIR = $(SOC_DM_DIR)/input/joystick +SOC_DM_INPUT_TOUCHSCREEN_DIR = $(SOC_DM_DIR)/input/touchscreen +SOC_DM_MBOX_DIR = $(SOC_DM_DIR)/mailbox +SOC_DM_MFD_DIR = $(SOC_DM_DIR)/mfd +SOC_DM_NVMEM_DIR = $(SOC_DM_DIR)/nvmem +SOC_DM_PCI_DIR = $(SOC_DM_DIR)/pci +SOC_DM_PHY_DIR = $(SOC_DM_DIR)/phy +SOC_DM_PIC_DIR = $(SOC_DM_DIR)/pic +SOC_DM_PIN_DIR = $(SOC_DM_DIR)/pin +SOC_DM_PINCTRL_DIR = $(SOC_DM_DIR)/pinctrl +SOC_DM_PMDOMAIN_DIR = $(SOC_DM_DIR)/pmdomain +SOC_DM_PWM_DIR = $(SOC_DM_DIR)/pwm +SOC_DM_RESET_DIR = $(SOC_DM_DIR)/reset +SOC_DM_RTC_DIR = $(SOC_DM_DIR)/rtc +SOC_DM_SDIO_DIR = $(SOC_DM_DIR)/sdio +SOC_DM_SERIAL_DIR = $(SOC_DM_DIR)/serial +SOC_DM_SOC_DIR = $(SOC_DM_DIR)/soc +SOC_DM_SPI_DIR = $(SOC_DM_DIR)/spi +SOC_DM_THERMAL_DIR = $(SOC_DM_DIR)/thermal +SOC_DM_WDT_DIR = $(SOC_DM_DIR)/watchdog diff --git a/bsp/raspberry-pi/raspi-dm2.0/SConscript b/bsp/raspberry-pi/dm/SConscript old mode 100644 new mode 100755 similarity index 92% rename from bsp/raspberry-pi/raspi-dm2.0/SConscript rename to bsp/raspberry-pi/dm/SConscript index c7ef7659ec..3d15055d62 --- a/bsp/raspberry-pi/raspi-dm2.0/SConscript +++ b/bsp/raspberry-pi/dm/SConscript @@ -1,4 +1,3 @@ -# for module compiling import os from building import * diff --git a/bsp/raspberry-pi/dm/adc/Kconfig b/bsp/raspberry-pi/dm/adc/Kconfig new file mode 100755 index 0000000000..69c057cf88 --- /dev/null +++ b/bsp/raspberry-pi/dm/adc/Kconfig @@ -0,0 +1,6 @@ +config RT_ADC_RP1 + bool "RP1 ADC and temperature sensor driver" + depends on RT_USING_DM + depends on RT_USING_ADC + depends on RT_USING_REGULATOR + default n diff --git a/bsp/raspberry-pi/dm/adc/SConscript b/bsp/raspberry-pi/dm/adc/SConscript new file mode 100755 index 0000000000..b8fe67491c --- /dev/null +++ b/bsp/raspberry-pi/dm/adc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_ADC_RP1']): + src += ['adc-rp1.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/adc/adc-rp1.c b/bsp/raspberry-pi/dm/adc/adc-rp1.c new file mode 100755 index 0000000000..d85d9a602c --- /dev/null +++ b/bsp/raspberry-pi/dm/adc/adc-rp1.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include +#include + +#define RP1_ADC_CS 0x00 +#define RP1_ADC_RESULT 0x04 +#define RP1_ADC_FCS 0x08 +#define RP1_ADC_FIFO 0x0c +#define RP1_ADC_DIV 0x10 + +#define RP1_ADC_INTR 0x14 +#define RP1_ADC_INTE 0x18 +#define RP1_ADC_INTF 0x1c +#define RP1_ADC_INTS 0x20 + +#define RP1_ADC_RWTYPE_SET 0x2000 +#define RP1_ADC_RWTYPE_CLR 0x3000 + +#define RP1_ADC_CS_RROBIN_MASK 0x1f +#define RP1_ADC_CS_RROBIN_SHIFT 16 +#define RP1_ADC_CS_AINSEL_MASK 0x7 +#define RP1_ADC_CS_AINSEL_SHIFT 12 +#define RP1_ADC_CS_ERR_STICKY 0x400 +#define RP1_ADC_CS_ERR 0x200 +#define RP1_ADC_CS_READY 0x100 +#define RP1_ADC_CS_START_MANY 0x8 +#define RP1_ADC_CS_START_ONCE 0x4 +#define RP1_ADC_CS_TS_EN 0x2 +#define RP1_ADC_CS_EN 0x1 + +#define RP1_ADC_FCS_THRESH_MASK 0xf +#define RP1_ADC_FCS_THRESH_SHIFT 24 +#define RP1_ADC_FCS_LEVEL_MASK 0xf +#define RP1_ADC_FCS_LEVEL_SHIFT 16 +#define RP1_ADC_FCS_OVER 0x800 +#define RP1_ADC_FCS_UNDER 0x400 +#define RP1_ADC_FCS_FULL 0x200 +#define RP1_ADC_FCS_EMPTY 0x100 +#define RP1_ADC_FCS_DREQ_EN 0x8 +#define RP1_ADC_FCS_ERR 0x4 +#define RP1_ADC_FCS_SHIFR 0x2 +#define RP1_ADC_FCS_EN 0x1 + +#define RP1_ADC_FIFO_ERR 0x8000 +#define RP1_ADC_FIFO_VAL_MASK 0xfff + +#define RP1_ADC_DIV_INT_MASK 0xffff +#define RP1_ADC_DIV_INT_SHIFT 8 +#define RP1_ADC_DIV_FRAC_MASK 0xff +#define RP1_ADC_DIV_FRAC_SHIFT 0 + +enum +{ + RP1_ADC_IN, + RP1_ADC_RAW, + RP1_ADC_TEMP, +}; + +struct rp1_adc_channel +{ + rt_uint32_t type; + + const char *name; +}; + +struct rp1_adc +{ + struct rt_adc_device parent; + + void *regs; + int vref_mv; + + struct rt_clk *clk; + struct rt_regulator *vref; + + rt_size_t channel_nr; + struct rp1_adc_channel *channel; + + struct rt_spinlock lock; +}; + +#define raw_to_rp1_adc(raw) rt_container_of(raw, struct rp1_adc, parent) + +static rt_err_t rp1_adc_ready_wait(struct rp1_adc *radc) +{ + int retries = 10; + + while (retries && !(HWREG32(radc->regs + RP1_ADC_CS) & RP1_ADC_CS_READY)) + { + --retries; + } + + return retries ? 0 : -RT_EIO; +} + +static rt_err_t rp1_adc_read(struct rp1_adc *radc, int channel, rt_uint32_t *val) +{ + rt_err_t err; + + rt_hw_spin_lock(&radc->lock.lock); + + HWREG32(radc->regs + RP1_ADC_RWTYPE_CLR + RP1_ADC_CS) = + RP1_ADC_CS_AINSEL_MASK << RP1_ADC_CS_AINSEL_SHIFT; + HWREG32(radc->regs + RP1_ADC_RWTYPE_SET + RP1_ADC_CS) = + channel << RP1_ADC_CS_AINSEL_SHIFT; + HWREG32(radc->regs + RP1_ADC_RWTYPE_SET + RP1_ADC_CS) = + RP1_ADC_CS_START_ONCE; + + if ((err = rp1_adc_ready_wait(radc))) + { + goto _out_lock; + } + + /* Asserted if the completed conversion had a convergence error */ + if (HWREG32(radc->regs + RP1_ADC_CS) & RP1_ADC_CS_ERR) + { + err = -RT_EIO; + goto _out_lock; + } + + *val = HWREG32(radc->regs + RP1_ADC_RESULT); + +_out_lock: + rt_hw_spin_unlock(&radc->lock.lock); + + return err; +} + +static int rp1_adc_to_mv(struct rp1_adc *radc, rt_uint32_t val) +{ + return ((rt_uint64_t)radc->vref_mv * val) / 0xfff; +} + +static struct rp1_adc_channel adc_channel[] = +{ + { .type = RP1_ADC_IN, .name = "in1-input" }, + { .type = RP1_ADC_IN, .name = "in2-input" }, + { .type = RP1_ADC_IN, .name = "in3-input" }, + { .type = RP1_ADC_IN, .name = "in4-input" }, + { .type = RP1_ADC_TEMP, .name = "temp1-input" }, + { .type = RP1_ADC_RAW, .name = "in1-raw" }, + { .type = RP1_ADC_RAW, .name = "in2-raw" }, + { .type = RP1_ADC_RAW, .name = "in3-raw" }, + { .type = RP1_ADC_RAW, .name = "in4-raw" }, + { .type = RP1_ADC_RAW, .name = "temp1-raw" }, +}; + +static rt_err_t rp1_adc_enabled(struct rt_adc_device *adc, rt_int8_t channel, rt_bool_t enabled) +{ + return RT_EOK; +} + +static rt_err_t rp1_adc_convert(struct rt_adc_device *adc, rt_int8_t channel, rt_uint32_t *value) +{ + rt_err_t err; + rt_uint32_t val; + struct rp1_adc_channel *chan; + struct rp1_adc *radc = raw_to_rp1_adc(adc); + + if (channel >= radc->channel_nr) + { + return -RT_EINVAL; + } + + chan = &radc->channel[channel]; + + if (chan->type == RP1_ADC_TEMP) + { + int mv; + + HWREG32(radc->regs + RP1_ADC_RWTYPE_SET + RP1_ADC_CS) = RP1_ADC_CS_TS_EN; + + if ((err = rp1_adc_read(radc, channel, &val))) + { + return err; + } + + mv = rp1_adc_to_mv(radc, val); + + /* T = 27 - (ADC_voltage - 0.706)/0.001721 */ + + *value = 27000 - RT_DIV_ROUND_CLOSEST((mv - 706) * (rt_int64_t)1000000, 1721); + } + else if (chan->type == RP1_ADC_IN || chan->type == RP1_ADC_RAW) + { + if ((err = rp1_adc_read(radc, channel, &val))) + { + return err; + } + + *value = val; + } + + return RT_EOK; +} + +static const struct rt_adc_ops rp1_adc_ops = +{ + .enabled = rp1_adc_enabled, + .convert = rp1_adc_convert, +}; + +static void rp1_adc_free(struct rp1_adc *radc) +{ + if (radc->regs) + { + rt_iounmap(radc->regs); + } + + if (!rt_is_err_or_null(radc->clk)) + { + rt_clk_disable_unprepare(radc->clk); + rt_clk_put(radc->clk); + } + + rt_free(radc); +} + +static rt_err_t rp1_adc_probe(struct rt_platform_device *pdev) +{ + int vref_uv; + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct rp1_adc *radc = rt_calloc(1, sizeof(*radc)); + + if (!radc) + { + return -RT_ENOMEM; + } + + radc->regs = rt_dm_dev_iomap(dev, 0); + + if (!radc->regs) + { + err = -RT_EIO; + goto _fail; + } + + radc->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(radc->clk)) + { + err = rt_ptr_err(radc->clk); + goto _fail; + } + + rt_clk_set_rate(radc->clk, 50000000); + rt_clk_prepare_enable(radc->clk); + + radc->vref = rt_regulator_get(dev, "vref"); + + if (rt_is_err(radc->vref)) + { + err = rt_ptr_err(radc->vref); + goto _fail; + } + + vref_uv = rt_regulator_get_voltage(radc->vref); + radc->vref_mv = RT_DIV_ROUND_CLOSEST(vref_uv, 1000); + + radc->channel_nr = RT_ARRAY_SIZE(adc_channel); + radc->channel = adc_channel; + + rt_spin_lock_init(&radc->lock); + + dev->user_data = radc; + + rt_dm_dev_set_name_auto(&radc->parent.parent, "adc"); + dev_name = rt_dm_dev_get_name(&radc->parent.parent); + + rt_hw_adc_register(&radc->parent, dev_name, &rp1_adc_ops, radc); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, radc); + + /* Disable interrupts */ + HWREG32(radc->regs + RP1_ADC_INTE) = 0; + + /* Enable the block, clearing any sticky error */ + HWREG32(radc->regs + RP1_ADC_CS) = RP1_ADC_CS_EN | RP1_ADC_CS_ERR_STICKY; + + return RT_EOK; + +_fail: + rp1_adc_free(radc); + + return err; +} + +static rt_err_t rp1_adc_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rp1_adc *radc = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + rt_device_unregister(&radc->parent.parent); + + rp1_adc_free(radc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rp1_adc_ofw_ids[] = +{ + { .compatible = "raspberrypi,rp1-adc" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rp1_adc_driver = +{ + .name = "rp1-adc", + .ids = rp1_adc_ofw_ids, + + .probe = rp1_adc_probe, + .remove = rp1_adc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rp1_adc_driver); diff --git a/bsp/raspberry-pi/dm/audio/Kconfig b/bsp/raspberry-pi/dm/audio/Kconfig new file mode 100755 index 0000000000..68ea51b350 --- /dev/null +++ b/bsp/raspberry-pi/dm/audio/Kconfig @@ -0,0 +1,4 @@ +config RT_AUDIO_BCM2835_I2S + bool "Broadcom BCM2835 I2S" + depends on RT_USING_DMA + default n diff --git a/bsp/raspberry-pi/dm/audio/SConscript b/bsp/raspberry-pi/dm/audio/SConscript new file mode 100755 index 0000000000..591d525124 --- /dev/null +++ b/bsp/raspberry-pi/dm/audio/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_AUDIO_BCM2835_I2S']): + src += ['bcm2835-i2s.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/audio/bcm2835-i2s.c b/bsp/raspberry-pi/dm/audio/bcm2835-i2s.c new file mode 100755 index 0000000000..7b9e948654 --- /dev/null +++ b/bsp/raspberry-pi/dm/audio/bcm2835-i2s.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "audio.bcm2835-i2s" +#define DBG_LVL DBG_INFO +#include + +/* I2S registers */ +#define BCM2835_I2S_CS_A_REG 0x00 +#define BCM2835_I2S_FIFO_A_REG 0x04 +#define BCM2835_I2S_MODE_A_REG 0x08 +#define BCM2835_I2S_RXC_A_REG 0x0c +#define BCM2835_I2S_TXC_A_REG 0x10 +#define BCM2835_I2S_DREQ_A_REG 0x14 +#define BCM2835_I2S_INTEN_A_REG 0x18 +#define BCM2835_I2S_INTSTC_A_REG 0x1c +#define BCM2835_I2S_GRAY_REG 0x20 + +/* I2S register settings */ +#define BCM2835_I2S_STBY RT_BIT(25) +#define BCM2835_I2S_SYNC RT_BIT(24) +#define BCM2835_I2S_RXSEX RT_BIT(23) +#define BCM2835_I2S_RXF RT_BIT(22) +#define BCM2835_I2S_TXE RT_BIT(21) +#define BCM2835_I2S_RXD RT_BIT(20) +#define BCM2835_I2S_TXD RT_BIT(19) +#define BCM2835_I2S_RXR RT_BIT(18) +#define BCM2835_I2S_TXW RT_BIT(17) +#define BCM2835_I2S_CS_RXERR RT_BIT(16) +#define BCM2835_I2S_CS_TXERR RT_BIT(15) +#define BCM2835_I2S_RXSYNC RT_BIT(14) +#define BCM2835_I2S_TXSYNC RT_BIT(13) +#define BCM2835_I2S_DMAEN RT_BIT(9) +#define BCM2835_I2S_RXTHR(v) ((v) << 7) +#define BCM2835_I2S_TXTHR(v) ((v) << 5) +#define BCM2835_I2S_RXCLR RT_BIT(4) +#define BCM2835_I2S_TXCLR RT_BIT(3) +#define BCM2835_I2S_TXON RT_BIT(2) +#define BCM2835_I2S_RXON RT_BIT(1) +#define BCM2835_I2S_EN (1) + +#define BCM2835_I2S_CLKDIS RT_BIT(28) +#define BCM2835_I2S_PDMN RT_BIT(27) +#define BCM2835_I2S_PDME RT_BIT(26) +#define BCM2835_I2S_FRXP RT_BIT(25) +#define BCM2835_I2S_FTXP RT_BIT(24) +#define BCM2835_I2S_CLKM RT_BIT(23) +#define BCM2835_I2S_CLKI RT_BIT(22) +#define BCM2835_I2S_FSM RT_BIT(21) +#define BCM2835_I2S_FSI RT_BIT(20) +#define BCM2835_I2S_FLEN(v) ((v) << 10) +#define BCM2835_I2S_FSLEN(v) (v) + +#define BCM2835_I2S_CHWEX RT_BIT(15) +#define BCM2835_I2S_CHEN RT_BIT(14) +#define BCM2835_I2S_CHPOS(v) ((v) << 4) +#define BCM2835_I2S_CHWID(v) (v) +#define BCM2835_I2S_CH1(v) ((v) << 16) +#define BCM2835_I2S_CH2(v) (v) +#define BCM2835_I2S_CH1_POS(v) BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(v)) +#define BCM2835_I2S_CH2_POS(v) BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(v)) + +#define BCM2835_I2S_TX_PANIC(v) ((v) << 24) +#define BCM2835_I2S_RX_PANIC(v) ((v) << 16) +#define BCM2835_I2S_TX(v) ((v) << 8) +#define BCM2835_I2S_RX(v) (v) + +#define BCM2835_I2S_INT_RXERR RT_BIT(3) +#define BCM2835_I2S_INT_TXERR RT_BIT(2) +#define BCM2835_I2S_INT_RXR RT_BIT(1) +#define BCM2835_I2S_INT_TXW RT_BIT(0) + +#define BCM2835_I2S_MAX_FRAME_LENGTH 1024 /* Frame length register is 10 bit, maximum length 1024 */ +#define BCM2835_I2S_MAX_FIFO_LENGTH (64 * 32) /* 64 * 32 bit TX/RX FIFO */ + +struct bcm2835_i2s +{ + struct rt_audio_device parent; + struct rt_audio_configure audio_config; + struct rt_device *dev; + + void *regs; + struct rt_clk *clk; + rt_bool_t clk_prepared; + rt_bool_t hifi_hat; + + void *playback_buf; + void *capture_buf; + rt_ubase_t playback_dma; + rt_ubase_t capture_dma; + + rt_ubase_t fifo_dma; + struct rt_dma_chan *dma_rx; + struct rt_dma_chan *dma_tx; +}; + +#define raw_to_bcm2835_i2s(raw) rt_container_of(raw, struct bcm2835_i2s, parent) + +static void bcm2835_i2s_start_clock(struct bcm2835_i2s *i2s) +{ + if (i2s->clk_prepared) + { + return; + } + + rt_clk_prepare_enable(i2s->clk); + i2s->clk_prepared = RT_TRUE; +} + +static void bcm2835_i2s_stop_clock(struct bcm2835_i2s *i2s) +{ + if (i2s->clk_prepared) + { + rt_clk_disable_unprepare(i2s->clk); + } + + i2s->clk_prepared = RT_FALSE; +} + +static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s *i2s, rt_bool_t tx, rt_bool_t rx) +{ + int timeout = 1000; + rt_bool_t clk_was_prepared; + rt_uint32_t syncval, csreg, i2s_active_state, off, clr; + + off = (tx ? BCM2835_I2S_TXON : 0) | (rx ? BCM2835_I2S_RXON : 0); + clr = (tx ? BCM2835_I2S_TXCLR : 0) | (rx ? BCM2835_I2S_RXCLR : 0); + + /* Backup the current state */ + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON); + + /* Start clock if not running */ + if (!(clk_was_prepared = i2s->clk_prepared)) + { + bcm2835_i2s_start_clock(i2s); + } + + /* Stop I2S module */ + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~off; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg; + + /* Clear the FIFOs, Requires at least 2 PCM clock cycles to take effect */ + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~clr; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | clr; + + /* Wait for 2 PCM clock cycles */ + + /* Toggle the SYNC flag. After 2 PCM clock cycles it can be read back */ + syncval = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) & BCM2835_I2S_SYNC; + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~BCM2835_I2S_SYNC; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | ~syncval; + + /* Wait for the SYNC flag changing it's state */ + while (--timeout) + { + if ((HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) & BCM2835_I2S_SYNC) != syncval) + { + break; + } + } + + if (!timeout) + { + LOG_E("%s: sync error", rt_dm_dev_get_name(&i2s->parent.parent)); + } + + /* Stop clock if it was not running before */ + if (!clk_was_prepared) + { + bcm2835_i2s_stop_clock(i2s); + } + + /* Restore I2S state */ + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~(BCM2835_I2S_RXON | BCM2835_I2S_TXON); + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | i2s_active_state; +} + +static rt_err_t bcm2835_i2s_audio_getcaps(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: + i2s->hifi_hat = caps->udata.value > 0; + + switch (caps->sub_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + break; + + default: + return -RT_ENOSYS; + } + break; + + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + switch(caps->sub_type) + { + case AUDIO_DSP_PARAM: + caps->udata.config.channels = i2s->audio_config.channels; + caps->udata.config.samplebits = i2s->audio_config.samplebits; + caps->udata.config.samplerate = i2s->audio_config.samplerate; + break; + + case AUDIO_DSP_SAMPLERATE: + caps->udata.config.samplerate = i2s->audio_config.samplerate; + break; + + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = i2s->audio_config.channels; + break; + + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = i2s->audio_config.samplebits; + break; + + default: + return -RT_ENOSYS; + } + break; + + default: + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t bcm2835_i2s_audio_configure(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + rt_uint32_t csreg, value, frame_length; + struct rt_audio_configure audio_config; + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + + if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON)) + { + return -RT_EBUSY; + } + + rt_memcpy(&audio_config, &i2s->audio_config, sizeof(audio_config)); + + switch (caps->main_type) + { + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + audio_config.channels = caps->udata.config.channels; + audio_config.samplebits = caps->udata.config.samplebits; + audio_config.samplerate = caps->udata.config.samplerate; + break; + + case AUDIO_DSP_SAMPLERATE: + audio_config.samplerate = caps->udata.config.samplerate; + break; + + case AUDIO_DSP_CHANNELS: + audio_config.channels = caps->udata.config.channels; + break; + + case AUDIO_DSP_SAMPLEBITS: + audio_config.samplebits = caps->udata.config.samplebits; + break; + + default: + return -RT_ENOSYS; + } + break; + + default: + return -RT_ENOSYS; + } + + if (audio_config.channels > 2) + { + return -RT_EINVAL; + } + + if (audio_config.samplerate < 8000 || audio_config.samplerate > 384000) + { + return -RT_EINVAL; + } + + if (audio_config.samplebits != 16 && + audio_config.samplebits != 24 && + audio_config.samplebits != 32) + { + return -RT_EINVAL; + } + + rt_memcpy(&i2s->audio_config, &audio_config, sizeof(audio_config)); + + if (i2s->hifi_hat) + { + /* Clock setting */ + bcm2835_i2s_stop_clock(i2s); + + rt_clk_set_rate(i2s->clk, audio_config.samplerate); + + bcm2835_i2s_start_clock(i2s); + } + + /* Setup the frame format */ + value = BCM2835_I2S_CHEN; + + if (audio_config.samplebits >= 24) + { + value |= BCM2835_I2S_CHWEX; + } + + value |= BCM2835_I2S_CHWID((audio_config.samplebits - 8) & 0xf); + /* CH2 format is the same as for CH1 */ + value = BCM2835_I2S_CH1(value) | BCM2835_I2S_CH2(value); + + HWREG32(i2s->regs + BCM2835_I2S_RXC_A_REG) = value | + BCM2835_I2S_CH1_POS(1) | BCM2835_I2S_CH2_POS(33); + HWREG32(i2s->regs + BCM2835_I2S_TXC_A_REG) = value | + BCM2835_I2S_CH1_POS(1) | BCM2835_I2S_CH2_POS(33); + + /* Setup the I2S mode */ + value = 0; + frame_length = audio_config.channels * audio_config.samplebits; + + if (audio_config.samplebits <= 16) + { + /* Use frame packed mode (2 channels per 32 bit word) */ + value |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; + } + + value |= BCM2835_I2S_FLEN(frame_length - 1); + value |= BCM2835_I2S_FSLEN(frame_length / 2); + + if (!i2s->hifi_hat) + { + value |= BCM2835_I2S_CLKM | BCM2835_I2S_CLKI | BCM2835_I2S_FSM; + } + + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = value; + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~(BCM2835_I2S_RXTHR(1) | BCM2835_I2S_TXTHR(1) | BCM2835_I2S_DMAEN); + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | 0xffffffff; + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~(BCM2835_I2S_TX_PANIC(0x10) | BCM2835_I2S_RX_PANIC(0x30) | + BCM2835_I2S_TX(0x30) | BCM2835_I2S_RX(0x20)); + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | 0xffffffff; + + bcm2835_i2s_clear_fifos(i2s, RT_TRUE, RT_TRUE); + + return RT_EOK; +} + +static rt_err_t bcm2835_i2s_audio_init(struct rt_audio_device *audio) +{ + rt_uint32_t csreg; + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + i2s->audio_config.samplerate = 8000; /* 8000 ~ 384000 */ + i2s->audio_config.samplebits = 16; /* 16/24/32 */ + i2s->audio_config.channels = 2; + + bcm2835_i2s_stop_clock(i2s); + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~BCM2835_I2S_EN; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | BCM2835_I2S_EN; + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~BCM2835_I2S_STBY; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | BCM2835_I2S_STBY; + + return RT_EOK; +} + +static rt_err_t bcm2835_i2s_audio_start(struct rt_audio_device *audio, int stream) +{ + rt_uint32_t csreg, mask; + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + bcm2835_i2s_start_clock(i2s); + + if (stream == AUDIO_STREAM_RECORD) + { + mask = BCM2835_I2S_RXON; + } + else if (stream == AUDIO_STREAM_REPLAY) + { + mask = BCM2835_I2S_TXON; + } + else + { + return -RT_EINVAL; + } + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~mask; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg | mask; + + return RT_EOK; +} + +static rt_err_t bcm2835_i2s_audio_stop(struct rt_audio_device *audio, int stream) +{ + rt_uint32_t csreg, mask; + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + if (stream == AUDIO_STREAM_RECORD) + { + mask = BCM2835_I2S_RXON; + } + else if (stream == AUDIO_STREAM_REPLAY) + { + mask = BCM2835_I2S_TXON; + } + else + { + return -RT_EINVAL; + } + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~mask; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg; + + bcm2835_i2s_stop_clock(i2s); + + return RT_EOK; +} + +static rt_ssize_t bcm2835_i2s_audio_transmit(struct rt_audio_device *audio, + const void *write_buf, void *read_buf, rt_size_t size) +{ + rt_err_t err; + struct rt_dma_chan *chan; + struct rt_dma_slave_config config; + struct rt_dma_slave_transfer transfer; + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + rt_memset(&config, 0, sizeof(config)); + + if (write_buf) + { + config.dst_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_maxburst = 2; + + config.direction = RT_DMA_MEM_TO_DEV; + config.src_addr = (write_buf - i2s->playback_buf) + i2s->playback_dma; + config.dst_addr = i2s->fifo_dma; + + chan = i2s->dma_tx; + } + else if (read_buf) + { + config.src_addr_width = RT_DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_maxburst = 2; + + config.direction = RT_DMA_DEV_TO_MEM; + config.src_addr = i2s->fifo_dma; + config.dst_addr = i2s->capture_dma; + + chan = i2s->dma_rx; + } + else + { + return -RT_EINVAL; + } + + if ((err = rt_dma_chan_config(chan, &config))) + { + LOG_E("Config DMA error = %s", rt_strerror(err)); + return err; + } + + rt_memset(&transfer, 0, sizeof(transfer)); + transfer.buffer_len = size; + transfer.src_addr = config.src_addr; + transfer.dst_addr = config.dst_addr; + transfer.period_len = BCM2835_I2S_MAX_FRAME_LENGTH; + + if (chan == i2s->dma_rx) + { + transfer.buffer = read_buf; + } + + if ((err = rt_dma_prep_cyclic(chan, &transfer))) + { + LOG_E("Prepare DMA error = %s", rt_strerror(err)); + return err; + } + + if ((err = rt_dma_chan_start(chan))) + { + LOG_E("Start DMA error = %s", rt_strerror(err)); + return err; + } + + return size; +} + +static void bcm2835_i2s_audio_buffer_info(struct rt_audio_device *audio, + struct rt_audio_buf_info *info) +{ + struct bcm2835_i2s *i2s = raw_to_bcm2835_i2s(audio); + + info->buffer = i2s->playback_buf; + info->total_size = BCM2835_I2S_MAX_FIFO_LENGTH; + info->block_size = BCM2835_I2S_MAX_FRAME_LENGTH; + info->block_count = BCM2835_I2S_MAX_FIFO_LENGTH / BCM2835_I2S_MAX_FRAME_LENGTH; +} + +const static struct rt_audio_ops bcm2835_i2s_audio_ops = +{ + .getcaps = bcm2835_i2s_audio_getcaps, + .configure = bcm2835_i2s_audio_configure, + .init = bcm2835_i2s_audio_init, + .start = bcm2835_i2s_audio_start, + .stop = bcm2835_i2s_audio_stop, + .transmit = bcm2835_i2s_audio_transmit, + .buffer_info = bcm2835_i2s_audio_buffer_info, +}; + +static void bcm2835_i2s_dma_rx_done(struct rt_dma_chan *chan, rt_size_t size) +{ + void *buffer; + struct bcm2835_i2s *i2s = chan->priv; + + buffer = chan->transfer.buffer; + chan->transfer.buffer += size; + + rt_memcpy(buffer, i2s->capture_buf, size); + rt_audio_rx_done(&i2s->parent, buffer, size); +} + +static void bcm2835_i2s_dma_tx_done(struct rt_dma_chan *chan, rt_size_t size) +{ + struct bcm2835_i2s *i2s = chan->priv; + + rt_audio_tx_complete(&i2s->parent); +} + +static void bcm2835_i2s_free(struct bcm2835_i2s *i2s) +{ + if (!rt_is_err_or_null(i2s->dma_rx)) + { + rt_dma_chan_release(i2s->dma_rx); + } + + if (!rt_is_err_or_null(i2s->dma_tx)) + { + rt_dma_chan_release(i2s->dma_tx); + } + + if (i2s->playback_buf) + { + rt_dma_free_coherent(i2s->dev, BCM2835_I2S_MAX_FIFO_LENGTH, + i2s->playback_buf, i2s->playback_dma); + } + + if (i2s->capture_buf) + { + rt_dma_free_coherent(i2s->dev, BCM2835_I2S_MAX_FIFO_LENGTH, + i2s->capture_buf, i2s->capture_dma); + } + + if (!rt_is_err_or_null(i2s->clk)) + { + rt_clk_put(i2s->clk); + } + + if (i2s->regs) + { + rt_iounmap(i2s->regs); + } + + rt_free(i2s); +} + +static rt_err_t bcm2835_i2s_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct bcm2835_i2s *i2s = rt_calloc(1, sizeof(*i2s)); + + if (!i2s) + { + return -RT_ENOMEM; + } + + i2s->dev = dev; + i2s->regs = rt_dm_dev_iomap(dev, 0); + + if (!i2s->regs) + { + err = -RT_EIO; + goto _fail; + } + + i2s->playback_buf = rt_dma_alloc_coherent(dev, + BCM2835_I2S_MAX_FIFO_LENGTH, &i2s->playback_dma); + + if (!i2s->playback_buf) + { + err = -RT_ENOMEM; + goto _fail; + } + + i2s->capture_buf = rt_dma_alloc_coherent(dev, + BCM2835_I2S_MAX_FIFO_LENGTH, &i2s->capture_dma); + + if (!i2s->capture_buf) + { + err = -RT_ENOMEM; + goto _fail; + } + + i2s->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(i2s->clk)) + { + err = rt_ptr_err(i2s->clk); + goto _fail; + } + + i2s->dma_rx = rt_dma_chan_request(dev, "rx"); + + if (rt_is_err(i2s->dma_rx)) + { + err = rt_ptr_err(i2s->clk); + goto _fail; + } + + i2s->dma_tx = rt_dma_chan_request(dev, "tx"); + + if (rt_is_err(i2s->dma_tx)) + { + err = rt_ptr_err(i2s->clk); + goto _fail; + } + + i2s->dma_rx->callback = bcm2835_i2s_dma_rx_done; + i2s->dma_tx->callback = bcm2835_i2s_dma_tx_done; + + i2s->dma_rx->priv = i2s; + i2s->dma_tx->priv = i2s; + + i2s->fifo_dma = (rt_ubase_t)rt_kmem_v2p(i2s->regs) + BCM2835_I2S_FIFO_A_REG; + + rt_dm_dev_set_name_auto(&i2s->parent.parent, "sound"); + dev_name = rt_dm_dev_get_name(&i2s->parent.parent); + + i2s->parent.ops = (struct rt_audio_ops *)&bcm2835_i2s_audio_ops; + if ((err = rt_audio_register(&i2s->parent, dev_name, RT_DEVICE_FLAG_RDWR, i2s))) + { + goto _fail; + } + + dev->user_data = i2s; + + return RT_EOK; + +_fail: + bcm2835_i2s_free(i2s); + + return err; +} + +static rt_err_t bcm2835_i2s_remove(struct rt_platform_device *pdev) +{ + rt_uint32_t csreg; + struct bcm2835_i2s *i2s = pdev->parent.user_data; + + csreg = HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG); + csreg &= ~BCM2835_I2S_EN; + HWREG32(i2s->regs + BCM2835_I2S_CS_A_REG) = csreg; + + bcm2835_i2s_stop_clock(i2s); + + rt_device_unregister(&i2s->parent.parent); + + bcm2835_i2s_free(i2s); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_i2s_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-i2s" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_i2s_driver = +{ + .name = "bcm2835-i2s", + .ids = bcm2835_i2s_ofw_ids, + + .probe = bcm2835_i2s_probe, + .remove = bcm2835_i2s_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_i2s_driver); diff --git a/bsp/raspberry-pi/dm/clk/Kconfig b/bsp/raspberry-pi/dm/clk/Kconfig new file mode 100755 index 0000000000..443774e188 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/Kconfig @@ -0,0 +1,19 @@ +config RT_CLK_BCM2711_DVP + bool "Broadcom BCM2711 DVP support" + depends on RT_USING_OFW + default n + +config RT_CLK_BCM2835 + bool "Broadcom BCM2835 clock support" + depends on RT_USING_OFW + default n + +config RT_CLK_RASPBERRYPI + bool "Raspberry Pi firmware based clock support" + depends on RT_USING_OFW + default n + +config RT_CLK_RP1 + bool "RP1 clock support" + depends on RT_USING_OFW + default n diff --git a/bsp/raspberry-pi/dm/clk/SConscript b/bsp/raspberry-pi/dm/clk/SConscript new file mode 100755 index 0000000000..630644edf3 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/SConscript @@ -0,0 +1,22 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLK_BCM2711_DVP']): + src += ['clk-bcm2711-dvp.c'] + +if GetDepend(['RT_CLK_BCM2835']): + src += ['clk-bcm2835-aux.c', 'clk-bcm2835.c', 'clk-dsi.c'] + +if GetDepend(['RT_CLK_RASPBERRYPI']): + src += ['clk-raspberrypi.c'] + +if GetDepend(['RT_CLK_RP1']): + src += ['clk-rp1.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/clk/clk-bcm2711-dvp.c b/bsp/raspberry-pi/dm/clk/clk-bcm2711-dvp.c new file mode 100755 index 0000000000..eb357d8b72 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-bcm2711-dvp.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.bcm2711.dvp" +#define DBG_LVL DBG_INFO +#include + +#include "../../reset/reset-simple.h" + +#define DVP_HT_RPI_SW_INIT 0x04 +#define DVP_HT_RPI_MISC_CONFIG 0x08 + +struct bcm2711_dvp_clk +{ + struct rt_clk_node clk_parent; + struct reset_simple reset_parent; + + void *regs; + struct rt_clk *clk; +}; + +#define raw_to_bcm2711_dvp_clk(raw) rt_container_of(raw, struct bcm2711_dvp_clk, clk_parent) + +struct dvp_clk_gate +{ + struct rt_clk_cell cell; + + rt_uint8_t bit_idx; +}; + +#define raw_to_dvp_clk_gate(raw) rt_container_of(raw, struct dvp_clk_gate, cell) + +static void bcm2711_dvp_clk_endisable(struct rt_clk_cell *cell, int enable) +{ + rt_ubase_t level; + rt_uint32_t value; + int set = 1 ^ enable; + struct dvp_clk_gate *gate = raw_to_dvp_clk_gate(cell); + struct bcm2711_dvp_clk *dvp_clk = raw_to_bcm2711_dvp_clk(cell->clk_np); + + level = rt_spin_lock_irqsave(&dvp_clk->reset_parent.lock); + + value = HWREG32(dvp_clk->regs + DVP_HT_RPI_MISC_CONFIG); + if (set) + { + value |= RT_BIT(gate->bit_idx); + } + else + { + value &= ~RT_BIT(gate->bit_idx); + } + HWREG32(dvp_clk->regs + DVP_HT_RPI_MISC_CONFIG) = value; + + rt_spin_unlock_irqrestore(&dvp_clk->reset_parent.lock, level); +} + +static rt_err_t bcm2711_dvp_clk_enable(struct rt_clk_cell *cell) +{ + bcm2711_dvp_clk_endisable(cell, 1); + + return RT_EOK; +} + +static void bcm2711_dvp_clk_disable(struct rt_clk_cell *cell) +{ + bcm2711_dvp_clk_endisable(cell, 0); +} + +static rt_bool_t bcm2711_dvp_clk_is_enabled(struct rt_clk_cell *cell) +{ + rt_uint32_t value; + struct dvp_clk_gate *gate = raw_to_dvp_clk_gate(cell); + struct bcm2711_dvp_clk *dvp_clk = raw_to_bcm2711_dvp_clk(cell->clk_np); + + value = HWREG32(dvp_clk->regs + DVP_HT_RPI_MISC_CONFIG); + value ^= RT_BIT(gate->bit_idx); + value &= RT_BIT(gate->bit_idx); + + return !!value; +} + +static rt_ubase_t bcm2711_dvp_clk_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct bcm2711_dvp_clk *dvp_clk = raw_to_bcm2711_dvp_clk(cell->clk_np); + + return rt_clk_cell_get_rate(dvp_clk->clk->cell); +} + +const struct rt_clk_ops bcm2711_dvp_clk_ops = +{ + .enable = bcm2711_dvp_clk_enable, + .disable = bcm2711_dvp_clk_disable, + .is_enabled = bcm2711_dvp_clk_is_enabled, + .recalc_rate = bcm2711_dvp_clk_recalc_rate, +}; + +static struct dvp_clk_gate hdmi0_108mhz = +{ + .cell.name = "hdmi0-108MHz", + .cell.ops = &bcm2711_dvp_clk_ops, + .bit_idx = 3, +}; + +static struct dvp_clk_gate hdmi1_108mhz = +{ + .cell.name = "hdmi1-108MHz", + .cell.ops = &bcm2711_dvp_clk_ops, + .bit_idx = 4, +}; + +static struct rt_clk_cell *dvp_clk_cell[] = +{ + &hdmi0_108mhz.cell, + &hdmi1_108mhz.cell, +}; + +static rt_err_t bcm2711_dvp_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct reset_simple *rsts; + struct rt_reset_controller *rstcer; + struct rt_device *dev = &pdev->parent; + struct bcm2711_dvp_clk *dvp_clk = rt_calloc(1, sizeof(*dvp_clk)); + + if (!dvp_clk) + { + return -RT_ENOMEM; + } + + dvp_clk->regs = rt_dm_dev_iomap(dev, 0); + + if (!dvp_clk->regs) + { + err = -RT_EIO; + goto _fail; + } + + dvp_clk->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(dvp_clk->clk)) + { + err = rt_ptr_err(dvp_clk->clk); + goto _fail; + } + + for (int i = 0; i < RT_ARRAY_SIZE(dvp_clk_cell); ++i) + { + struct rt_clk_cell *cell = dvp_clk_cell[i]; + + cell->parents_nr = 1; + cell->parent_name = dvp_clk->clk->cell->name; + } + + dvp_clk->clk_parent.dev = dev; + dvp_clk->clk_parent.cells = dvp_clk_cell; + dvp_clk->clk_parent.cells_nr = RT_ARRAY_SIZE(dvp_clk_cell); + + if ((err = rt_clk_register(&dvp_clk->clk_parent))) + { + goto _fail; + } + + /* Reset */ + rsts = &dvp_clk->reset_parent; + + rt_spin_lock_init(&rsts->lock); + rsts->mmio_base = dvp_clk->regs + DVP_HT_RPI_SW_INIT; + + rstcer = &rsts->parent; + rstcer->priv = rsts; + rstcer->ofw_node = dev->ofw_node; + rstcer->ops = &reset_simple_ops; + + if ((err = rt_reset_controller_register(rstcer))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (dvp_clk->regs) + { + rt_iounmap(dvp_clk->regs); + } + + if (dvp_clk->clk_parent.dev) + { + rt_clk_unregister(&dvp_clk->clk_parent); + } + + if (dvp_clk->reset_parent.parent.ops) + { + rt_reset_controller_unregister(&dvp_clk->reset_parent.parent); + } + + if (rt_is_err_or_null(dvp_clk->clk)) + { + rt_clk_put(dvp_clk->clk); + } + + rt_free(dvp_clk); + + return err; +} + +static const struct rt_ofw_node_id bcm2711_dvp_clk_ofw_ids[] = +{ + { .compatible = "brcm,brcm2711-dvp", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2711_dvp_clk_driver = +{ + .name = "clk-brcm2711-dvp", + .ids = bcm2711_dvp_clk_ofw_ids, + + .probe = bcm2711_dvp_clk_probe, +}; + +static int bcm2711_dvp_clk_register(void) +{ + rt_platform_driver_register(&bcm2711_dvp_clk_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2711_dvp_clk_register); diff --git a/bsp/raspberry-pi/dm/clk/clk-bcm2835-aux.c b/bsp/raspberry-pi/dm/clk/clk-bcm2835-aux.c new file mode 100755 index 0000000000..7bf9e08cbf --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-bcm2835-aux.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.bcm2835.aux" +#define DBG_LVL DBG_INFO +#include + +#include + +#define BCM2835_AUXIRQ 0x00 +#define BCM2835_AUXENB 0x04 + +struct bcm2835_aux_clk +{ + struct rt_clk_node parent; + + void *regs; + struct rt_clk *clk; +}; + +#define raw_to_bcm2835_aux_clk(raw) rt_container_of(raw, struct bcm2835_aux_clk, parent) + +struct aux_clk_gate +{ + struct rt_clk_cell cell; + + rt_uint8_t bit_idx; +}; + +#define raw_to_aux_clk_gate(raw) rt_container_of(raw, struct aux_clk_gate, cell) + +static void bcm2835_aux_clk_endisable(struct rt_clk_cell *cell, int enable) +{ + int set = 0 ^ enable; + rt_uint32_t value, bit_idx; + struct aux_clk_gate *gate = raw_to_aux_clk_gate(cell); + struct bcm2835_aux_clk *aux_clk = raw_to_bcm2835_aux_clk(cell->clk_np); + + bit_idx = gate->bit_idx; + + value = HWREG32(aux_clk->regs); + if (set) + { + value |= RT_BIT(bit_idx); + } + else + { + value &= ~RT_BIT(bit_idx); + } + HWREG32(aux_clk->regs) = value; +} + +static rt_err_t bcm2835_aux_clk_enable(struct rt_clk_cell *cell) +{ + bcm2835_aux_clk_endisable(cell, 1); + + return RT_EOK; +} + +static void bcm2835_aux_clk_disable(struct rt_clk_cell *cell) +{ + bcm2835_aux_clk_endisable(cell, 0); +} + +static rt_bool_t bcm2835_aux_clk_is_enabled(struct rt_clk_cell *cell) +{ + rt_uint32_t value, bit_idx; + struct aux_clk_gate *gate = raw_to_aux_clk_gate(cell); + struct bcm2835_aux_clk *aux_clk = raw_to_bcm2835_aux_clk(cell->clk_np); + + bit_idx = gate->bit_idx; + + value = HWREG32(aux_clk->regs + BCM2835_AUXENB); + value &= RT_BIT(bit_idx); + + return !!value; +} + +static rt_ubase_t bcm2835_aux_clk_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct bcm2835_aux_clk *aux_clk = raw_to_bcm2835_aux_clk(cell->clk_np); + + return rt_clk_cell_get_rate(aux_clk->clk->cell); +} + +const struct rt_clk_ops bcm2835_aux_clk_ops = +{ + .enable = bcm2835_aux_clk_enable, + .disable = bcm2835_aux_clk_disable, + .is_enabled = bcm2835_aux_clk_is_enabled, + .recalc_rate = bcm2835_aux_clk_recalc_rate, +}; + +static struct aux_clk_gate aux_uart = +{ + .cell.name = "aux_uart", + .cell.ops = &bcm2835_aux_clk_ops, + .bit_idx = 0, +}; + +static struct aux_clk_gate aux_spi1 = +{ + .cell.name = "aux_spi1", + .cell.ops = &bcm2835_aux_clk_ops, + .bit_idx = 1, +}; + +static struct aux_clk_gate aux_spi2 = +{ + .cell.name = "aux_spi2", + .cell.ops = &bcm2835_aux_clk_ops, + .bit_idx = 2, +}; + +static struct rt_clk_cell *bcm2835_aux_clk_cell[] = +{ + [BCM2835_AUX_CLOCK_UART] = &aux_uart.cell, + [BCM2835_AUX_CLOCK_SPI1] = &aux_spi1.cell, + [BCM2835_AUX_CLOCK_SPI2] = &aux_spi2.cell, +}; + +static rt_err_t bcm2835_aux_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct bcm2835_aux_clk *aux_clk = rt_calloc(1, sizeof(*aux_clk)); + + if (!aux_clk) + { + return -RT_ENOMEM; + } + + aux_clk->regs = rt_dm_dev_iomap(dev, 0); + + if (!aux_clk->regs) + { + err = -RT_EIO; + goto _fail; + } + + aux_clk->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(aux_clk->clk)) + { + err = rt_ptr_err(aux_clk->clk); + goto _fail; + } + + if (aux_clk->clk) + { + for (int i = 0; i < RT_ARRAY_SIZE(bcm2835_aux_clk_cell); ++i) + { + struct rt_clk_cell *cell = bcm2835_aux_clk_cell[i]; + + if (cell) + { + cell->parents_nr = 1; + cell->parent_name = aux_clk->clk->cell->name; + } + } + } + + aux_clk->parent.dev = dev; + aux_clk->parent.cells = bcm2835_aux_clk_cell; + aux_clk->parent.cells_nr = RT_ARRAY_SIZE(bcm2835_aux_clk_cell); + + if ((err = rt_clk_register(&aux_clk->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (aux_clk->regs) + { + rt_iounmap(aux_clk->regs); + } + + if (!rt_is_err_or_null(aux_clk->clk)) + { + rt_clk_put(aux_clk->clk); + } + + rt_free(aux_clk); + + return err; +} + +static const struct rt_ofw_node_id bcm2835_aux_clk_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-aux", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_aux_clk_driver = +{ + .name = "clk-bcm2835-aux", + .ids = bcm2835_aux_clk_ofw_ids, + + .probe = bcm2835_aux_clk_probe, +}; + +static int bcm2835_aux_clk_register(void) +{ + rt_platform_driver_register(&bcm2835_aux_clk_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_aux_clk_register); diff --git a/bsp/raspberry-pi/dm/clk/clk-bcm2835.c b/bsp/raspberry-pi/dm/clk/clk-bcm2835.c new file mode 100755 index 0000000000..c1c80de444 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-bcm2835.c @@ -0,0 +1,1976 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define CM_PASSWORD 0x5a000000 + +#define CM_GNRICCTL 0x000 +#define CM_GNRICDIV 0x004 +#define CM_DIV_FRAC_BITS 12 +#define CM_DIV_FRAC_MASK RT_GENMASK(CM_DIV_FRAC_BITS - 1, 0) + +#define CM_VPUCTL 0x008 +#define CM_VPUDIV 0x00c +#define CM_SYSCTL 0x010 +#define CM_SYSDIV 0x014 +#define CM_PERIACTL 0x018 +#define CM_PERIADIV 0x01c +#define CM_PERIICTL 0x020 +#define CM_PERIIDIV 0x024 +#define CM_H264CTL 0x028 +#define CM_H264DIV 0x02c +#define CM_ISPCTL 0x030 +#define CM_ISPDIV 0x034 +#define CM_V3DCTL 0x038 +#define CM_V3DDIV 0x03c +#define CM_CAM0CTL 0x040 +#define CM_CAM0DIV 0x044 +#define CM_CAM1CTL 0x048 +#define CM_CAM1DIV 0x04c +#define CM_CCP2CTL 0x050 +#define CM_CCP2DIV 0x054 +#define CM_DSI0ECTL 0x058 +#define CM_DSI0EDIV 0x05c +#define CM_DSI0PCTL 0x060 +#define CM_DSI0PDIV 0x064 +#define CM_DPICTL 0x068 +#define CM_DPIDIV 0x06c +#define CM_GP0CTL 0x070 +#define CM_GP0DIV 0x074 +#define CM_GP1CTL 0x078 +#define CM_GP1DIV 0x07c +#define CM_GP2CTL 0x080 +#define CM_GP2DIV 0x084 +#define CM_HSMCTL 0x088 +#define CM_HSMDIV 0x08c +#define CM_OTPCTL 0x090 +#define CM_OTPDIV 0x094 +#define CM_PCMCTL 0x098 +#define CM_PCMDIV 0x09c +#define CM_PWMCTL 0x0a0 +#define CM_PWMDIV 0x0a4 +#define CM_SLIMCTL 0x0a8 +#define CM_SLIMDIV 0x0ac +#define CM_SMICTL 0x0b0 +#define CM_SMIDIV 0x0b4 +/* No definition for 0x0b8 and 0x0bc */ +#define CM_TCNTCTL 0x0c0 +#define CM_TCNT_SRC1_SHIFT 12 +#define CM_TCNTCNT 0x0c4 +#define CM_TECCTL 0x0c8 +#define CM_TECDIV 0x0cc +#define CM_TD0CTL 0x0d0 +#define CM_TD0DIV 0x0d4 +#define CM_TD1CTL 0x0d8 +#define CM_TD1DIV 0x0dc +#define CM_TSENSCTL 0x0e0 +#define CM_TSENSDIV 0x0e4 +#define CM_TIMERCTL 0x0e8 +#define CM_TIMERDIV 0x0ec +#define CM_UARTCTL 0x0f0 +#define CM_UARTDIV 0x0f4 +#define CM_VECCTL 0x0f8 +#define CM_VECDIV 0x0fc +#define CM_DSI0HSCK 0x120 +#define CM_PULSECTL 0x190 +#define CM_PULSEDIV 0x194 +#define CM_SDCCTL 0x1a8 +#define CM_SDCDIV 0x1ac +#define CM_ARMCTL 0x1b0 +#define CM_AVEOCTL 0x1b8 +#define CM_AVEODIV 0x1bc +#define CM_EMMCCTL 0x1c0 +#define CM_EMMCDIV 0x1c4 +#define CM_EMMC2CTL 0x1d0 +#define CM_EMMC2DIV 0x1d4 + +/* General bits for the CM_*CTL regs */ +#define CM_ENABLE RT_BIT(4) +#define CM_KILL RT_BIT(5) +#define CM_GATE_BIT 6 +#define CM_GATE RT_BIT(CM_GATE_BIT) +#define CM_BUSY RT_BIT(7) +#define CM_BUSYD RT_BIT(8) +#define CM_FRAC RT_BIT(9) +#define CM_SRC_SHIFT 0 +#define CM_SRC_BITS 4 +#define CM_SRC_MASK 0xf +#define CM_SRC_GND 0 +#define CM_SRC_OSC 1 +#define CM_SRC_TESTDEBUG0 2 +#define CM_SRC_TESTDEBUG1 3 +#define CM_SRC_PLLA_CORE 4 +#define CM_SRC_PLLA_PER 4 +#define CM_SRC_PLLC_CORE0 5 +#define CM_SRC_PLLC_PER 5 +#define CM_SRC_PLLC_CORE1 8 +#define CM_SRC_PLLD_CORE 6 +#define CM_SRC_PLLD_PER 6 +#define CM_SRC_PLLH_AUX 7 +#define CM_SRC_PLLC_CORE1 8 +#define CM_SRC_PLLC_CORE2 9 + +#define CM_OSCCOUNT 0x100 + +#define CM_PLLA 0x104 +#define CM_PLL_ANARST RT_BIT(8) +#define CM_PLLA_HOLDPER RT_BIT(7) +#define CM_PLLA_LOADPER RT_BIT(6) +#define CM_PLLA_HOLDCORE RT_BIT(5) +#define CM_PLLA_LOADCORE RT_BIT(4) +#define CM_PLLA_HOLDCCP2 RT_BIT(3) +#define CM_PLLA_LOADCCP2 RT_BIT(2) +#define CM_PLLA_HOLDDSI0 RT_BIT(1) +#define CM_PLLA_LOADDSI0 RT_BIT(0) + +#define CM_PLLC 0x108 +#define CM_PLLC_HOLDPER RT_BIT(7) +#define CM_PLLC_LOADPER RT_BIT(6) +#define CM_PLLC_HOLDCORE2 RT_BIT(5) +#define CM_PLLC_LOADCORE2 RT_BIT(4) +#define CM_PLLC_HOLDCORE1 RT_BIT(3) +#define CM_PLLC_LOADCORE1 RT_BIT(2) +#define CM_PLLC_HOLDCORE0 RT_BIT(1) +#define CM_PLLC_LOADCORE0 RT_BIT(0) + +#define CM_PLLD 0x10c +#define CM_PLLD_HOLDPER RT_BIT(7) +#define CM_PLLD_LOADPER RT_BIT(6) +#define CM_PLLD_HOLDCORE RT_BIT(5) +#define CM_PLLD_LOADCORE RT_BIT(4) +#define CM_PLLD_HOLDDSI1 RT_BIT(3) +#define CM_PLLD_LOADDSI1 RT_BIT(2) +#define CM_PLLD_HOLDDSI0 RT_BIT(1) +#define CM_PLLD_LOADDSI0 RT_BIT(0) + +#define CM_PLLH 0x110 +#define CM_PLLH_LOADRCAL RT_BIT(2) +#define CM_PLLH_LOADAUX RT_BIT(1) +#define CM_PLLH_LOADPIX RT_BIT(0) + +#define CM_LOCK 0x114 +#define CM_LOCK_FLOCKH RT_BIT(12) +#define CM_LOCK_FLOCKD RT_BIT(11) +#define CM_LOCK_FLOCKC RT_BIT(10) +#define CM_LOCK_FLOCKB RT_BIT(9) +#define CM_LOCK_FLOCKA RT_BIT(8) + +#define CM_EVENT 0x118 +#define CM_DSI1ECTL 0x158 +#define CM_DSI1EDIV 0x15c +#define CM_DSI1PCTL 0x160 +#define CM_DSI1PDIV 0x164 +#define CM_DFTCTL 0x168 +#define CM_DFTDIV 0x16c + +#define CM_PLLB 0x170 +#define CM_PLLB_HOLDARM RT_BIT(1) +#define CM_PLLB_LOADARM RT_BIT(0) + +#define A2W_PLLA_CTRL 0x1100 +#define A2W_PLLC_CTRL 0x1120 +#define A2W_PLLD_CTRL 0x1140 +#define A2W_PLLH_CTRL 0x1160 +#define A2W_PLLB_CTRL 0x11e0 +#define A2W_PLL_CTRL_PRST_DISABLE RT_BIT(17) +#define A2W_PLL_CTRL_PWRDN RT_BIT(16) +#define A2W_PLL_CTRL_PDIV_MASK 0x000007000 +#define A2W_PLL_CTRL_PDIV_SHIFT 12 +#define A2W_PLL_CTRL_NDIV_MASK 0x0000003ff +#define A2W_PLL_CTRL_NDIV_SHIFT 0 + +#define A2W_PLLA_ANA0 0x1010 +#define A2W_PLLC_ANA0 0x1030 +#define A2W_PLLD_ANA0 0x1050 +#define A2W_PLLH_ANA0 0x1070 +#define A2W_PLLB_ANA0 0x10f0 + +#define A2W_PLL_KA_SHIFT 7 +#define A2W_PLL_KA_MASK RT_GENMASK(9, 7) +#define A2W_PLL_KI_SHIFT 19 +#define A2W_PLL_KI_MASK RT_GENMASK(21, 19) +#define A2W_PLL_KP_SHIFT 15 +#define A2W_PLL_KP_MASK RT_GENMASK(18, 15) + +#define A2W_PLLH_KA_SHIFT 19 +#define A2W_PLLH_KA_MASK RT_GENMASK(21, 19) +#define A2W_PLLH_KI_LOW_SHIFT 22 +#define A2W_PLLH_KI_LOW_MASK RT_GENMASK(23, 22) +#define A2W_PLLH_KI_HIGH_SHIFT 0 +#define A2W_PLLH_KI_HIGH_MASK RT_GENMASK(0, 0) +#define A2W_PLLH_KP_SHIFT 1 +#define A2W_PLLH_KP_MASK RT_GENMASK(4, 1) + +#define A2W_XOSC_CTRL 0x1190 +#define A2W_XOSC_CTRL_PLLB_ENABLE RT_BIT(7) +#define A2W_XOSC_CTRL_PLLA_ENABLE RT_BIT(6) +#define A2W_XOSC_CTRL_PLLD_ENABLE RT_BIT(5) +#define A2W_XOSC_CTRL_DDR_ENABLE RT_BIT(4) +#define A2W_XOSC_CTRL_CPR1_ENABLE RT_BIT(3) +#define A2W_XOSC_CTRL_USB_ENABLE RT_BIT(2) +#define A2W_XOSC_CTRL_HDMI_ENABLE RT_BIT(1) +#define A2W_XOSC_CTRL_PLLC_ENABLE RT_BIT(0) + +#define A2W_PLLA_FRAC 0x1200 +#define A2W_PLLC_FRAC 0x1220 +#define A2W_PLLD_FRAC 0x1240 +#define A2W_PLLH_FRAC 0x1260 +#define A2W_PLLB_FRAC 0x12e0 +#define A2W_PLL_FRAC_MASK ((1 << A2W_PLL_FRAC_BITS) - 1) +#define A2W_PLL_FRAC_BITS 20 + +#define A2W_PLL_CHANNEL_DISABLE RT_BIT(8) +#define A2W_PLL_DIV_BITS 8 +#define A2W_PLL_DIV_SHIFT 0 + +#define A2W_PLLA_DSI0 0x1300 +#define A2W_PLLA_CORE 0x1400 +#define A2W_PLLA_PER 0x1500 +#define A2W_PLLA_CCP2 0x1600 + +#define A2W_PLLC_CORE2 0x1320 +#define A2W_PLLC_CORE1 0x1420 +#define A2W_PLLC_PER 0x1520 +#define A2W_PLLC_CORE0 0x1620 + +#define A2W_PLLD_DSI0 0x1340 +#define A2W_PLLD_CORE 0x1440 +#define A2W_PLLD_PER 0x1540 +#define A2W_PLLD_DSI1 0x1640 + +#define A2W_PLLH_AUX 0x1360 +#define A2W_PLLH_RCAL 0x1460 +#define A2W_PLLH_PIX 0x1560 +#define A2W_PLLH_STS 0x1660 + +#define A2W_PLLH_CTRLR 0x1960 +#define A2W_PLLH_FRACR 0x1a60 +#define A2W_PLLH_AUXR 0x1b60 +#define A2W_PLLH_RCALR 0x1c60 +#define A2W_PLLH_PIXR 0x1d60 +#define A2W_PLLH_STSR 0x1e60 + +#define A2W_PLLB_ARM 0x13e0 +#define A2W_PLLB_SP0 0x14e0 +#define A2W_PLLB_SP1 0x15e0 +#define A2W_PLLB_SP2 0x16e0 + +#define LOCK_TIMEOUT_NS 100000000 +#define LOCK_TIMEOUT_US (LOCK_TIMEOUT_NS / 1000) +#define BCM2835_MAX_FB_RATE 1750000000U + +#define CLK_TYPE_PLL 0 +#define CLK_TYPE_DIV 1 +#define CLK_TYPE_CLK 2 +#define CLK_TYPE_VPU 3 + +#define SOC_TYPE_BCM2835 RT_BIT(0) +#define SOC_TYPE_BCM2711 RT_BIT(1) +#define SOC_ALL (SOC_TYPE_BCM2835 | SOC_TYPE_BCM2711) + +#define VCMSG_ID_CORE_CLOCK 4 + +struct bcm2835_cprman; + +struct cprman_soc_data +{ + rt_uint32_t soc; +}; + +struct bcm2835_clock_data +{ + struct rt_clk_cell cell; + + struct bcm2835_cprman *cprman; + void (*init)(struct bcm2835_cprman *cprman, struct bcm2835_clock_data *cdata); + + rt_uint32_t supported; + + /* Bitmap encoding which parents accept rate change propagation. */ + rt_uint32_t set_rate_parent; + + rt_uint32_t ctl_reg; + rt_uint32_t div_reg; + + /* Number of integer bits in the divider */ + rt_uint32_t int_bits; + /* Number of fractional bits in the divider */ + rt_uint32_t frac_bits; + + rt_uint32_t flags; + + rt_bool_t is_vpu_clock; + rt_bool_t is_mash_clock; + rt_bool_t low_jitter; + + rt_uint32_t tcnt_mux; + + rt_bool_t round_up; +}; + +#define cell_to_bcm2835_clock_data(cell) rt_container_of(cell, struct bcm2835_clock_data, cell); + +static const char *const cprman_parent_names[] = +{ + "osc", "dsi0_byte", "dsi0_ddr2", "dsi0_ddr", "dsi1_byte", "dsi1_ddr2", "dsi1_ddr", +}; + +struct bcm2835_cprman +{ + struct rt_clk_node parent; + + void *regs; + struct rt_clk *osc_clk; + struct rpi_firmware *fw; + + rt_uint32_t soc; + const char *real_parent_names[RT_ARRAY_SIZE(cprman_parent_names)]; +}; + +#define raw_to_bcm2835_cprman(raw) rt_container_of(raw, struct bcm2835_cprman, parent) + +rt_inline void cprman_write(struct bcm2835_cprman *cprman, + rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32(cprman->regs + reg) = CM_PASSWORD | val; +} + +rt_inline rt_uint32_t cprman_read(struct bcm2835_cprman *cprman, rt_uint32_t reg) +{ + return HWREG32(cprman->regs + reg); +} + +static rt_bool_t bcm2835_clk_is_claimed(const char *name); + +/* ---------------------------------- PLL ----------------------------------- */ +struct bcm2835_pll_ana_bits +{ + rt_uint32_t mask0; + rt_uint32_t set0; + rt_uint32_t mask1; + rt_uint32_t set1; + rt_uint32_t mask3; + rt_uint32_t set3; + rt_uint32_t fb_prediv_mask; +}; + +struct bcm2835_pll_data +{ + struct bcm2835_clock_data cdata; + + rt_uint32_t cm_ctrl_reg; + rt_uint32_t a2w_ctrl_reg; + rt_uint32_t frac_reg; + rt_uint32_t ana_reg_base; + rt_uint32_t reference_enable_mask; + /* Bit in CM_LOCK to indicate when the PLL has locked. */ + rt_uint32_t lock_mask; + + const struct bcm2835_pll_ana_bits *ana; + + rt_ubase_t min_rate; + rt_ubase_t max_rate; + /* + * Highest rate for the VCO before we have to use the + * pre-divide-by-2. + */ + rt_ubase_t max_fb_rate; +}; + +rt_inline struct bcm2835_pll_data *cell_to_bcm2835_pll_data(struct rt_clk_cell *cell) +{ + struct bcm2835_clock_data *cdata = cell_to_bcm2835_clock_data(cell); + + return rt_container_of(cdata, struct bcm2835_pll_data, cdata); +} + +static const struct bcm2835_pll_ana_bits bcm2835_ana_default = +{ + .mask0 = 0, + .set0 = 0, + .mask1 = A2W_PLL_KI_MASK | A2W_PLL_KP_MASK, + .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), + .mask3 = A2W_PLL_KA_MASK, + .set3 = (2 << A2W_PLL_KA_SHIFT), + .fb_prediv_mask = RT_BIT(14), +}; + +static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = +{ + .mask0 = A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK, + .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), + .mask1 = A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK, + .set1 = (6 << A2W_PLLH_KP_SHIFT), + .mask3 = 0, + .set3 = 0, + .fb_prediv_mask = RT_BIT(11), +}; + +static void bcm2835_pll_choose_ndiv_and_fdiv(rt_base_t rate, + rt_base_t parent_rate, rt_uint32_t *ndiv, rt_uint32_t *fdiv) +{ + rt_uint64_t div; + + div = (rt_uint64_t)rate << A2W_PLL_FRAC_BITS; + rt_do_div(div, parent_rate); + + *ndiv = div >> A2W_PLL_FRAC_BITS; + *fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1); +} + +static rt_uint32_t bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman, + struct bcm2835_pll_data *data) +{ + /* + * On BCM2711 there isn't a pre-divisor available in the PLL feedback + * loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed + * for to for VCO RANGE bits. + */ + if (cprman->soc & SOC_TYPE_BCM2711) + { + return 0; + } + + return data->ana->fb_prediv_mask; +} + +static rt_ubase_t bcm2835_pll_rate_from_divisors(rt_base_t parent_rate, + rt_uint32_t ndiv, rt_uint32_t fdiv, rt_uint32_t pdiv) +{ + rt_uint64_t rate; + + if (pdiv == 0) + { + return 0; + } + + rate = (rt_uint64_t)parent_rate * ((ndiv << A2W_PLL_FRAC_BITS) + fdiv); + rt_do_div(rate, pdiv); + + return rate >> A2W_PLL_FRAC_BITS; +} + +static void bcm2835_pll_write_ana(struct bcm2835_cprman *cprman, + rt_uint32_t ana_reg_base, rt_uint32_t *ana) +{ + /* + * ANA register setup is done as a series of writes to ANA3-ANA0, + * in that order. This lets us write all 4 registers as a single cycle of + * the serdes interface (taking 100 xosc clocks), + * whereas if we were to update ana0, 1, and 3 individually through + * their partial-write registers, each would be their own serdes cycle. + */ + for (int i = 3; i >= 0; --i) + { + cprman_write(cprman, ana_reg_base + i * 4, ana[i]); + } +} + +static rt_err_t bcm2835_pll_on(struct rt_clk_cell *cell) +{ + rt_tick_t timeout; + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) & ~A2W_PLL_CTRL_PWRDN); + + /* Take the PLL out of reset. */ + cprman_write(cprman, data->cm_ctrl_reg, + cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); + + /* Wait for the PLL to lock. */ + if (rt_strcmp(cell->name, "pllh")) + { + timeout = rt_tick_from_millisecond(LOCK_TIMEOUT_US / 1000); + timeout += rt_tick_get(); + + while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) + { + if (rt_tick_get() > timeout) + { + return -RT_ETIMEOUT; + } + + rt_hw_cpu_relax(); + } + } + + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | A2W_PLL_CTRL_PRST_DISABLE); + + return RT_EOK; +} + +static void bcm2835_pll_off(struct rt_clk_cell *cell) +{ + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | A2W_PLL_CTRL_PWRDN); +} + +static rt_bool_t bcm2835_pll_is_on(struct rt_clk_cell *cell) +{ + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + return !!(cprman_read(cprman, data->a2w_ctrl_reg) & A2W_PLL_CTRL_PRST_DISABLE); +} + +static rt_ubase_t bcm2835_pll_get_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_bool_t using_prediv; + rt_uint32_t ndiv, pdiv, fdiv, a2wctrl; + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + if (parent_rate == 0) + { + return 0; + } + + a2wctrl = cprman_read(cprman, data->a2w_ctrl_reg); + + fdiv = cprman_read(cprman, data->frac_reg) & A2W_PLL_FRAC_MASK; + ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; + pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; + using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & + bcm2835_pll_get_prediv_mask(cprman, data); + + if (using_prediv) + { + ndiv *= 2; + fdiv *= 2; + } + + return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); +} + +static rt_base_t bcm2835_pll_round_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + rt_uint32_t ndiv, fdiv; + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + + rate = rt_clamp(rate, data->min_rate, data->max_rate); + + bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); + + return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); +} + +static rt_err_t bcm2835_pll_set_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t prediv_mask, ndiv, fdiv, a2w_ctl, ana[4]; + rt_bool_t was_using_prediv, use_fb_prediv, do_ana_setup_first; + struct bcm2835_pll_data *data = cell_to_bcm2835_pll_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data); + + if (rate > data->max_fb_rate) + { + use_fb_prediv = RT_TRUE; + rate /= 2; + } + else + { + use_fb_prediv = RT_FALSE; + } + + bcm2835_pll_choose_ndiv_and_fdiv(rate, parent_rate, &ndiv, &fdiv); + + for (int i = 3; i >= 0; --i) + { + ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); + } + + was_using_prediv = ana[1] & prediv_mask; + + ana[0] &= ~data->ana->mask0; + ana[0] |= data->ana->set0; + ana[1] &= ~data->ana->mask1; + ana[1] |= data->ana->set1; + ana[3] &= ~data->ana->mask3; + ana[3] |= data->ana->set3; + + if (was_using_prediv && !use_fb_prediv) + { + ana[1] &= ~prediv_mask; + do_ana_setup_first = RT_TRUE; + } + else if (!was_using_prediv && use_fb_prediv) + { + ana[1] |= prediv_mask; + do_ana_setup_first = RT_FALSE; + } + else + { + do_ana_setup_first = RT_TRUE; + } + + /* Unmask the reference clock from the oscillator. */ + cprman_write(cprman, A2W_XOSC_CTRL, + cprman_read(cprman, A2W_XOSC_CTRL) | data->reference_enable_mask); + + if (do_ana_setup_first) + { + bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); + } + + /* Set the PLL multiplier from the oscillator. */ + cprman_write(cprman, data->frac_reg, fdiv); + + a2w_ctl = cprman_read(cprman, data->a2w_ctrl_reg); + a2w_ctl &= ~A2W_PLL_CTRL_NDIV_MASK; + a2w_ctl |= ndiv << A2W_PLL_CTRL_NDIV_SHIFT; + a2w_ctl &= ~A2W_PLL_CTRL_PDIV_MASK; + a2w_ctl |= 1 << A2W_PLL_CTRL_PDIV_SHIFT; + cprman_write(cprman, data->a2w_ctrl_reg, a2w_ctl); + + if (!do_ana_setup_first) + { + bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); + } + + return RT_EOK; +} + +static const struct rt_clk_ops bcm2835_pll_clk_ops = +{ + .prepare = bcm2835_pll_on, + .unprepare = bcm2835_pll_off, + .is_prepared = bcm2835_pll_is_on, + .recalc_rate = bcm2835_pll_get_rate, + .round_rate = bcm2835_pll_round_rate, + .set_rate = bcm2835_pll_set_rate, +}; + +static void bcm2835_pll_init(struct bcm2835_cprman *cprman, struct bcm2835_clock_data *cdata) +{ + struct rt_clk_cell *cell = &cdata->cell; + + /* All of the PLLs derive from the external oscillator. */ + cell->parents_nr = 1; + cell->parent_name = cprman->real_parent_names[0]; + + if (!bcm2835_clk_is_claimed(cell->name)) + { + cell->flags |= RT_CLK_F_IS_CRITICAL; + } +} + +#define REGISTER_PLL(_struct, _name, _supported, _flags, ...) \ +static struct bcm2835_pll_data _struct = \ +{ \ + .cdata = \ + { \ + .cell.name = _name, \ + .cell.ops = &bcm2835_pll_clk_ops, \ + .cell.flags = RT_CLK_F_IGNORE_UNUSED | _flags, \ + .init = bcm2835_pll_init, \ + .supported = _supported, \ + }, \ + __VA_ARGS__ \ +}; +/* ---------------------------------- PLL ----------------------------------- */ + +/* ------------------------------ PLL Divider ------------------------------- */ +struct bcm2835_pll_divider_data +{ + struct bcm2835_clock_data cdata; + + rt_uint32_t cm_reg; + rt_uint32_t a2w_reg; + + rt_uint32_t load_mask; + rt_uint32_t hold_mask; + rt_uint32_t fixed_divider; +}; + +rt_inline struct bcm2835_pll_divider_data *cell_to_bcm2835_divider_data(struct rt_clk_cell *cell) +{ + struct bcm2835_clock_data *cdata = cell_to_bcm2835_clock_data(cell); + + return rt_container_of(cdata, struct bcm2835_pll_divider_data, cdata); +} + +static rt_err_t bcm2835_pll_divider_on(struct rt_clk_cell *cell) +{ + struct bcm2835_pll_divider_data *data = cell_to_bcm2835_divider_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + cprman_write(cprman, data->a2w_reg, + cprman_read(cprman, data->a2w_reg) & ~A2W_PLL_CHANNEL_DISABLE); + + cprman_write(cprman, data->cm_reg, + cprman_read(cprman, data->cm_reg) & ~data->hold_mask); + + return RT_EOK; +} + +static void bcm2835_pll_divider_off(struct rt_clk_cell *cell) +{ + struct bcm2835_pll_divider_data *data = cell_to_bcm2835_divider_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + cprman_write(cprman, data->cm_reg, + (cprman_read(cprman, data->cm_reg) & ~data->load_mask) | data->hold_mask); + cprman_write(cprman, data->a2w_reg, + cprman_read(cprman, data->a2w_reg) | A2W_PLL_CHANNEL_DISABLE); +} + +static rt_bool_t bcm2835_pll_divider_is_on(struct rt_clk_cell *cell) +{ + struct bcm2835_pll_divider_data *data = cell_to_bcm2835_divider_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + return !(cprman_read(cprman, data->a2w_reg) & A2W_PLL_CHANNEL_DISABLE); +} + +static rt_ubase_t bcm2835_pll_divider_get_rate(struct rt_clk_cell *cell, + rt_ubase_t parent_rate) +{ + rt_uint32_t val, div; + struct bcm2835_pll_divider_data *data = cell_to_bcm2835_divider_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + val = cprman_read(cprman, data->a2w_reg) >> A2W_PLL_DIV_SHIFT; + val &= (1 << A2W_PLL_DIV_BITS) - 1; + + div = val ? val : (1 << A2W_PLL_DIV_BITS); + + return div ? RT_DIV_ROUND_UP_ULL((rt_uint64_t)parent_rate, div) : parent_rate; +} + +static rt_err_t bcm2835_pll_divider_set_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t cm, div, max_div = 1 << A2W_PLL_DIV_BITS; + struct bcm2835_pll_divider_data *data = cell_to_bcm2835_divider_data(cell); + struct bcm2835_cprman *cprman = data->cdata.cprman; + + div = RT_DIV_ROUND_UP_ULL(parent_rate, rate); + + div = rt_min(div, max_div); + if (div == max_div) + { + div = 0; + } + + cprman_write(cprman, data->a2w_reg, div); + cm = cprman_read(cprman, data->cm_reg); + cprman_write(cprman, data->cm_reg, cm | data->load_mask); + cprman_write(cprman, data->cm_reg, cm & ~data->load_mask); + + return RT_EOK; +} + +static const struct rt_clk_ops bcm2835_pll_divider_clk_ops = +{ + .prepare = bcm2835_pll_divider_on, + .unprepare = bcm2835_pll_divider_off, + .is_prepared = bcm2835_pll_divider_is_on, + .recalc_rate = bcm2835_pll_divider_get_rate, + .set_rate = bcm2835_pll_divider_set_rate, +}; + +static void bcm2835_pll_divider_init(struct bcm2835_cprman *cprman, struct bcm2835_clock_data *cdata) +{ + struct rt_clk_cell *cell = &cdata->cell; + struct bcm2835_pll_divider_data *divider_data = cell_to_bcm2835_divider_data(cell);; + + if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) + { + if (!bcm2835_clk_is_claimed(cell->parent_name) || + !bcm2835_clk_is_claimed(cell->name)) + { + cell->flags |= RT_CLK_F_IS_CRITICAL; + } + } +} + +#define REGISTER_PLL_DIV(_struct, _name, _parent, _supported, _flags, ...) \ +static struct bcm2835_pll_divider_data _struct = \ +{ \ + .cdata = \ + { \ + .cell.name = _name, \ + .cell.ops = &bcm2835_pll_divider_clk_ops, \ + .cell.parents_nr = 1, \ + .cell.parent_name = _parent, \ + .cell.flags = RT_CLK_F_IGNORE_UNUSED | _flags, \ + .init = bcm2835_pll_divider_init, \ + .supported = _supported, \ + }, \ + __VA_ARGS__ \ +}; +/* ------------------------------ PLL Divider ------------------------------- */ + +/* ---------------------------------- CLK ----------------------------------- */ +/* + * The CM dividers do fixed-point division, so we can't use the + * generic integer divider code like the PLL dividers do (and we can't + * fake it by having some fixed shifts preceding it in the clock tree, + * because we'd run out of bits in a 32-bit rt_ubase_t). + */ +struct bcm2835_clock +{ + struct bcm2835_clock_data cdata; +}; + +rt_inline struct bcm2835_clock *cell_to_bcm2835_clock(struct rt_clk_cell *cell) +{ + struct bcm2835_clock_data *cdata = cell_to_bcm2835_clock_data(cell); + + return rt_container_of(cdata, struct bcm2835_clock, cdata); +} + +static rt_uint32_t bcm2835_clock_choose_div(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint64_t temp; + rt_uint32_t unused_frac_mask, div, mindiv, maxdiv; + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + + unused_frac_mask = RT_GENMASK(CM_DIV_FRAC_BITS - cdata->frac_bits, 0) >> 1; + temp = (rt_uint64_t)parent_rate << CM_DIV_FRAC_BITS; + + rt_do_div(temp, rate); + div = temp; + div &= ~unused_frac_mask; + + /* Different clamping limits apply for a mash clock */ + if (cdata->is_mash_clock) + { + /* Clamp to min divider of 2 */ + mindiv = 2 << CM_DIV_FRAC_BITS; + /* Clamp to the highest possible integer divider */ + maxdiv = (RT_BIT(cdata->int_bits) - 1) << CM_DIV_FRAC_BITS; + } + else + { + /* Clamp to min divider of 1 */ + mindiv = 1 << CM_DIV_FRAC_BITS; + /* Clamp to the highest possible fractional divider */ + maxdiv = RT_GENMASK(cdata->int_bits + CM_DIV_FRAC_BITS - 1, + CM_DIV_FRAC_BITS - cdata->frac_bits); + } + + /* Apply the clamping limits */ + div = rt_max_t(rt_uint32_t, div, mindiv); + div = rt_min_t(rt_uint32_t, div, maxdiv); + + return div; +} + +static rt_ubase_t bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, + rt_ubase_t parent_rate, rt_uint32_t div) +{ + rt_uint64_t temp; + struct bcm2835_clock_data *data = &clock->cdata; + + if (data->int_bits == 0 && data->frac_bits == 0) + { + return parent_rate; + } + + /* + * The divisor is a 12.12 fixed point field, but only some of + * the bits are populated in any given clock. + */ + div >>= CM_DIV_FRAC_BITS - data->frac_bits; + div &= (1 << (data->int_bits + data->frac_bits)) - 1; + + if (div == 0) + { + return 0; + } + + temp = (rt_uint64_t)parent_rate << data->frac_bits; + + rt_do_div(temp, div); + + return temp; +} + +static rt_ubase_t bcm2835_round_rate(rt_ubase_t rate) +{ + rt_ubase_t scaler = 1, limit; + + limit = rate / 100000; + + while (scaler < limit) + { + scaler *= 10; + } + + /* + * If increasing a clock by less than 0.1% changes it + * from ..999.. to ..000.., round up. + */ + if ((rate + scaler - 1) / scaler % 1000 == 0) + { + rate = rt_roundup(rate, scaler); + } + + return rate; +} + +static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) +{ + rt_tick_t timeout; + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + timeout = rt_tick_from_millisecond(LOCK_TIMEOUT_US / 1000); + timeout += rt_tick_get(); + + while (cprman_read(cprman, cdata->ctl_reg) & CM_BUSY) + { + if (rt_tick_get() > timeout) + { + LOG_E("%s: couldn't lock PLL", cdata->cell.name); + return; + } + + rt_hw_cpu_relax(); + } +} + +static void bcm2835_clock_off(struct rt_clk_cell *cell) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + cprman_write(cprman, cdata->ctl_reg, + cprman_read(cprman, cdata->ctl_reg) & ~CM_ENABLE); + + /* BUSY will remain high until the divider completes its cycle. */ + bcm2835_clock_wait_busy(clock); +} + +static rt_err_t bcm2835_clock_on(struct rt_clk_cell *cell) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + cprman_write(cprman, cdata->ctl_reg, + cprman_read(cprman, cdata->ctl_reg) | CM_ENABLE | CM_GATE); + + return RT_EOK; +} + +static rt_bool_t bcm2835_clock_is_on(struct rt_clk_cell *cell) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + return (cprman_read(cprman, cdata->ctl_reg) & CM_ENABLE) != 0; +} + +static rt_ubase_t bcm2835_clock_get_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_uint32_t div; + rt_ubase_t rate; + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + if (cdata->int_bits == 0 && cdata->frac_bits == 0) + { + return parent_rate; + } + + div = cprman_read(cprman, cdata->div_reg); + + rate = bcm2835_clock_rate_from_divisor(clock, parent_rate, div); + + if (cdata->round_up) + { + rate = bcm2835_round_rate(rate); + } + + return rate; +} + +static rt_ubase_t bcm2835_clock_get_rate_vpu(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + if (cprman->fw) + { + struct + { + rt_uint32_t id; + rt_uint32_t val; + } packet; + + packet.id = VCMSG_ID_CORE_CLOCK; + packet.val = 0; + + if (!rpi_firmware_property(cprman->fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + &packet, sizeof(packet))) + { + return packet.val; + } + } + + return bcm2835_clock_get_rate(cell, parent_rate); +} + +static rt_err_t bcm2835_clock_set_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t div, ctl; + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + div = bcm2835_clock_choose_div(cell, rate, parent_rate); + ctl = cprman_read(cprman, cdata->ctl_reg); + + /* + * If the clock is running, we have to pause clock generation while + * updating the control and div regs. This is glitchless (no clock + * signals generated faster than the rate) but each reg access is two + * OSC cycles so the clock will slow down for a moment. + */ + if (ctl & CM_ENABLE) + { + cprman_write(cprman, cdata->ctl_reg, ctl & ~CM_ENABLE); + bcm2835_clock_wait_busy(clock); + } + + ctl &= ~CM_FRAC; + ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; + cprman_write(cprman, cdata->ctl_reg, ctl); + + cprman_write(cprman, cdata->div_reg, div); + + return RT_EOK; +} + +static rt_err_t bcm2835_clock_set_parent(struct rt_clk_cell *cell, rt_uint8_t idx) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + cprman_write(cprman, cdata->ctl_reg, (idx << CM_SRC_SHIFT) & CM_SRC_MASK); + + return RT_EOK; +} + +static rt_uint8_t bcm2835_clock_get_parent(struct rt_clk_cell *cell) +{ + struct bcm2835_clock *clock = cell_to_bcm2835_clock(cell); + struct bcm2835_clock_data *cdata = &clock->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + return (cprman_read(cprman, cdata->ctl_reg) & CM_SRC_MASK) >> CM_SRC_SHIFT; +} + +static const struct rt_clk_ops bcm2835_clock_clk_ops = +{ + .prepare = bcm2835_clock_on, + .unprepare = bcm2835_clock_off, + .is_prepared = bcm2835_clock_is_on, + .recalc_rate = bcm2835_clock_get_rate, + .set_rate = bcm2835_clock_set_rate, + .set_parent = bcm2835_clock_set_parent, + .get_parent = bcm2835_clock_get_parent, +}; + +static rt_bool_t bcm2835_vpu_clock_is_on(struct rt_clk_cell *cell) +{ + return RT_TRUE; +} + +/* + * The VPU clock can never be disabled (it doesn't have an ENABLE bit), + * so it gets its own set of clock ops. + */ +static const struct rt_clk_ops bcm2835_vpu_clock_clk_ops = +{ + .is_prepared = bcm2835_vpu_clock_is_on, + .recalc_rate = bcm2835_clock_get_rate_vpu, + .set_rate = bcm2835_clock_set_rate, + .set_parent = bcm2835_clock_set_parent, + .get_parent = bcm2835_clock_get_parent, +}; + +static void bcm2835_clock_init(struct bcm2835_cprman *cprman, struct bcm2835_clock_data *cdata) +{ + struct rt_clk_cell *cell = &cdata->cell; + + /* + * Some GPIO clocks for ethernet/wifi PLLs are marked as + * critical (since some platforms use them), but if the + * firmware didn't have them turned on then they clearly + * aren't actually critical. + */ + if ((cprman_read(cprman, cdata->ctl_reg) & CM_ENABLE) == 0) + { + cell->flags &= ~RT_CLK_F_IS_CRITICAL; + } + + /* + * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate + * rate changes on at least of the parents. + */ + if (cdata->set_rate_parent) + { + cell->flags |= RT_CLK_F_SET_RATE_PARENT; + } + + if (cdata->is_vpu_clock) + { + cell->ops = &bcm2835_vpu_clock_clk_ops; + } + else + { + /* If the clock wasn't actually enabled at boot, it's not critical. */ + if (!(cprman_read(cprman, cdata->ctl_reg) & CM_ENABLE)) + { + cell->flags &= ~RT_CLK_F_IS_CRITICAL; + } + } +} + +#define REGISTER_CLK(_struct, _name, _parents, _supported, _flags, ...) \ +static struct bcm2835_clock _struct = \ +{ \ + .cdata = \ + { \ + .cell.name = _name, \ + .cell.parents_nr = RT_ARRAY_SIZE(_parents), \ + .cell.parent_names = _parents, \ + .cell.ops = &bcm2835_clock_clk_ops, \ + .cell.flags = RT_CLK_F_IGNORE_UNUSED | _flags, \ + .init = bcm2835_clock_init, \ + .supported = _supported, \ + }, \ + __VA_ARGS__ \ +}; +/* ---------------------------------- CLK ----------------------------------- */ + +/* -------------------------------- PLL Gate -------------------------------- */ +struct bcm2835_gate_data +{ + struct bcm2835_clock_data cdata; +}; + +rt_inline struct bcm2835_gate_data *cell_to_bcm2835_gate_data(struct rt_clk_cell *cell) +{ + struct bcm2835_clock_data *cdata = cell_to_bcm2835_clock_data(cell); + + return rt_container_of(cdata, struct bcm2835_gate_data, cdata); +} + +static void bcm2835_clock_gate_endisable(struct rt_clk_cell *cell, int enable) +{ + rt_uint32_t value; + int set = 0 ^ enable; + struct bcm2835_gate_data *gate = cell_to_bcm2835_gate_data(cell); + struct bcm2835_clock_data *cdata = &gate->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + value = cprman_read(cprman, cdata->ctl_reg); + if (set) + { + value |= RT_BIT(CM_GATE_BIT); + } + else + { + value &= ~RT_BIT(CM_GATE_BIT); + } + cprman_write(cprman, cdata->ctl_reg, value); +} + +static rt_err_t bcm2835_clock_gate_enable(struct rt_clk_cell *cell) +{ + bcm2835_clock_gate_endisable(cell, 1); + + return RT_EOK; +} + +static void bcm2835_clock_gate_disable(struct rt_clk_cell *cell) +{ + bcm2835_clock_gate_endisable(cell, 0); +} + +static rt_bool_t bcm2835_clock_gate_is_enabled(struct rt_clk_cell *cell) +{ + rt_uint32_t value; + struct bcm2835_gate_data *gate = cell_to_bcm2835_gate_data(cell); + struct bcm2835_clock_data *cdata = &gate->cdata; + struct bcm2835_cprman *cprman = cdata->cprman; + + value = cprman_read(cprman, cdata->ctl_reg); + value &= RT_BIT(CM_GATE_BIT); + + return !!value; +} + +const struct rt_clk_ops bcm2835_clock_gate_ops = +{ + .enable = bcm2835_clock_gate_enable, + .disable = bcm2835_clock_gate_disable, + .is_enabled = bcm2835_clock_gate_is_enabled, +}; + +#define REGISTER_GATE(_struct, _name, _parent, _supported, _flags, ...) \ +static struct bcm2835_gate_data _struct = \ +{ \ + .cdata = \ + { \ + .cell.name = _name, \ + .cell.ops = &bcm2835_clock_gate_ops, \ + .cell.parents_nr = 1, \ + .cell.parent_name = _parent, \ + .cell.flags = RT_CLK_F_SET_RATE_GATE | \ + RT_CLK_F_IGNORE_UNUSED | _flags, \ + .supported = _supported, \ + }, \ + __VA_ARGS__ \ +}; +/* -------------------------------- PLL Gate -------------------------------- */ + +/* + * PLLA is the auxiliary PLL, used to drive the CCP2 + * (Compact Camera Port 2) transmitter clock. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ +REGISTER_PLL(plla, "plla", SOC_ALL, 0, + .cm_ctrl_reg = CM_PLLA, + .a2w_ctrl_reg = A2W_PLLA_CTRL, + .frac_reg = A2W_PLLA_FRAC, + .ana_reg_base = A2W_PLLA_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, + .lock_mask = CM_LOCK_FLOCKA, + .ana = &bcm2835_ana_default, + .min_rate = 600000000U, + .max_rate = 2400000000U, + .max_fb_rate = BCM2835_MAX_FB_RATE); +/* PLLB is used for the ARM's clock. */ +REGISTER_PLL(pllb, "pllb", SOC_ALL, RT_CLK_F_GET_RATE_NOCACHE, + .cm_ctrl_reg = CM_PLLB, + .a2w_ctrl_reg = A2W_PLLB_CTRL, + .frac_reg = A2W_PLLB_FRAC, + .ana_reg_base = A2W_PLLB_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, + .lock_mask = CM_LOCK_FLOCKB, + .ana = &bcm2835_ana_default, + .min_rate = 600000000U, + .max_rate = 3000000000U, + .max_fb_rate = BCM2835_MAX_FB_RATE); +/* + * PLLC is the core PLL, used to drive the core VPU clock. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ +REGISTER_PLL(pllc, "pllc", SOC_ALL, 0, + .cm_ctrl_reg = CM_PLLC, + .a2w_ctrl_reg = A2W_PLLC_CTRL, + .frac_reg = A2W_PLLC_FRAC, + .ana_reg_base = A2W_PLLC_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, + .lock_mask = CM_LOCK_FLOCKC, + .ana = &bcm2835_ana_default, + .min_rate = 600000000U, + .max_rate = 3000000000U, + .max_fb_rate = BCM2835_MAX_FB_RATE); +/* + * PLLD is the display PLL, used to drive DSI display panels. + * + * It is in the PX LDO power domain, which is on when the + * AUDIO domain is on. + */ +REGISTER_PLL(plld, "plld", SOC_ALL, 0, + .cm_ctrl_reg = CM_PLLD, + .a2w_ctrl_reg = A2W_PLLD_CTRL, + .frac_reg = A2W_PLLD_FRAC, + .ana_reg_base = A2W_PLLD_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, + .lock_mask = CM_LOCK_FLOCKD, + .ana = &bcm2835_ana_default, + .min_rate = 600000000U, + .max_rate = 2400000000U, + .max_fb_rate = BCM2835_MAX_FB_RATE); + +/* + * PLLH is used to supply the pixel clock or the AUX clock for the + * TV encoder. + * + * It is in the HDMI power domain. + */ +REGISTER_PLL(pllh, "pllh", SOC_TYPE_BCM2835, 0, + .cm_ctrl_reg = CM_PLLH, + .a2w_ctrl_reg = A2W_PLLH_CTRL, + .frac_reg = A2W_PLLH_FRAC, + .ana_reg_base = A2W_PLLH_ANA0, + .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, + .lock_mask = CM_LOCK_FLOCKH, + .ana = &bcm2835_ana_pllh, + .min_rate = 600000000U, + .max_rate = 3000000000U, + .max_fb_rate = BCM2835_MAX_FB_RATE); + +REGISTER_PLL_DIV(plla_core, "plla_core", "plla", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_CORE, + .load_mask = CM_PLLA_LOADCORE, + .hold_mask = CM_PLLA_HOLDCORE, + .fixed_divider = 1); + +/* + * PLLA_PER is used for gpu clocks. Controlled by firmware, see + * clk-raspberrypi.c. + */ +REGISTER_PLL_DIV(plla_dsi0, "plla_dsi0", "plla", SOC_ALL, 0, + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_DSI0, + .load_mask = CM_PLLA_LOADDSI0, + .hold_mask = CM_PLLA_HOLDDSI0, + .fixed_divider = 1); + +REGISTER_PLL_DIV(plla_ccp2, "plla_ccp2", "plla", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLA, + .a2w_reg = A2W_PLLA_CCP2, + .load_mask = CM_PLLA_LOADCCP2, + .hold_mask = CM_PLLA_HOLDCCP2, + .fixed_divider = 1); + +REGISTER_PLL_DIV(pllb_arm, "pllb_arm", "pllb", SOC_ALL, RT_CLK_F_SET_RATE_PARENT | RT_CLK_F_GET_RATE_NOCACHE, + .cm_reg = CM_PLLB, + .a2w_reg = A2W_PLLB_ARM, + .load_mask = CM_PLLB_LOADARM, + .hold_mask = CM_PLLB_HOLDARM, + .fixed_divider = 1); + +REGISTER_PLL_DIV(pllc_core0, "pllc_core0", "pllc", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE0, + .load_mask = CM_PLLC_LOADCORE0, + .hold_mask = CM_PLLC_HOLDCORE0, + .fixed_divider = 1); +REGISTER_PLL_DIV(pllc_core1, "pllc_core1", "pllc", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE1, + .load_mask = CM_PLLC_LOADCORE1, + .hold_mask = CM_PLLC_HOLDCORE1, + .fixed_divider = 1); +REGISTER_PLL_DIV(pllc_core2, "pllc_core2", "pllc", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_CORE2, + .load_mask = CM_PLLC_LOADCORE2, + .hold_mask = CM_PLLC_HOLDCORE2, + .fixed_divider = 1); +REGISTER_PLL_DIV(pllc_per, "pllc_per", "pllc", SOC_ALL, RT_CLK_F_IS_CRITICAL | RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLC, + .a2w_reg = A2W_PLLC_PER, + .load_mask = CM_PLLC_LOADPER, + .hold_mask = CM_PLLC_HOLDPER, + .fixed_divider = 1); + +REGISTER_PLL_DIV(plld_core, "plld_core", "plld", SOC_ALL, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_CORE, + .load_mask = CM_PLLD_LOADCORE, + .hold_mask = CM_PLLD_HOLDCORE, + .fixed_divider = 1); +/* + * VPU firmware assumes that PLLD_PER isn't disabled by the ARM core. + * Otherwise this could cause firmware lookups. That's why we mark + * it as critical. + */ +REGISTER_PLL_DIV(plld_per, "plld_per", "plld", SOC_ALL, RT_CLK_F_IS_CRITICAL | RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_PER, + .load_mask = CM_PLLD_LOADPER, + .hold_mask = CM_PLLD_HOLDPER, + .fixed_divider = 1); +REGISTER_PLL_DIV(plld_dsi0, "plld_dsi0", "plld", SOC_ALL, 0, + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_DSI0, + .load_mask = CM_PLLD_LOADDSI0, + .hold_mask = CM_PLLD_HOLDDSI0, + .fixed_divider = 1); +REGISTER_PLL_DIV(plld_dsi1, "plld_dsi1", "plld", SOC_ALL, 0, + .cm_reg = CM_PLLD, + .a2w_reg = A2W_PLLD_DSI1, + .load_mask = CM_PLLD_LOADDSI1, + .hold_mask = CM_PLLD_HOLDDSI1, + .fixed_divider = 1); +REGISTER_PLL_DIV(pllh_rcal, "pllh_rcal", "pllh", SOC_TYPE_BCM2835, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_RCAL, + .load_mask = CM_PLLH_LOADRCAL, + .hold_mask = 0, + .fixed_divider = 10); +REGISTER_PLL_DIV(pllh_aux, "pllh_aux", "pllh", SOC_TYPE_BCM2835, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_AUX, + .load_mask = CM_PLLH_LOADAUX, + .hold_mask = 0, + .fixed_divider = 1); +REGISTER_PLL_DIV(pllh_pix, "pllh_pix", "pllh", SOC_TYPE_BCM2835, RT_CLK_F_SET_RATE_PARENT, + .cm_reg = CM_PLLH, + .a2w_reg = A2W_PLLH_PIX, + .load_mask = CM_PLLH_LOADPIX, + .hold_mask = 0, + .fixed_divider = 10); + +/* Main oscillator parent mux */ +static const char *const bcm2835_clock_osc_parents[] = +{ + "gnd", "osc", "testdebug0", "testdebug1" +}; + +/* One Time Programmable Memory clock. Maximum 10Mhz. */ +REGISTER_CLK(clock_otp, "otp", bcm2835_clock_osc_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_OTPCTL, + .cdata.div_reg = CM_OTPDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 0, + .cdata.tcnt_mux = 6); +/* + * Used for a 1Mhz clock for the system clocksource, and also used + * bythe watchdog timer and the camera pulse generator. + */ +REGISTER_CLK(clock_timer, "timer", bcm2835_clock_osc_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_TIMERCTL, + .cdata.div_reg = CM_TIMERDIV, + .cdata.int_bits = 6, + .cdata.frac_bits = 12); +/* + * Clock for the temperature sensor. + * Generally run at 2Mhz, max 5Mhz. + */ +REGISTER_CLK(clock_tsens, "tsens", bcm2835_clock_osc_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_TSENSCTL, + .cdata.div_reg = CM_TSENSDIV, + .cdata.int_bits = 5, + .cdata.frac_bits = 0); +REGISTER_CLK(clock_tec, "tec", bcm2835_clock_osc_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_TECCTL, + .cdata.div_reg = CM_TECDIV, + .cdata.int_bits = 6, + .cdata.frac_bits = 0); + +/* Main peripherial parent mux */ +static const char *const bcm2835_clock_per_parents[] = +{ + "gnd", "osc", "testdebug0", "testdebug1", "plla_per", "pllc_per", "plld_per", "pllh_aux", +}; + +/* Clocks with per parent mux */ +REGISTER_CLK(clock_aveo, "aveo", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_AVEOCTL, + .cdata.div_reg = CM_AVEODIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 0, + .cdata.tcnt_mux = 38); +REGISTER_CLK(clock_cam0, "cam0", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_CAM0CTL, + .cdata.div_reg = CM_CAM0DIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 14); +REGISTER_CLK(clock_cam1, "cam1", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_CAM1CTL, + .cdata.div_reg = CM_CAM1DIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 15); +REGISTER_CLK(clock_dft, "dft", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DFTCTL, + .cdata.div_reg = CM_DFTDIV, + .cdata.int_bits = 5, + .cdata.frac_bits = 0); +REGISTER_CLK(clock_dpi, "dpi", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DPICTL, + .cdata.div_reg = CM_DPIDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 17); + +/* Arasan EMMC clock */ +REGISTER_CLK(clock_emmc, "emmc", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_EMMCCTL, + .cdata.div_reg = CM_EMMCDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 39); + +/* EMMC2 clock (only available for BCM2711) */ +REGISTER_CLK(clock_emmc2, "emmc2", bcm2835_clock_per_parents, SOC_TYPE_BCM2711, 0, + .cdata.ctl_reg = CM_EMMC2CTL, + .cdata.div_reg = CM_EMMC2DIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 42); + +/* General purpose (GPIO) clocks */ +REGISTER_CLK(clock_gp0, "gp0", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_GP0CTL, + .cdata.div_reg = CM_GP0DIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12, + .cdata.is_mash_clock = RT_TRUE, + .cdata.tcnt_mux = 20); +REGISTER_CLK(clock_gp1, "gp1", bcm2835_clock_per_parents, SOC_ALL, RT_CLK_F_IS_CRITICAL, + .cdata.ctl_reg = CM_GP1CTL, + .cdata.div_reg = CM_GP1DIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12, + .cdata.is_mash_clock = RT_TRUE, + .cdata.tcnt_mux = 21); +REGISTER_CLK(clock_gp2, "gp2", bcm2835_clock_per_parents, SOC_ALL, RT_CLK_F_IS_CRITICAL, + .cdata.ctl_reg = CM_GP2CTL, + .cdata.div_reg = CM_GP2DIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12); + +/* HDMI state machine */ +REGISTER_CLK(clock_hsm, "hsm", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_HSMCTL, + .cdata.div_reg = CM_HSMDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 22); +REGISTER_CLK(clock_pwm, "pwm", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_PWMCTL, + .cdata.div_reg = CM_PWMDIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12, + .cdata.is_mash_clock = RT_TRUE, + .cdata.tcnt_mux = 24); +REGISTER_CLK(clock_slim, "slim", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_SLIMCTL, + .cdata.div_reg = CM_SLIMDIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12, + .cdata.is_mash_clock = RT_TRUE, + .cdata.tcnt_mux = 25); +REGISTER_CLK(clock_smi, "smi", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_SMICTL, + .cdata.div_reg = CM_SMIDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 27); +REGISTER_CLK(clock_uart, "uart", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_UARTCTL, + .cdata.div_reg = CM_UARTDIV, + .cdata.int_bits = 10, + .cdata.frac_bits = 12, + .cdata.tcnt_mux = 28, + .cdata.round_up = RT_TRUE); + +/* Dsi clocks */ +REGISTER_CLK(clock_dsi0e, "dsi0e", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DSI0ECTL, + .cdata.div_reg = CM_DSI0EDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 18); +REGISTER_CLK(clock_dsi1e, "dsi1e", bcm2835_clock_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DSI1ECTL, + .cdata.div_reg = CM_DSI1EDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 19); + +/* + * Restrict clock sources for the PCM peripheral to the oscillator and + * PLLD_PER because other source may have varying rates or be switched + * off. + * + * Prevent other sources from being selected by replacing their names in + * the list of potential parents with dummy entries (entry index is + * significant). + */ +static const char *const bcm2835_pcm_per_parents[] = +{ + "-", "osc", "-", "-", "-", "-", "plld_per", "-", +}; + +REGISTER_CLK(clock_pcm, "pcm", bcm2835_pcm_per_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_PCMCTL, + .cdata.div_reg = CM_PCMDIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 12, + .cdata.is_mash_clock = RT_TRUE, + .cdata.low_jitter = RT_TRUE, + .cdata.tcnt_mux = 23); + +/* Main vpu parent mux */ +static const char *const bcm2835_clock_vpu_parents[] = +{ + "gnd", "osc", "testdebug0", "testdebug1", "plla_core", "pllc_core0", + "plld_core", "pllh_aux", "pllc_core1", "pllc_core2", +}; + +/* Clocks with vpu parent mux */ +REGISTER_CLK(clock_h264, "h264", bcm2835_clock_vpu_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_H264CTL, + .cdata.div_reg = CM_H264DIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 1); +REGISTER_CLK(clock_isp, "isp", bcm2835_clock_vpu_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_ISPCTL, + .cdata.div_reg = CM_ISPDIV, + .cdata.int_bits = 4, + .cdata.frac_bits = 8, + .cdata.tcnt_mux = 2); + +/* + * Secondary SDRAM clock. Used for low-voltage modes when the PLL + * in the SDRAM controller can't be used. + */ +REGISTER_CLK(clock_sdram, "sdram", bcm2835_clock_vpu_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_SDCCTL, + .cdata.div_reg = CM_SDCDIV, + .cdata.int_bits = 6, + .cdata.frac_bits = 0, + .cdata.tcnt_mux = 3); +/* + * CLOCK_V3D is used for v3d clock. Controlled by firmware, see + * clk-raspberrypi.c. + */ + +/* + * VPU clock. This doesn't have an enable bit, since it drives + * the bus for everything else, and is special so it doesn't need + * to be gated for rate changes. It is also known as "clk_audio" + * in various hardware documentation. + */ +REGISTER_CLK(clock_vpu, "vpu", bcm2835_clock_vpu_parents, SOC_ALL, RT_CLK_F_IS_CRITICAL, + .cdata.ctl_reg = CM_VPUCTL, + .cdata.div_reg = CM_VPUDIV, + .cdata.int_bits = 12, + .cdata.frac_bits = 8, + .cdata.is_vpu_clock = RT_TRUE, + .cdata.tcnt_mux = 5); + +/* + * DSI parent clocks. The DSI byte/DDR/DDR2 clocks come from the DSI + * analog PHY. The _inv variants are generated internally to cprman, + * but we don't use them so they aren't hooked up. + */ +static const char *const bcm2835_clock_dsi0_parents[] = +{ + "gnd", "osc", "testdebug0", "testdebug1", "dsi0_ddr", "dsi0_ddr_inv", "dsi0_ddr2", + "dsi0_ddr2_inv", "dsi0_byte", "dsi0_byte_inv", +}; + +REGISTER_CLK(clock_dsi0p, "dsi0p", bcm2835_clock_dsi0_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DSI0PCTL, + .cdata.div_reg = CM_DSI0PDIV, + .cdata.int_bits = 0, + .cdata.frac_bits = 0, + .cdata.tcnt_mux = 12); + +static const char *const bcm2835_clock_dsi1_parents[] = +{ + "gnd", "osc", "testdebug0", "testdebug1", "dsi1_ddr", "dsi1_ddr_inv", "dsi1_ddr2", + "dsi1_ddr2_inv", "dsi1_byte", "dsi1_byte_inv", +}; + +REGISTER_CLK(clock_dsi1p, "dsi1p", bcm2835_clock_dsi1_parents, SOC_ALL, 0, + .cdata.ctl_reg = CM_DSI1PCTL, + .cdata.div_reg = CM_DSI1PDIV, + .cdata.int_bits = 0, + .cdata.frac_bits = 0, + .cdata.tcnt_mux = 13); +/* + * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if + * you have the debug bit set in the power manager, which we + * don't bother exposing) are individual gates off of the + * non-stop vpu clock. + */ +REGISTER_GATE(clock_peri_image, "peri_image", "vpu", SOC_ALL, 0, + .cdata.ctl_reg = CM_PERIICTL); + +static struct rt_clk_cell *bcm2835_clk_cell[] = +{ + [BCM2835_PLLA] = &plla.cdata.cell, + [BCM2835_PLLB] = &pllb.cdata.cell, + [BCM2835_PLLC] = &pllc.cdata.cell, + [BCM2835_PLLD] = &plld.cdata.cell, + [BCM2835_PLLH] = &pllh.cdata.cell, + + [BCM2835_PLLA_CORE] = &plla_core.cdata.cell, + [BCM2835_PLLA_DSI0] = &plla_dsi0.cdata.cell, + [BCM2835_PLLA_CCP2] = &plla_ccp2.cdata.cell, + [BCM2835_PLLB_ARM] = &pllb_arm.cdata.cell, + [BCM2835_PLLC_CORE0] = &pllc_core0.cdata.cell, + [BCM2835_PLLC_CORE1] = &pllc_core1.cdata.cell, + [BCM2835_PLLC_CORE2] = &pllc_core2.cdata.cell, + [BCM2835_PLLC_PER] = &pllc_per.cdata.cell, + [BCM2835_PLLD_CORE] = &plld_core.cdata.cell, + [BCM2835_PLLD_PER] = &plld_per.cdata.cell, + [BCM2835_PLLD_DSI0] = &plld_dsi0.cdata.cell, + [BCM2835_PLLD_DSI1] = &plld_dsi1.cdata.cell, + [BCM2835_PLLH_RCAL] = &pllh_rcal.cdata.cell, + [BCM2835_PLLH_AUX] = &pllh_aux.cdata.cell, + [BCM2835_PLLH_PIX] = &pllh_pix.cdata.cell, + + [BCM2835_CLOCK_OTP] = &clock_otp.cdata.cell, + [BCM2835_CLOCK_TIMER] = &clock_timer.cdata.cell, + [BCM2835_CLOCK_TSENS] = &clock_tsens.cdata.cell, + [BCM2835_CLOCK_TEC] = &clock_tec.cdata.cell, + [BCM2835_CLOCK_AVEO] = &clock_aveo.cdata.cell, + [BCM2835_CLOCK_CAM0] = &clock_cam0.cdata.cell, + [BCM2835_CLOCK_CAM1] = &clock_cam1.cdata.cell, + [BCM2835_CLOCK_DFT] = &clock_dft.cdata.cell, + [BCM2835_CLOCK_DPI] = &clock_dpi.cdata.cell, + [BCM2835_CLOCK_EMMC] = &clock_emmc.cdata.cell, + [BCM2711_CLOCK_EMMC2] = &clock_emmc2.cdata.cell, + [BCM2835_CLOCK_GP0] = &clock_gp0.cdata.cell, + [BCM2835_CLOCK_GP1] = &clock_gp1.cdata.cell, + [BCM2835_CLOCK_GP2] = &clock_gp2.cdata.cell, + [BCM2835_CLOCK_HSM] = &clock_hsm.cdata.cell, + [BCM2835_CLOCK_PWM] = &clock_pwm.cdata.cell, + [BCM2835_CLOCK_SLIM] = &clock_slim.cdata.cell, + [BCM2835_CLOCK_SMI] = &clock_smi.cdata.cell, + [BCM2835_CLOCK_UART] = &clock_uart.cdata.cell, + [BCM2835_CLOCK_DSI0E] = &clock_dsi0e.cdata.cell, + [BCM2835_CLOCK_DSI1E] = &clock_dsi1e.cdata.cell, + [BCM2835_CLOCK_PCM] = &clock_pcm.cdata.cell, + [BCM2835_CLOCK_H264] = &clock_h264.cdata.cell, + [BCM2835_CLOCK_ISP] = &clock_isp.cdata.cell, + [BCM2835_CLOCK_SDRAM] = &clock_sdram.cdata.cell, + [BCM2835_CLOCK_VPU] = &clock_vpu.cdata.cell, + [BCM2835_CLOCK_DSI0P] = &clock_dsi0p.cdata.cell, + [BCM2835_CLOCK_DSI1P] = &clock_dsi1p.cdata.cell, + + [BCM2835_CLOCK_PERI_IMAGE] = &clock_peri_image.cdata.cell, +}; + +static rt_bool_t bcm2835_clk_claimed[RT_ARRAY_SIZE(bcm2835_clk_cell)]; + +static rt_bool_t bcm2835_clk_is_claimed(const char *name) +{ + for (int i = 0; i < RT_ARRAY_SIZE(bcm2835_clk_cell); ++i) + { + if (bcm2835_clk_cell[i]) + { + if (!rt_strcmp(name, bcm2835_clk_cell[i]->name)) + { + return bcm2835_clk_claimed[i]; + } + } + } + + return RT_FALSE; +} + +/* + * Permanently take a reference on the parent of the SDRAM clock. + * + * While the SDRAM is being driven by its dedicated PLL most of the + * time, there is a little loop running in the firmware that + * periodically switches the SDRAM to using our CM clock to do PVT + * recalibration, with the assumption that the previously configured + * SDRAM parent is still enabled and running. + */ +static void bcm2835_mark_sdc_parent_critical(struct rt_clk_cell *cell) +{ + struct rt_clk_cell *parent = rt_clk_cell_get_parent(cell); + + if (parent) + { + rt_clk_prepare_enable(parent->clk); + } +} + +static rt_err_t bcm2835_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t value; + struct rt_clk_cell *cell; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct bcm2835_clock_data *cdata; + const struct cprman_soc_data *pdata = pdev->id->data; + struct bcm2835_cprman *cprman = rt_calloc(1, sizeof(*cprman)); + + if (!cprman) + { + return -RT_ENOMEM; + } + + pdata = pdev->id->data; + cprman->soc = pdata->soc; + + cprman->regs = rt_dm_dev_iomap(dev, 0); + + if (!cprman->regs) + { + err = -RT_EIO; + goto _fail; + } + + if ((fw_np = rt_ofw_parse_phandle(np, "firmware", 0))) + { + if (!(cprman->fw = rpi_firmware_get(fw_np))) + { + err = -RT_ENOSYS; + goto _fail; + } + + rt_ofw_node_put(fw_np); + } + + /* Mux DSI0 clock to PLLD */ + cprman_write(cprman, CM_DSI0HSCK, 1); + + rt_memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); + + for (int i = 0; !rt_dm_dev_prop_read_u32_index(dev, "claim-clocks", i, &value); ++i) + { + bcm2835_clk_claimed[value]= RT_TRUE; + } + + rt_memcpy(cprman->real_parent_names, cprman_parent_names, sizeof(cprman_parent_names)); + + for (int i = 0; i < RT_ARRAY_SIZE(cprman_parent_names); ++i) + { + if (!(cprman->real_parent_names[i] = rt_ofw_clk_get_parent_name(np, i))) + { + break; + } + } + + /* + * Make sure the external oscillator has been registered. + * + * The other (DSI) clocks are not present on older device + * trees, which we still need to support for backwards + * compatibility. + */ + if (!cprman->real_parent_names[0]) + { + err = -RT_EINVAL; + goto _fail; + } + + for (int i = 0; i < RT_ARRAY_SIZE(bcm2835_clk_cell); ++i) + { + cell = bcm2835_clk_cell[i]; + + if (!cell) + { + continue; + } + + cdata = cell_to_bcm2835_clock_data(cell); + + if (cdata->supported & cprman->soc) + { + cdata->cprman = cprman; + + if (cdata->init) + { + cdata->init(cprman, cdata); + } + } + else + { + bcm2835_clk_cell[i] = RT_NULL; + } + } + + cprman->parent.dev = dev; + cprman->parent.cells = bcm2835_clk_cell; + cprman->parent.cells_nr = RT_ARRAY_SIZE(bcm2835_clk_cell); + + if ((err = rt_clk_register(&cprman->parent))) + { + goto _fail; + } + + bcm2835_mark_sdc_parent_critical(bcm2835_clk_cell[BCM2835_CLOCK_SDRAM]); + + return RT_EOK; + +_fail: + if (cprman->fw) + { + rpi_firmware_put(cprman->fw); + } + + if (cprman->regs) + { + rt_iounmap(cprman->regs); + } + + rt_free(cprman); + + return err; +} + +static const struct cprman_soc_data cprman_bcm2835_plat_data = +{ + .soc = SOC_TYPE_BCM2835, +}; + +static const struct cprman_soc_data cprman_bcm2711_plat_data = +{ + .soc = SOC_TYPE_BCM2711, +}; + +static const struct rt_ofw_node_id bcm2835_clk_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data }, + { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data }, + { /* Sentinel */ } +}; + +static struct rt_platform_driver clk_bcm2835_driver = +{ + .name = "clk-bcm2835", + .ids = bcm2835_clk_ofw_ids, + + .probe = bcm2835_clk_probe, +}; + +static int clk_bcm2835_register(void) +{ + rt_platform_driver_register(&clk_bcm2835_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(clk_bcm2835_register); diff --git a/bsp/raspberry-pi/dm/clk/clk-dsi.c b/bsp/raspberry-pi/dm/clk/clk-dsi.c new file mode 100755 index 0000000000..3a17849a96 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-dsi.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.dsi" +#define DBG_LVL DBG_INFO +#include + +struct dsi_clk +{ + struct rt_clk_node parent; +}; + +struct dsi_clk_output +{ + struct rt_clk_cell cell; + + rt_ubase_t div; +}; + +static rt_ubase_t dsi_clk_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct dsi_clk_output *clk = rt_container_of(cell, struct dsi_clk_output, cell); + + return parent_rate / clk->div; +} + +static rt_base_t dsi_clk_round_rate(struct rt_clk_cell *cell, rt_ubase_t drate, rt_ubase_t *prate) +{ + struct dsi_clk_output *clk = rt_container_of(cell, struct dsi_clk_output, cell); + + return *prate / clk->div; +} + +const struct rt_clk_ops dsi_clk_ops = +{ + .recalc_rate = dsi_clk_recalc_rate, + .round_rate = dsi_clk_round_rate, +}; + +#define REGISTER_CLK_DSI(_name, _div) \ +(void *)&(struct dsi_clk_output) \ +{ \ + .cell.name = _name, \ + .cell.ops = &dsi_clk_ops, \ + .div = _div, \ +} + +static struct rt_clk_cell *dsi0_clk_cell[] = +{ + REGISTER_CLK_DSI("dsi0_byte", 8), + REGISTER_CLK_DSI("dsi0_ddr2", 4), + REGISTER_CLK_DSI("dsi0_ddr", 2), +}; + +static struct rt_clk_cell *dsi1_clk_cell[] = +{ + REGISTER_CLK_DSI("dsi1_byte", 8), + REGISTER_CLK_DSI("dsi1_ddr2", 4), + REGISTER_CLK_DSI("dsi1_ddr", 2), +}; + +static rt_err_t dsi_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_clk_cell **dsi_clk_cell = (void *)pdev->id->data; + struct dsi_clk *dclk = rt_calloc(1, sizeof(*dclk)); + + if (!dclk) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < 3; ++i) + { + struct dsi_clk_output *clk = rt_container_of(dsi_clk_cell[i], struct dsi_clk_output, cell); + + rt_dm_dev_prop_read_string_index(dev, "clock-output-names", i, &clk->cell.name); + } + + dclk->parent.dev = dev; + dclk->parent.cells = dsi_clk_cell; + dclk->parent.cells_nr = 3; + dclk->parent.parents_clk = rt_err_ptr(-RT_EEMPTY); + + if ((err = rt_clk_register(&dclk->parent))) + { + goto _fail; + } + + return RT_EOK; +_fail: + rt_free(dclk); + + return err; +} + +static const struct rt_ofw_node_id dsi_clk_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-dsi0", .data = dsi0_clk_cell }, + { .compatible = "brcm,bcm2835-dsi1", .data = dsi1_clk_cell }, + { .compatible = "brcm,bcm2711-dsi0", .data = dsi0_clk_cell }, + { .compatible = "brcm,bcm2711-dsi1", .data = dsi1_clk_cell }, + { /* sentinel */ } +}; + +static struct rt_platform_driver dsi_clk_driver = +{ + .name = "clk-dsi", + .ids = dsi_clk_ofw_ids, + + .probe = dsi_clk_probe, +}; + +static int dsi_clk_register(void) +{ + struct rt_ofw_node *np = RT_NULL; + + rt_platform_driver_register(&dsi_clk_driver); + + /* Force probing of the DSIx clock */ + while ((np = rt_ofw_find_node_by_ids(np, dsi_clk_ofw_ids))) + { + rt_platform_ofw_device_probe_child(np); + } + + return 0; +} +INIT_SUBSYS_EXPORT(dsi_clk_register); diff --git a/bsp/raspberry-pi/dm/clk/clk-raspberrypi.c b/bsp/raspberry-pi/dm/clk/clk-raspberrypi.c new file mode 100755 index 0000000000..d6d43fb9e3 --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-raspberrypi.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.raspberrypi" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define RPI_FIRMWARE_STATE_ENABLE_BIT RT_BIT(0) +#define RPI_FIRMWARE_STATE_WAIT_BIT RT_BIT(1) + +/* + * Structure of the message passed to Raspberry Pi's firmware in order to + * change clock rates. The 'disable_turbo' option is only available to the ARM + * clock (pllb) which we enable by default as turbo mode will alter multiple + * clocks at once. + * + * Even though we're able to access the clock registers directly we're bound to + * use the firmware interface as the firmware ultimately takes care of + * mitigating overheating/undervoltage situations and we would be changing + * frequencies behind his back. + * + * For more information on the firmware interface check: + * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface + */ +rt_packed(struct raspberrypi_firmware_prop +{ + rt_le32_t id; + rt_le32_t val; + rt_le32_t disable_turbo; +}); + +struct rpi_firmware_get_clocks_response +{ + rt_uint32_t parent; + rt_uint32_t id; +}; + +struct raspberrypi_clk_data +{ + struct rt_clk_cell cell; + + rt_uint32_t id; + rt_bool_t export; + rt_bool_t minimize; + rt_ubase_t min_rate; +}; + +#define cell_to_raspberrypi_clk_data(cell) rt_container_of(cell, struct raspberrypi_clk_data, cell) + +struct raspberrypi_clk +{ + struct rt_clk_node parent; + + struct rpi_firmware *rpi_fw; +}; + +#define raw_to_raspberrypi_clk(raw) rt_container_of(raw, struct raspberrypi_clk, parent) + +static rt_err_t raspberrypi_clock_property(struct rpi_firmware *firmware, + struct raspberrypi_clk_data *data, rt_uint32_t tag, rt_uint32_t *val) +{ + rt_err_t err; + struct raspberrypi_firmware_prop msg = + { + .id = rt_cpu_to_le32(data->id), + .val = rt_cpu_to_le32(*val), + .disable_turbo = rt_cpu_to_le32(0), + }; + + if ((err = rpi_firmware_property(firmware, tag, &msg, sizeof(msg)))) + { + return err; + } + + *val = rt_le32_to_cpu(msg.val); + + return RT_EOK; +} + +static rt_bool_t raspberrypi_fw_is_prepared(struct rt_clk_cell *cell) +{ + rt_err_t err; + rt_uint32_t val = 0; + struct raspberrypi_clk_data *data = cell_to_raspberrypi_clk_data(cell); + struct raspberrypi_clk *rpi_clk = raw_to_raspberrypi_clk(cell->clk_np); + + if ((err = raspberrypi_clock_property(rpi_clk->rpi_fw, data, + RPI_FIRMWARE_GET_CLOCK_STATE, &val))) + { + return RT_FALSE; + } + + return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); +} + +static rt_ubase_t raspberrypi_fw_get_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_err_t err; + rt_uint32_t val = 0; + struct raspberrypi_clk_data *data = cell_to_raspberrypi_clk_data(cell); + struct raspberrypi_clk *rpi_clk = raw_to_raspberrypi_clk(cell->clk_np); + + if ((err = raspberrypi_clock_property(rpi_clk->rpi_fw, data, + RPI_FIRMWARE_GET_CLOCK_RATE, &val))) + { + return -RT_EIO; + } + + return val; +} + +static rt_err_t raspberrypi_fw_set_rate(struct rt_clk_cell *cell, + rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_err_t err; + rt_uint32_t in_rate = rate; + struct raspberrypi_clk_data *data = cell_to_raspberrypi_clk_data(cell); + struct raspberrypi_clk *rpi_clk = raw_to_raspberrypi_clk(cell->clk_np); + + if ((err = raspberrypi_clock_property(rpi_clk->rpi_fw, data, + RPI_FIRMWARE_SET_CLOCK_RATE, &in_rate))) + { + return err; + } + + return RT_EOK; +} + +static const struct rt_clk_ops raspberrypi_firmware_clk_ops = +{ + .is_prepared = raspberrypi_fw_is_prepared, + .recalc_rate = raspberrypi_fw_get_rate, + .set_rate = raspberrypi_fw_set_rate, +}; + +#define REGISTER_CLK(_struct, _name, ...) \ +static struct raspberrypi_clk_data _struct = \ +{ \ + .cell.name = _name, \ + .cell.ops = &raspberrypi_firmware_clk_ops, \ + .cell.flags = RT_CLK_F_GET_RATE_NOCACHE, \ + __VA_ARGS__ \ +}; + +REGISTER_CLK(clk_emmc, "emmc"); +REGISTER_CLK(clk_uart, "uart"); +REGISTER_CLK(clk_arm, "arm", .export = RT_TRUE); +REGISTER_CLK(clk_core, "core", + .export = RT_TRUE, + + /* + * The clock is shared between the HVS and the CSI + * controllers, on the BCM2711 and will change depending + * on the pixels composited on the HVS and the capture + * resolution on Unicam. + * + * Since the rate can get quite large, and we need to + * coordinate between both driver instances, let's + * always use the minimum the drivers will let us. + */ + .minimize = RT_TRUE); +REGISTER_CLK(clk_v3d, "v3d", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_h264, "h264"); +REGISTER_CLK(clk_isp, "isp", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_sdram, "sdram"); +REGISTER_CLK(clk_pixel, "pixel", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_pwm, "pwm"); +REGISTER_CLK(clk_hevc, "hevc", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_emmc2, "emmc2"); +REGISTER_CLK(clk_m2mc, "m2mc", + .export = RT_TRUE, + /* + * If we boot without any cable connected to any of the + * HDMI connector, the firmware will skip the HSM + * initialization and leave it with a rate of 0, + * resulting in a bus lockup when we're accessing the + * registers even if it's enabled. + * + * Let's put a sensible default so that we don't end up + * in this situation. + */ + .min_rate = 120000000, + /* + * The clock is shared between the two HDMI controllers + * on the BCM2711 and will change depending on the + * resolution output on each. Since the rate can get + * quite large, and we need to coordinate between both + * driver instances, let's always use the minimum the + * drivers will let us. + */ + .minimize = RT_TRUE); +REGISTER_CLK(clk_pixel_bvb, "pixel-bvb", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_vec, "vec", .export = RT_TRUE, .minimize = RT_TRUE); +REGISTER_CLK(clk_disp, "disp", .export = RT_TRUE, .minimize = RT_TRUE); + +static struct rt_clk_cell *raspberrypi_clk_cell[RPI_FIRMWARE_NUM_CLK_ID] = +{ + [RPI_FIRMWARE_EMMC_CLK_ID] = &clk_emmc.cell, + [RPI_FIRMWARE_UART_CLK_ID] = &clk_uart.cell, + [RPI_FIRMWARE_ARM_CLK_ID] = &clk_arm.cell, + [RPI_FIRMWARE_CORE_CLK_ID] = &clk_core.cell, + [RPI_FIRMWARE_V3D_CLK_ID] = &clk_v3d.cell, + [RPI_FIRMWARE_H264_CLK_ID] = &clk_h264.cell, + [RPI_FIRMWARE_ISP_CLK_ID] = &clk_isp.cell, + [RPI_FIRMWARE_SDRAM_CLK_ID] = &clk_sdram.cell, + [RPI_FIRMWARE_PIXEL_CLK_ID] = &clk_pixel.cell, + [RPI_FIRMWARE_PWM_CLK_ID] = &clk_pwm.cell, + [RPI_FIRMWARE_HEVC_CLK_ID] = &clk_hevc.cell, + [RPI_FIRMWARE_EMMC2_CLK_ID] = &clk_emmc2.cell, + [RPI_FIRMWARE_M2MC_CLK_ID] = &clk_m2mc.cell, + [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = &clk_pixel_bvb.cell, + [RPI_FIRMWARE_VEC_CLK_ID] = &clk_vec.cell, + [RPI_FIRMWARE_DISP_CLK_ID] = &clk_disp.cell, +}; + +struct rt_clk *raspberrypi_arm_clk_get(void) +{ + if (!clk_arm.cell.clk_np) + { + return RT_NULL; + } + + return rt_clk_cell_get_clk(&clk_arm.cell, RT_NULL); +} + +static rt_err_t raspberrypi_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_firmware_get_clocks_response *clks; + struct raspberrypi_clk *rpi_clk = rt_calloc(1, sizeof(*rpi_clk)); + + if (!rpi_clk) + { + return -RT_ENOMEM; + } + + if (np) + { + fw_np = rt_ofw_get_parent(np); + + if (fw_np) + { + rpi_clk->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + } + } + + if (!rpi_clk->rpi_fw) + { + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (fw_np) + { + rpi_clk->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + } + } + + if (!rpi_clk->rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + if (!(clks = rt_malloc(sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID))) + { + goto _fail; + } + + if ((err = rpi_firmware_property(rpi_clk->rpi_fw, RPI_FIRMWARE_GET_CLOCKS, + clks, sizeof(*clks) * RPI_FIRMWARE_NUM_CLK_ID))) + { + rt_free(clks); + goto _fail; + } + + for (int i = 0; i < RPI_FIRMWARE_NUM_CLK_ID; ++i) + { + rt_uint32_t min_rate = 0, max_rate = 0; + struct rt_clk *clk; + struct rt_clk_cell *cell; + struct raspberrypi_clk_data *data; + struct rpi_firmware_get_clocks_response *clk_req = &clks[i]; + + if (!clk_req->id) + { + break; + } + cell = raspberrypi_clk_cell[clk_req->id]; + if (!cell) + { + continue; + } + + cell->clk_np = &rpi_clk->parent; + data = cell_to_raspberrypi_clk_data(cell); + + data->id = clk_req->id; + + if (raspberrypi_clock_property(rpi_clk->rpi_fw, data, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE, &min_rate)) + { + LOG_W("clock %u: get min rate failed", clk_req->id); + } + + if (raspberrypi_clock_property(rpi_clk->rpi_fw, data, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, &max_rate)) + { + LOG_W("clock %u: get max rate failed", clk_req->id); + } + + if (!max_rate) + { + continue; + } + + if (clk_req->id == RPI_FIRMWARE_M2MC_CLK_ID) + { + min_rate = rt_min_t(rt_uint32_t, min_rate, 120000000); + } + + clk = rt_clk_cell_get_clk(cell, RT_NULL); + + if (!clk) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_clk_set_rate_range(clk, min_rate, max_rate); + + if (data->min_rate) + { + rt_ubase_t rate; + + rt_clk_set_rate_range(clk, data->min_rate, max_rate); + + rate = raspberrypi_fw_get_rate(cell, 0); + if (rate != (rt_ubase_t)-RT_EIO && rate < data->min_rate) + { + raspberrypi_fw_set_rate(cell, data->min_rate, 0); + } + } + } + + rt_free(clks); + + rpi_clk->parent.dev = dev; + rpi_clk->parent.cells = raspberrypi_clk_cell; + rpi_clk->parent.cells_nr = RT_ARRAY_SIZE(raspberrypi_clk_cell); + + if ((err = rt_clk_register(&rpi_clk->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rpi_clk->rpi_fw) + { + rpi_firmware_put(rpi_clk->rpi_fw); + } + + rt_free(rpi_clk); + + return err; +} + +static const struct rt_ofw_node_id raspberrypi_clk_ofw_ids[] = +{ + { .compatible = "raspberrypi,firmware-clocks" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver raspberrypi_clk_driver = +{ + .name = "clk-raspberrypi", + .ids = raspberrypi_clk_ofw_ids, + + .probe = raspberrypi_clk_probe, +}; + +static int raspberrypi_clk_register(void) +{ + rt_platform_driver_register(&raspberrypi_clk_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(raspberrypi_clk_register); diff --git a/bsp/raspberry-pi/dm/clk/clk-rp1.c b/bsp/raspberry-pi/dm/clk/clk-rp1.c new file mode 100755 index 0000000000..719763e23a --- /dev/null +++ b/bsp/raspberry-pi/dm/clk/clk-rp1.c @@ -0,0 +1,1797 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "clk.rp1" +#define DBG_LVL DBG_LOG +#include + +#include +#include + +#define PLL_SYS_CS 0x08000 +#define PLL_SYS_PWR 0x08004 +#define PLL_SYS_FBDIV_INT 0x08008 +#define PLL_SYS_FBDIV_FRAC 0x0800c +#define PLL_SYS_PRIM 0x08010 +#define PLL_SYS_SEC 0x08014 + +#define PLL_AUDIO_CS 0x0c000 +#define PLL_AUDIO_PWR 0x0c004 +#define PLL_AUDIO_FBDIV_INT 0x0c008 +#define PLL_AUDIO_FBDIV_FRAC 0x0c00c +#define PLL_AUDIO_PRIM 0x0c010 +#define PLL_AUDIO_SEC 0x0c014 +#define PLL_AUDIO_TERN 0x0c018 + +#define PLL_VIDEO_CS 0x10000 +#define PLL_VIDEO_PWR 0x10004 +#define PLL_VIDEO_FBDIV_INT 0x10008 +#define PLL_VIDEO_FBDIV_FRAC 0x1000c +#define PLL_VIDEO_PRIM 0x10010 +#define PLL_VIDEO_SEC 0x10014 + +#define GPCLK_OE_CTRL 0x00000 + +#define CLK_SYS_CTRL 0x00014 +#define CLK_SYS_DIV_INT 0x00018 +#define CLK_SYS_SEL 0x00020 + +#define CLK_SLOW_SYS_CTRL 0x00024 +#define CLK_SLOW_SYS_DIV_INT 0x00028 +#define CLK_SLOW_SYS_SEL 0x00030 + +#define CLK_DMA_CTRL 0x00044 +#define CLK_DMA_DIV_INT 0x00048 +#define CLK_DMA_SEL 0x00050 + +#define CLK_UART_CTRL 0x00054 +#define CLK_UART_DIV_INT 0x00058 +#define CLK_UART_SEL 0x00060 + +#define CLK_ETH_CTRL 0x00064 +#define CLK_ETH_DIV_INT 0x00068 +#define CLK_ETH_SEL 0x00070 + +#define CLK_PWM0_CTRL 0x00074 +#define CLK_PWM0_DIV_INT 0x00078 +#define CLK_PWM0_DIV_FRAC 0x0007c +#define CLK_PWM0_SEL 0x00080 + +#define CLK_PWM1_CTRL 0x00084 +#define CLK_PWM1_DIV_INT 0x00088 +#define CLK_PWM1_DIV_FRAC 0x0008c +#define CLK_PWM1_SEL 0x00090 + +#define CLK_AUDIO_IN_CTRL 0x00094 +#define CLK_AUDIO_IN_DIV_INT 0x00098 +#define CLK_AUDIO_IN_SEL 0x000a0 + +#define CLK_AUDIO_OUT_CTRL 0x000a4 +#define CLK_AUDIO_OUT_DIV_INT 0x000a8 +#define CLK_AUDIO_OUT_SEL 0x000b0 + +#define CLK_I2S_CTRL 0x000b4 +#define CLK_I2S_DIV_INT 0x000b8 +#define CLK_I2S_SEL 0x000c0 + +#define CLK_MIPI0_CFG_CTRL 0x000c4 +#define CLK_MIPI0_CFG_DIV_INT 0x000c8 +#define CLK_MIPI0_CFG_SEL 0x000d0 + +#define CLK_MIPI1_CFG_CTRL 0x000d4 +#define CLK_MIPI1_CFG_DIV_INT 0x000d8 +#define CLK_MIPI1_CFG_SEL 0x000e0 + +#define CLK_PCIE_AUX_CTRL 0x000e4 +#define CLK_PCIE_AUX_DIV_INT 0x000e8 +#define CLK_PCIE_AUX_SEL 0x000f0 + +#define CLK_USBH0_MICROFRAME_CTRL 0x000f4 +#define CLK_USBH0_MICROFRAME_DIV_INT 0x000f8 +#define CLK_USBH0_MICROFRAME_SEL 0x00100 + +#define CLK_USBH1_MICROFRAME_CTRL 0x00104 +#define CLK_USBH1_MICROFRAME_DIV_INT 0x00108 +#define CLK_USBH1_MICROFRAME_SEL 0x00110 + +#define CLK_USBH0_SUSPEND_CTRL 0x00114 +#define CLK_USBH0_SUSPEND_DIV_INT 0x00118 +#define CLK_USBH0_SUSPEND_SEL 0x00120 + +#define CLK_USBH1_SUSPEND_CTRL 0x00124 +#define CLK_USBH1_SUSPEND_DIV_INT 0x00128 +#define CLK_USBH1_SUSPEND_SEL 0x00130 + +#define CLK_ETH_TSU_CTRL 0x00134 +#define CLK_ETH_TSU_DIV_INT 0x00138 +#define CLK_ETH_TSU_SEL 0x00140 + +#define CLK_ADC_CTRL 0x00144 +#define CLK_ADC_DIV_INT 0x00148 +#define CLK_ADC_SEL 0x00150 + +#define CLK_SDIO_TIMER_CTRL 0x00154 +#define CLK_SDIO_TIMER_DIV_INT 0x00158 +#define CLK_SDIO_TIMER_SEL 0x00160 + +#define CLK_SDIO_ALT_SRC_CTRL 0x00164 +#define CLK_SDIO_ALT_SRC_DIV_INT 0x00168 +#define CLK_SDIO_ALT_SRC_SEL 0x00170 + +#define CLK_GP0_CTRL 0x00174 +#define CLK_GP0_DIV_INT 0x00178 +#define CLK_GP0_DIV_FRAC 0x0017c +#define CLK_GP0_SEL 0x00180 + +#define CLK_GP1_CTRL 0x00184 +#define CLK_GP1_DIV_INT 0x00188 +#define CLK_GP1_DIV_FRAC 0x0018c +#define CLK_GP1_SEL 0x00190 + +#define CLK_GP2_CTRL 0x00194 +#define CLK_GP2_DIV_INT 0x00198 +#define CLK_GP2_DIV_FRAC 0x0019c +#define CLK_GP2_SEL 0x001a0 + +#define CLK_GP3_CTRL 0x001a4 +#define CLK_GP3_DIV_INT 0x001a8 +#define CLK_GP3_DIV_FRAC 0x001ac +#define CLK_GP3_SEL 0x001b0 + +#define CLK_GP4_CTRL 0x001b4 +#define CLK_GP4_DIV_INT 0x001b8 +#define CLK_GP4_DIV_FRAC 0x001bc +#define CLK_GP4_SEL 0x001c0 + +#define CLK_GP5_CTRL 0x001c4 +#define CLK_GP5_DIV_INT 0x001c8 +#define CLK_GP5_DIV_FRAC 0x001cc +#define CLK_GP5_SEL 0x001d0 + +#define CLK_SYS_RESUS_CTRL 0x0020c + +#define CLK_SLOW_SYS_RESUS_CTRL 0x00214 + +#define FC0_REF_KHZ 0x0021c +#define FC0_MIN_KHZ 0x00220 +#define FC0_MAX_KHZ 0x00224 +#define FC0_DELAY 0x00228 +#define FC0_INTERVAL 0x0022c +#define FC0_SRC 0x00230 +#define FC0_STATUS 0x00234 +#define FC0_RESULT 0x00238 +#define FC_SIZE 0x20 +#define FC_COUNT 8 +#define FC_NUM(idx, off) ((idx) * 32 + (off)) + +#define AUX_SEL 1 + +#define VIDEO_CLOCKS_OFFSET 0x4000 +#define VIDEO_CLK_VEC_CTRL (VIDEO_CLOCKS_OFFSET + 0x0000) +#define VIDEO_CLK_VEC_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0004) +#define VIDEO_CLK_VEC_SEL (VIDEO_CLOCKS_OFFSET + 0x000c) +#define VIDEO_CLK_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0010) +#define VIDEO_CLK_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0014) +#define VIDEO_CLK_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x001c) +#define VIDEO_CLK_MIPI0_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0020) +#define VIDEO_CLK_MIPI0_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0024) +#define VIDEO_CLK_MIPI0_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0028) +#define VIDEO_CLK_MIPI0_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x002c) +#define VIDEO_CLK_MIPI1_DPI_CTRL (VIDEO_CLOCKS_OFFSET + 0x0030) +#define VIDEO_CLK_MIPI1_DPI_DIV_INT (VIDEO_CLOCKS_OFFSET + 0x0034) +#define VIDEO_CLK_MIPI1_DPI_DIV_FRAC (VIDEO_CLOCKS_OFFSET + 0x0038) +#define VIDEO_CLK_MIPI1_DPI_SEL (VIDEO_CLOCKS_OFFSET + 0x003c) + +#define DIV_INT_8BIT_MAX 0x000000ffU /* max divide for most clocks */ +#define DIV_INT_16BIT_MAX 0x0000ffffU /* max divide for GPx, PWM */ +#define DIV_INT_24BIT_MAX 0x00ffffffU /* max divide for CLK_SYS */ + +#define FC0_STATUS_DONE RT_BIT(4) +#define FC0_STATUS_RUNNING RT_BIT(8) +#define FC0_RESULT_FRAC_SHIFT 5 + +#define PLL_PRIM_DIV1_SHIFT 16 +#define PLL_PRIM_DIV1_MASK 0x00070000 +#define PLL_PRIM_DIV2_SHIFT 12 +#define PLL_PRIM_DIV2_MASK 0x00007000 + +#define PLL_SEC_DIV_SHIFT 8 +#define PLL_SEC_DIV_WIDTH 5 +#define PLL_SEC_DIV_MASK 0x00001f00 + +#define PLL_CS_LOCK RT_BIT(31) +#define PLL_CS_REFDIV_SHIFT 0 + +#define PLL_PWR_PD RT_BIT(0) +#define PLL_PWR_DACPD RT_BIT(1) +#define PLL_PWR_DSMPD RT_BIT(2) +#define PLL_PWR_POSTDIVPD RT_BIT(3) +#define PLL_PWR_4PHASEPD RT_BIT(4) +#define PLL_PWR_VCOPD RT_BIT(5) +#define PLL_PWR_MASK 0x0000003f + +#define PLL_SEC_RST RT_BIT(16) +#define PLL_SEC_IMPL RT_BIT(31) + +/* PLL phase output for both PRI and SEC */ +#define PLL_PH_EN RT_BIT(4) +#define PLL_PH_PHASE_SHIFT 0 + +#define RP1_PLL_PHASE_0 0 +#define RP1_PLL_PHASE_90 1 +#define RP1_PLL_PHASE_180 2 +#define RP1_PLL_PHASE_270 3 + +/* Clock fields for all clocks */ +#define CLK_CTRL_ENABLE RT_BIT(11) +#define CLK_CTRL_AUXSRC_MASK 0x000003e0 +#define CLK_CTRL_AUXSRC_SHIFT 5 +#define CLK_CTRL_SRC_SHIFT 0 +#define CLK_DIV_FRAC_BITS 16 + +#define KHz 1000 +#define MHz (KHz * KHz) +#define RP1_XOSC_RATE 19200000 +#define LOCK_TIMEOUT_NS 100000000 +#define FC_TIMEOUT_NS 100000000 + +#define MAX_CLK_PARENTS 16 + +#define ABS_DIFF(a, b) ((a) > (b) ? (a) - (b) : (b) - (a)) +#define DIV_NEAREST(a, b) (((a) + ((b) >> 1)) / (b)) +#define DIV_U64_NEAREST(a, b) rt_div_u64(((a) + ((b) >> 1)), (b)) + +struct clk_div_table +{ + rt_uint32_t val; + rt_uint32_t div; +}; + +struct rp1_clockman +{ + struct rt_clk_node parent; + + void *regs; + + struct rt_clk_cell *clk_cell_xosc; + struct rt_clk_cell *clk_cell_audio; + struct rt_clk_cell *clk_cell_i2s; + struct rt_clk_cell *clk_cell_slow_sys; +}; + +#define raw_to_rp1_clockman(raw) rt_container_of(raw, struct rp1_clockman, parent) + +#define RP1_CLK_BASE \ + struct rt_clk_cell cell; \ + void (*init)(struct rp1_clockman *clockman, struct rt_clk_cell *cell); + +struct rp1_clk_common +{ + RP1_CLK_BASE; +}; + +rt_inline rt_uint32_t set_register_field(rt_uint32_t reg, rt_uint32_t val, + rt_uint32_t mask, rt_uint32_t shift) +{ + reg &= ~mask; + reg |= (val << shift) & mask; + + return reg; +} + +rt_inline void clockman_write(struct rp1_clockman *clockman, + rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32(clockman->regs + reg) = val; +} + +rt_inline rt_uint32_t clockman_read(struct rp1_clockman *clockman, rt_uint32_t reg) +{ + return HWREG32(clockman->regs + reg); +} + +struct rp1_pll_core_data +{ + RP1_CLK_BASE; + + rt_ubase_t cached_rate; + + rt_uint32_t cs_reg; + rt_uint32_t pwr_reg; + rt_uint32_t fbdiv_int_reg; + rt_uint32_t fbdiv_frac_reg; + rt_uint32_t fc0_src; +}; + +#define cell_to_rp1_pll_core_data(cell) rt_container_of(cell, struct rp1_pll_core_data, cell) + +static rt_err_t rp1_pll_core_on(struct rt_clk_cell *cell) +{ + rt_tick_t timeout; + rt_uint32_t fbdiv_frac; + struct rp1_pll_core_data *pll_core = cell_to_rp1_pll_core_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + if (!(clockman_read(clockman, pll_core->cs_reg) & PLL_CS_LOCK)) + { + /* Reset to a known state. */ + clockman_write(clockman, pll_core->pwr_reg, PLL_PWR_MASK); + clockman_write(clockman, pll_core->fbdiv_int_reg, 20); + clockman_write(clockman, pll_core->fbdiv_frac_reg, 0); + clockman_write(clockman, pll_core->cs_reg, 1 << PLL_CS_REFDIV_SHIFT); + } + + /* Come out of reset. */ + fbdiv_frac = clockman_read(clockman, pll_core->fbdiv_frac_reg); + clockman_write(clockman, pll_core->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); + + /* Wait for the PLL to lock. */ + timeout = rt_tick_from_millisecond(LOCK_TIMEOUT_NS / 1000000); + timeout += rt_tick_get(); + + while (!(clockman_read(clockman, pll_core->cs_reg) & PLL_CS_LOCK)) + { + if (rt_tick_get() > timeout) + { + LOG_E("%s: can't lock PLL", cell->name); + return -RT_ETIMEOUT; + } + + rt_hw_cpu_relax(); + } + + return RT_EOK; +} + +static void rp1_pll_core_off(struct rt_clk_cell *cell) +{ + struct rp1_pll_core_data *pll_core = cell_to_rp1_pll_core_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, pll_core->pwr_reg, 0); +} + +static rt_bool_t rp1_pll_core_is_on(struct rt_clk_cell *cell) +{ + rt_uint32_t pwr; + struct rp1_pll_core_data *pll_core = cell_to_rp1_pll_core_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + pwr = clockman_read(clockman, pll_core->pwr_reg); + + return (pwr & PLL_PWR_PD) || (pwr & PLL_PWR_POSTDIVPD); +} + +static rt_ubase_t rp1_pll_core_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_ubase_t calc_rate; + rt_uint32_t fbdiv_int, fbdiv_frac; + struct rp1_pll_core_data *pll_core = cell_to_rp1_pll_core_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + fbdiv_int = clockman_read(clockman, pll_core->fbdiv_int_reg); + fbdiv_frac = clockman_read(clockman, pll_core->fbdiv_frac_reg); + calc_rate = ((rt_uint64_t)parent_rate * (((rt_uint64_t)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; + + return calc_rate; +} + +static rt_ubase_t get_pll_core_divider(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate, + rt_uint32_t *div_int, rt_uint32_t *div_frac) +{ + rt_ubase_t calc_rate; + rt_uint32_t fbdiv_int, fbdiv_frac; + rt_uint64_t div_fp64; /* 32.32 fixed point fraction. */ + + /* Factor of reference clock to VCO frequency. */ + div_fp64 = (rt_uint64_t)rate << 32; + div_fp64 = DIV_U64_NEAREST(div_fp64, parent_rate); + + /* Round the fractional component at 24 bits. */ + div_fp64 += 1 << (32 - 24 - 1); + + fbdiv_int = div_fp64 >> 32; + fbdiv_frac = (div_fp64 >> (32 - 24)) & 0xffffff; + + calc_rate = ((rt_uint64_t)parent_rate * (((rt_uint64_t)fbdiv_int << 24) + fbdiv_frac) + (1 << 23)) >> 24; + + *div_int = fbdiv_int; + *div_frac = fbdiv_frac; + + return calc_rate; +} + +static rt_base_t rp1_pll_core_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + rt_base_t calc_rate; + rt_uint32_t fbdiv_int, fbdiv_frac; + + calc_rate = get_pll_core_divider(cell, rate, *parent_rate, &fbdiv_int, &fbdiv_frac); + + return calc_rate; +} + +static rt_err_t rp1_pll_core_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_ubase_t calc_rate; + rt_uint32_t fbdiv_int, fbdiv_frac; + struct rp1_pll_core_data *pll_core = cell_to_rp1_pll_core_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + /* Disable dividers to start with. */ + clockman_write(clockman, pll_core->fbdiv_int_reg, 0); + clockman_write(clockman, pll_core->fbdiv_frac_reg, 0); + + calc_rate = get_pll_core_divider(cell, rate, parent_rate, &fbdiv_int, &fbdiv_frac); + + clockman_write(clockman, pll_core->pwr_reg, fbdiv_frac ? 0 : PLL_PWR_DSMPD); + clockman_write(clockman, pll_core->fbdiv_int_reg, fbdiv_int); + clockman_write(clockman, pll_core->fbdiv_frac_reg, fbdiv_frac); + + pll_core->cached_rate = calc_rate; + + /* Don't need to divide ref unless parent_rate > (output freq / 16) */ + clockman_write(clockman, pll_core->cs_reg, + clockman_read(clockman, pll_core->cs_reg) | (1 << PLL_CS_REFDIV_SHIFT)); + + return RT_EOK; +} + +static const struct rt_clk_ops rp1_pll_core_ops = +{ + .prepare = rp1_pll_core_on, + .unprepare = rp1_pll_core_off, + .is_prepared = rp1_pll_core_is_on, + .recalc_rate = rp1_pll_core_recalc_rate, + .round_rate = rp1_pll_core_round_rate, + .set_rate = rp1_pll_core_set_rate, +}; + +static void rp1_init_pll_core(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + cell->parents_nr = 1; + cell->parent_name = "xosc"; + cell->ops = &rp1_pll_core_ops; + cell->flags |= RT_CLK_F_IS_CRITICAL; +} + +#define REGISTER_PLL_CORE(...) (void *)&(struct rp1_pll_core_data){ .init = rp1_init_pll_core, __VA_ARGS__ } + +struct rp1_pll_data +{ + RP1_CLK_BASE; + + rt_ubase_t cached_rate; + + rt_uint32_t ctrl_reg; + rt_uint32_t fc0_src; +}; + +#define cell_to_rp1_pll_data(cell) rt_container_of(cell, struct rp1_pll_data, cell) + +static rt_ubase_t rp1_pll_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_uint32_t prim, prim_div1, prim_div2; + struct rp1_pll_data *pll = cell_to_rp1_pll_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + prim = clockman_read(clockman, pll->ctrl_reg); + prim_div1 = (prim & PLL_PRIM_DIV1_MASK) >> PLL_PRIM_DIV1_SHIFT; + prim_div2 = (prim & PLL_PRIM_DIV2_MASK) >> PLL_PRIM_DIV2_SHIFT; + + if (!prim_div1 || !prim_div2) + { + LOG_E("%s: zero divider value", cell->name); + return 0; + } + + return RT_DIV_ROUND_CLOSEST(parent_rate, prim_div1 * prim_div2); +} + +static void get_pll_prim_dividers(rt_ubase_t rate, rt_ubase_t parent_rate, + rt_uint32_t *divider1, rt_uint32_t *divider2) +{ + rt_base_t rate_diff, calc_rate; + rt_uint32_t div1, div2, best_div1 = 7, best_div2 = 7; + rt_ubase_t best_rate_diff = ABS_DIFF(RT_DIV_ROUND_CLOSEST(parent_rate, best_div1 * best_div2), rate); + + for (div1 = 1; div1 <= 7; ++div1) + { + for (div2 = 1; div2 <= div1; ++div2) + { + calc_rate = RT_DIV_ROUND_CLOSEST(parent_rate, div1 * div2); + rate_diff = ABS_DIFF(calc_rate, rate); + + if (calc_rate == rate) + { + best_div1 = div1; + best_div2 = div2; + goto _done; + } + else if (rate_diff < best_rate_diff) + { + best_div1 = div1; + best_div2 = div2; + best_rate_diff = rate_diff; + } + } + } + +_done: + *divider1 = best_div1; + *divider2 = best_div2; +} + +static rt_ubase_t rp1_get_xosc_rate(struct rp1_clockman *clockman) +{ + if (clockman->clk_cell_xosc) + { + return rt_clk_cell_get_rate(clockman->clk_cell_xosc); + } + + return RP1_XOSC_RATE; +} + +static rt_ubase_t calc_core_pll_rate(struct rp1_clockman *clockman, + rt_ubase_t target_rate, int *pdiv_prim, int *pdiv_clk) +{ + const rt_ubase_t xosc_rate = rp1_get_xosc_rate(clockman); + const rt_ubase_t core_max = 2400000000; + const rt_ubase_t core_min = xosc_rate * 16; + static const int prim_divs[] = + { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, + 18, 20, 21, 24, 25, 28, 30, 35, 36, 42, 49, + }; + rt_ubase_t core_rate = 0, best_rate = core_max + 1; + int div_int, div_frac, best_div_prim = 1, best_div_clk = 1; + rt_uint64_t div; + + /* Given the target rate, choose a set of divisors/multipliers */ + for (int i = 0; i < RT_ARRAY_SIZE(prim_divs); ++i) + { + int div_clk, div_prim = prim_divs[i]; + + for (div_clk = 1; div_clk <= 256; ++div_clk) + { + core_rate = target_rate * div_clk * div_prim; + if (core_rate >= core_min) + { + if (core_rate < best_rate) + { + best_rate = core_rate; + best_div_prim = div_prim; + best_div_clk = div_clk; + } + break; + } + } + } + + if (best_rate < core_max) + { + div = ((best_rate << 24) + xosc_rate / 2) / xosc_rate; + div_int = div >> 24; + div_frac = div % (1 << 24); + core_rate = (xosc_rate * ((div_int << 24) + div_frac) + (1 << 23)) >> 24; + } + else + { + core_rate = 0; + } + + if (pdiv_prim) + { + *pdiv_prim = best_div_prim; + } + if (pdiv_clk) + { + *pdiv_clk = best_div_clk; + } + + return core_rate; +} + +static rt_base_t rp1_pll_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + int div_prim, div_clk; + rt_uint32_t div1, div2; + rt_ubase_t audio_rate, core_rate; + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + core_rate = calc_core_pll_rate(clockman, rate, &div_prim, &div_clk); + audio_rate = DIV_NEAREST(core_rate, div_prim); + + if (cell == clockman->clk_cell_audio && audio_rate == rate) + { + *parent_rate = audio_rate; + } + + get_pll_prim_dividers(rate, *parent_rate, &div1, &div2); + + return RT_DIV_ROUND_CLOSEST(*parent_rate, div1 * div2); +} + +static rt_err_t rp1_pll_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t prim, prim_div1, prim_div2; + struct rp1_pll_data *pll = cell_to_rp1_pll_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + get_pll_prim_dividers(rate, parent_rate, &prim_div1, &prim_div2); + + prim = clockman_read(clockman, pll->ctrl_reg); + prim = set_register_field(prim, prim_div1, PLL_PRIM_DIV1_MASK, PLL_PRIM_DIV1_SHIFT); + prim = set_register_field(prim, prim_div2, PLL_PRIM_DIV2_MASK, PLL_PRIM_DIV2_SHIFT); + clockman_write(clockman, pll->ctrl_reg, prim); + + return RT_EOK; +} + +static const struct rt_clk_ops rp1_pll_ops = +{ + .recalc_rate = rp1_pll_recalc_rate, + .round_rate = rp1_pll_round_rate, + .set_rate = rp1_pll_set_rate, +}; + +static void rp1_init_pll(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + cell->ops = &rp1_pll_ops; +} + +#define REGISTER_PLL(...) (void *)&(struct rp1_pll_data){ .init = rp1_init_pll, __VA_ARGS__ } + +struct rp1_pll_div_data +{ + RP1_CLK_BASE; + + rt_ubase_t cached_rate; + + rt_uint32_t ctrl_reg; + rt_uint32_t fc0_src; +}; + +#define cell_to_rp1_pll_div_data(cell) rt_container_of(cell, struct rp1_pll_div_data, cell) + +static const struct clk_div_table pll_sec_div_table[] = +{ + { 0x00, 19 }, + { 0x01, 19 }, + { 0x02, 19 }, + { 0x03, 19 }, + { 0x04, 19 }, + { 0x05, 19 }, + { 0x06, 19 }, + { 0x07, 19 }, + { 0x08, 8 }, + { 0x09, 9 }, + { 0x0a, 10 }, + { 0x0b, 11 }, + { 0x0c, 12 }, + { 0x0d, 13 }, + { 0x0e, 14 }, + { 0x0f, 15 }, + { 0x10, 16 }, + { 0x11, 17 }, + { 0x12, 18 }, + { 0x13, 19 }, + { 0x14, 19 }, + { 0x15, 19 }, + { 0x16, 19 }, + { 0x17, 19 }, + { 0x18, 19 }, + { 0x19, 19 }, + { 0x1a, 19 }, + { 0x1b, 19 }, + { 0x1c, 19 }, + { 0x1d, 19 }, + { 0x1e, 19 }, + { 0x1f, 19 }, +}; + +static rt_err_t rp1_pll_divider_on(struct rt_clk_cell *cell) +{ + struct rp1_pll_div_data *pll_div = cell_to_rp1_pll_div_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, pll_div->ctrl_reg, + clockman_read(clockman, pll_div->ctrl_reg) & ~PLL_SEC_RST); + + return RT_EOK; +} + +static void rp1_pll_divider_off(struct rt_clk_cell *cell) +{ + struct rp1_pll_div_data *pll_div = cell_to_rp1_pll_div_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, pll_div->ctrl_reg, + clockman_read(clockman, pll_div->ctrl_reg) | PLL_SEC_RST); +} + +static rt_bool_t rp1_pll_divider_is_on(struct rt_clk_cell *cell) +{ + struct rp1_pll_div_data *pll_div = cell_to_rp1_pll_div_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + return !(clockman_read(clockman, pll_div->ctrl_reg) & PLL_SEC_RST); +} + +static rt_ubase_t rp1_pll_divider_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_uint32_t val, div; + struct rp1_pll_div_data *pll_div = cell_to_rp1_pll_div_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + val = clockman_read(clockman, pll_div->ctrl_reg) >> PLL_SEC_DIV_SHIFT; + val &= (1 << (PLL_SEC_DIV_WIDTH)) - 1; + + div = val + 1; + + for (int i = 0; i < RT_ARRAY_SIZE(pll_sec_div_table); ++i) + { + const struct clk_div_table *clkt = &pll_sec_div_table[i]; + + if (clkt->val == val) + { + div = clkt->div; + break; + } + } + + return div ? RT_DIV_ROUND_UP_ULL((rt_uint64_t)parent_rate, div) : parent_rate; +} + +static rt_base_t rp1_pll_divider_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + int bestdiv = 0, div, up, down; + rt_ubase_t up_rate, down_rate, maxdiv = 0; + rt_uint32_t mask = (1 << (PLL_SEC_DIV_WIDTH)) - 1; + + if (!rate) + { + rate = 1; + } + + for (int i = 0; i < RT_ARRAY_SIZE(pll_sec_div_table); ++i) + { + const struct clk_div_table *clkt = &pll_sec_div_table[i]; + + if (clkt->div > maxdiv && clkt->val <= mask) + { + maxdiv = clkt->div; + } + } + + up = RT_DIV_ROUND_UP_ULL((rt_uint64_t)*parent_rate, rate); + down = *parent_rate / rate; + + /* Round up table */ + div = up; + up = RT_UINT32_MAX >> 1; + + for (int i = 0; i < RT_ARRAY_SIZE(pll_sec_div_table); ++i) + { + const struct clk_div_table *clkt = &pll_sec_div_table[i]; + + if (clkt->div == div) + { + up = clkt->div; + break; + } + else if (clkt->div < div) + { + continue; + } + + if (clkt->div - div < up - div) + { + up = clkt->div; + } + } + + /* Round down table */ + div = down; + down = RT_UINT32_MAX; + + for (int i = 0; i < RT_ARRAY_SIZE(pll_sec_div_table); ++i) + { + const struct clk_div_table *clkt = &pll_sec_div_table[i]; + + if (clkt->div < down) + { + down = clkt->div; + } + } + + for (int i = 0; i < RT_ARRAY_SIZE(pll_sec_div_table); ++i) + { + const struct clk_div_table *clkt = &pll_sec_div_table[i]; + + if (clkt->div == div) + { + down = clkt->div; + break; + } + else if (clkt->div > div) + { + continue; + } + + if (div - clkt->div < div - down) + { + down = clkt->div; + } + } + + up_rate = RT_DIV_ROUND_UP_ULL((rt_uint64_t)*parent_rate, up); + down_rate = RT_DIV_ROUND_UP_ULL((rt_uint64_t)*parent_rate, down); + + bestdiv = (rate - up_rate) <= (down_rate - rate) ? up : down; + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + + return RT_DIV_ROUND_UP_ULL((rt_uint64_t)*parent_rate, div); +} + +static rt_err_t rp1_pll_divider_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t div, sec; + struct rp1_pll_div_data *pll_div = cell_to_rp1_pll_div_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + div = RT_DIV_ROUND_UP_ULL(parent_rate, rate); + div = rt_clamp(div, 8U, 19U); + + sec = clockman_read(clockman, pll_div->ctrl_reg); + sec = set_register_field(sec, div, PLL_SEC_DIV_MASK, PLL_SEC_DIV_SHIFT); + + /* Must keep the divider in reset to change the value. */ + sec |= PLL_SEC_RST; + clockman_write(clockman, pll_div->ctrl_reg, sec); + + sec &= ~PLL_SEC_RST; + clockman_write(clockman, pll_div->ctrl_reg, sec); + + return RT_EOK; +} + +static const struct rt_clk_ops rp1_pll_divider_ops = +{ + .prepare = rp1_pll_divider_on, + .unprepare = rp1_pll_divider_off, + .is_prepared = rp1_pll_divider_is_on, + .recalc_rate = rp1_pll_divider_recalc_rate, + .round_rate = rp1_pll_divider_round_rate, + .set_rate = rp1_pll_divider_set_rate, +}; + +static void rp1_init_pll_divider(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + cell->ops = &rp1_pll_divider_ops; +} + +#define REGISTER_PLL_DIV(...) (void *)&(struct rp1_pll_div_data){ .init = rp1_init_pll_divider, __VA_ARGS__ } + +struct rp1_pll_ph_data +{ + RP1_CLK_BASE; + + rt_uint32_t phase; + rt_uint32_t fixed_divider; + rt_uint32_t ph_reg; + rt_uint32_t fc0_src; +}; + +#define cell_to_rp1_pll_ph_data(cell) rt_container_of(cell, struct rp1_pll_ph_data, cell) + +static rt_err_t rp1_pll_ph_on(struct rt_clk_cell *cell) +{ + rt_uint32_t ph_reg; + struct rp1_pll_ph_data *pll_ph = cell_to_rp1_pll_ph_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + ph_reg = clockman_read(clockman, pll_ph->ph_reg); + ph_reg |= pll_ph->phase << PLL_PH_PHASE_SHIFT; + ph_reg |= PLL_PH_EN; + clockman_write(clockman, pll_ph->ph_reg, ph_reg); + + return RT_EOK; +} + +static void rp1_pll_ph_off(struct rt_clk_cell *cell) +{ + struct rp1_pll_ph_data *pll_ph = cell_to_rp1_pll_ph_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, pll_ph->ph_reg, + clockman_read(clockman, pll_ph->ph_reg) & ~PLL_PH_EN); +} + +static rt_bool_t rp1_pll_ph_is_on(struct rt_clk_cell *cell) +{ + struct rp1_pll_ph_data *pll_ph = cell_to_rp1_pll_ph_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + return !!(clockman_read(clockman, pll_ph->ph_reg) & PLL_PH_EN); +} + +static rt_ubase_t rp1_pll_ph_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct rp1_pll_ph_data *pll_ph = cell_to_rp1_pll_ph_data(cell); + + return parent_rate / pll_ph->fixed_divider; +} + +static rt_base_t rp1_pll_ph_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + struct rp1_pll_ph_data *pll_ph = cell_to_rp1_pll_ph_data(cell); + + return *parent_rate / pll_ph->fixed_divider; +} + +static rt_err_t rp1_pll_ph_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + return RT_EOK; +} + +static const struct rt_clk_ops rp1_pll_ph_ops = +{ + .prepare = rp1_pll_ph_on, + .unprepare = rp1_pll_ph_off, + .is_prepared = rp1_pll_ph_is_on, + .recalc_rate = rp1_pll_ph_recalc_rate, + .round_rate = rp1_pll_ph_round_rate, + .set_rate = rp1_pll_ph_set_rate, +}; + +static void rp1_init_pll_ph(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + cell->ops = &rp1_pll_ph_ops; +} + +#define REGISTER_PLL_PH(...) (void *)&(struct rp1_pll_ph_data){ .init = rp1_init_pll_ph, __VA_ARGS__ } + +struct rp1_clock_data +{ + RP1_CLK_BASE; + + rt_ubase_t cached_rate; + + int num_std_parents; + int num_aux_parents; + + rt_uint32_t oe_mask; + rt_uint32_t clk_src_mask; + rt_uint32_t ctrl_reg; + rt_uint32_t div_int_reg; + rt_uint32_t div_frac_reg; + rt_uint32_t sel_reg; + rt_uint32_t div_int_max; + rt_ubase_t max_freq; + rt_uint32_t fc0_src; +}; + +#define cell_to_rp1_clock_data(cell) rt_container_of(cell, struct rp1_clock_data, cell) + +static rt_err_t rp1_clock_on(struct rt_clk_cell *cell) +{ + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, clock->ctrl_reg, + clockman_read(clockman, clock->ctrl_reg) | CLK_CTRL_ENABLE); + + /* If this is a GPCLK, turn on the output-enable */ + if (clock->oe_mask) + { + clockman_write(clockman, GPCLK_OE_CTRL, + clockman_read(clockman, GPCLK_OE_CTRL) | clock->oe_mask); + } + + return RT_EOK; +} + +static void rp1_clock_off(struct rt_clk_cell *cell) +{ + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + clockman_write(clockman, clock->ctrl_reg, + clockman_read(clockman, clock->ctrl_reg) & ~CLK_CTRL_ENABLE); + /* If this is a GPCLK, turn off the output-enable */ + if (clock->oe_mask) + { + clockman_write(clockman, GPCLK_OE_CTRL, + clockman_read(clockman, GPCLK_OE_CTRL) & ~clock->oe_mask); + } +} + +static rt_bool_t rp1_clock_is_on(struct rt_clk_cell *cell) +{ + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + return !!(clockman_read(clockman, clock->ctrl_reg) & CLK_CTRL_ENABLE); +} + +static rt_ubase_t rp1_clock_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + rt_uint32_t frac; + rt_uint64_t calc_rate, div; + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + div = clockman_read(clockman, clock->div_int_reg); + frac = (clock->div_frac_reg != 0) ? clockman_read(clockman, clock->div_frac_reg) : 0; + + /* If the integer portion of the divider is 0, treat it as 2^16 */ + if (!div) + { + div = 1 << 16; + } + + div = (div << CLK_DIV_FRAC_BITS) | (frac >> (32 - CLK_DIV_FRAC_BITS)); + + calc_rate = (rt_uint64_t)parent_rate << CLK_DIV_FRAC_BITS; + calc_rate = calc_rate / div; + + return calc_rate; +} + +static rt_uint32_t rp1_clock_choose_div(rt_ubase_t rate, rt_ubase_t parent_rate, + const struct rp1_clock_data *clock) +{ + rt_uint64_t div; + + /* + * Due to earlier rounding, calculated parent_rate may differ from + * expected value. Don't fail on a small discrepancy near unity divide. + */ + if (!rate || rate > parent_rate + (parent_rate >> CLK_DIV_FRAC_BITS)) + { + return 0; + } + + /* + * Always express div in fixed-point format for fractional division; + * If no fractional divider is present, the fraction part will be zero. + */ + if (clock->div_frac_reg) + { + div = (rt_uint64_t)parent_rate << CLK_DIV_FRAC_BITS; + div = DIV_U64_NEAREST(div, rate); + } + else + { + div = DIV_U64_NEAREST(parent_rate, rate); + div <<= CLK_DIV_FRAC_BITS; + } + + div = rt_clamp(div, + (rt_uint64_t)(1ULL << CLK_DIV_FRAC_BITS), + (rt_uint64_t)clock->div_int_max << CLK_DIV_FRAC_BITS); + + return div; +} + +static rt_err_t rp1_clock_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t div; + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + div = rp1_clock_choose_div(rate, parent_rate, clock); + + if (!div) + { + div = 1 << CLK_DIV_FRAC_BITS; + } + + clockman_write(clockman, clock->div_int_reg, div >> CLK_DIV_FRAC_BITS); + + if (clock->div_frac_reg) + { + clockman_write(clockman, clock->div_frac_reg, div << (32 - CLK_DIV_FRAC_BITS)); + } + + return RT_EOK; +} + +static rt_err_t rp1_clock_set_parent(struct rt_clk_cell *cell, rt_uint8_t index) +{ + rt_uint32_t ctrl; + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + ctrl = clockman_read(clockman, clock->ctrl_reg); + + if (index >= clock->num_std_parents) + { + /* This is an aux source request */ + if (index >= clock->num_std_parents + clock->num_aux_parents) + { + return -RT_EINVAL; + } + + /* Select parent from aux list */ + ctrl = set_register_field(ctrl, index - clock->num_std_parents, + CLK_CTRL_AUXSRC_MASK, CLK_CTRL_AUXSRC_SHIFT); + /* Set src to aux list */ + ctrl = set_register_field(ctrl, AUX_SEL, clock->clk_src_mask, + CLK_CTRL_SRC_SHIFT); + } + else + { + ctrl = set_register_field(ctrl, index, clock->clk_src_mask, + CLK_CTRL_SRC_SHIFT); + } + + clockman_write(clockman, clock->ctrl_reg, ctrl); + + return RT_EOK; +} + +static rt_uint8_t rp1_clock_get_parent(struct rt_clk_cell *cell) +{ + rt_uint8_t parent; + rt_uint32_t sel, ctrl; + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + struct rp1_clockman *clockman = raw_to_rp1_clockman(cell->clk_np); + + sel = clockman_read(clockman, clock->sel_reg); + parent = __rt_ffs(sel) - 1; + + /* sel == 0 implies the parent clock is not enabled yet. */ + if (!sel) + { + /* Read the clock src from the CTRL register instead */ + ctrl = clockman_read(clockman, clock->ctrl_reg); + parent = (ctrl & clock->clk_src_mask) >> CLK_CTRL_SRC_SHIFT; + } + + if (parent >= clock->num_std_parents) + { + parent = AUX_SEL; + } + + if (parent == AUX_SEL) + { + /* + * Clock parent is an auxiliary source, so get the parent from + * the AUXSRC register field. + */ + ctrl = clockman_read(clockman, clock->ctrl_reg); + parent = (ctrl & CLK_CTRL_AUXSRC_MASK) >> CLK_CTRL_AUXSRC_SHIFT; + parent += clock->num_std_parents; + } + + if (parent >= cell->parents_nr) + { + parent = 0; + } + + return parent; +} + +static const struct rt_clk_ops rp1_clk_ops = +{ + .prepare = rp1_clock_on, + .unprepare = rp1_clock_off, + .is_prepared = rp1_clock_is_on, + .recalc_rate = rp1_clock_recalc_rate, + .set_rate = rp1_clock_set_rate, + .set_parent = rp1_clock_set_parent, + .get_parent = rp1_clock_get_parent, +}; + +static void rp1_init_clock(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + struct rp1_clock_data *clock = cell_to_rp1_clock_data(cell); + + cell->parents_nr = clock->num_std_parents + clock->num_aux_parents; + cell->ops = &rp1_clk_ops; +} + +#define REGISTER_CLK(...) (void *)&(struct rp1_clock_data){ .init = rp1_init_clock, __VA_ARGS__ } + +struct rp1_varsrc_data +{ + RP1_CLK_BASE; + rt_ubase_t rate; +}; + +#define cell_to_rp1_varsrc(cell) rt_container_of(cell, struct rp1_varsrc_data, cell) + +static rt_ubase_t rp1_varsrc_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate) +{ + struct rp1_varsrc_data *varsrc = cell_to_rp1_varsrc(cell); + + return varsrc->rate; +} + +static rt_base_t rp1_varsrc_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *parent_rate) +{ + return rate; +} + +static rt_err_t rp1_varsrc_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + struct rp1_varsrc_data *varsrc = cell_to_rp1_varsrc(cell); + + /* + * "varsrc" exists purely to let clock dividers know the frequency + * of an externally-managed clock source (such as MIPI DSI byte-clock) + * which may change at run-time as a side-effect of some other driver. + */ + varsrc->rate = rate; + + return RT_EOK; +} + +static const struct rt_clk_ops rp1_varsrc_ops = +{ + .recalc_rate = rp1_varsrc_recalc_rate, + .round_rate = rp1_varsrc_round_rate, + .set_rate = rp1_varsrc_set_rate, +}; + +static void rp1_init_varsrc(struct rp1_clockman *clockman, struct rt_clk_cell *cell) +{ + cell->parents_nr = 1; + cell->parent_name = "xosc"; + cell->ops = &rp1_varsrc_ops; +} + +#define REGISTER_VARSRC(...) (void *)&(struct rp1_varsrc_data){ .init = rp1_init_varsrc, __VA_ARGS__ } + +static struct rt_clk_cell *rp1_clk_cell[] = +{ + [RP1_PLL_SYS_CORE] = REGISTER_PLL_CORE( + .cell.name = "pll_sys_core", + .cs_reg = PLL_SYS_CS, + .pwr_reg = PLL_SYS_PWR, + .fbdiv_int_reg = PLL_SYS_FBDIV_INT, + .fbdiv_frac_reg = PLL_SYS_FBDIV_FRAC), + + [RP1_PLL_AUDIO_CORE] = REGISTER_PLL_CORE( + .cell.name = "pll_audio_core", + .cs_reg = PLL_AUDIO_CS, + .pwr_reg = PLL_AUDIO_PWR, + .fbdiv_int_reg = PLL_AUDIO_FBDIV_INT, + .fbdiv_frac_reg = PLL_AUDIO_FBDIV_FRAC), + + [RP1_PLL_VIDEO_CORE] = REGISTER_PLL_CORE( + .cell.name = "pll_video_core", + .cs_reg = PLL_VIDEO_CS, + .pwr_reg = PLL_VIDEO_PWR, + .fbdiv_int_reg = PLL_VIDEO_FBDIV_INT, + .fbdiv_frac_reg = PLL_VIDEO_FBDIV_FRAC), + + [RP1_PLL_SYS] = REGISTER_PLL( + .cell.name = "pll_sys", + .cell.parents_nr = 1, + .cell.parent_name = "pll_sys_core", + .ctrl_reg = PLL_SYS_PRIM, + .fc0_src = FC_NUM(0, 2)), + + [RP1_PLL_AUDIO] = REGISTER_PLL( + .cell.name = "pll_audio", + .cell.parents_nr = 1, + .cell.parent_name = "pll_audio_core", + .cell.flags = RT_CLK_F_SET_RATE_PARENT, + .ctrl_reg = PLL_AUDIO_PRIM, + .fc0_src = FC_NUM(4, 2)), + + [RP1_PLL_VIDEO] = REGISTER_PLL( + .cell.name = "pll_video", + .cell.parents_nr = 1, + .cell.parent_name = "pll_video_core", + .ctrl_reg = PLL_VIDEO_PRIM, + .fc0_src = FC_NUM(3, 2)), + + [RP1_PLL_SYS_PRI_PH] = REGISTER_PLL_PH( + .cell.name = "pll_sys_pri_ph", + .cell.parents_nr = 1, + .cell.parent_name = "pll_sys", + .ph_reg = PLL_SYS_PRIM, + .fixed_divider = 2, + .phase = RP1_PLL_PHASE_0, + .fc0_src = FC_NUM(1, 2)), + + [RP1_PLL_AUDIO_PRI_PH] = REGISTER_PLL_PH( + .cell.name = "pll_audio_pri_ph", + .cell.parents_nr = 1, + .cell.parent_name = "pll_audio", + .ph_reg = PLL_AUDIO_PRIM, + .fixed_divider = 2, + .phase = RP1_PLL_PHASE_0, + .fc0_src = FC_NUM(5, 1)), + + [RP1_PLL_VIDEO_PRI_PH] = REGISTER_PLL_PH( + .cell.name = "pll_video_pri_ph", + .cell.parents_nr = 1, + .cell.parent_name = "pll_video", + .ph_reg = PLL_VIDEO_PRIM, + .fixed_divider = 2, + .phase = RP1_PLL_PHASE_0, + .fc0_src = FC_NUM(4, 3)), + + [RP1_PLL_SYS_SEC] = REGISTER_PLL_DIV( + .cell.name = "pll_sys_sec", + .cell.parents_nr = 1, + .cell.parent_name = "pll_sys_core", + .ctrl_reg = PLL_SYS_SEC, + .fc0_src = FC_NUM(2, 2)), + + [RP1_PLL_AUDIO_SEC] = REGISTER_PLL_DIV( + .cell.name = "pll_audio_sec", + .cell.parents_nr = 1, + .cell.parent_name = "pll_audio_core", + .ctrl_reg = PLL_AUDIO_SEC, + .fc0_src = FC_NUM(6, 2)), + + [RP1_PLL_VIDEO_SEC] = REGISTER_PLL_DIV( + .cell.name = "pll_video_sec", + .cell.parents_nr = 1, + .cell.parent_name = "pll_video_core", + .ctrl_reg = PLL_VIDEO_SEC, + .fc0_src = FC_NUM(5, 3)), + + [RP1_PLL_AUDIO_TERN] = REGISTER_PLL_DIV( + .cell.name = "pll_audio_tern", + .cell.parents_nr = 1, + .cell.parent_name = "pll_audio_core", + .ctrl_reg = PLL_AUDIO_TERN, + .fc0_src = FC_NUM(6, 2)), + + [RP1_CLK_SYS] = REGISTER_CLK( + .cell.name = "clk_sys", + .cell.parent_names = (const char *[]){ "xosc", "", "pll_sys" }, + .cell.flags = RT_CLK_F_IS_CRITICAL, + .num_std_parents = 3, + .num_aux_parents = 0, + .ctrl_reg = CLK_SYS_CTRL, + .div_int_reg = CLK_SYS_DIV_INT, + .sel_reg = CLK_SYS_SEL, + .div_int_max = DIV_INT_24BIT_MAX, + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(0, 4), + .clk_src_mask = 0x3), + + [RP1_CLK_SLOW_SYS] = REGISTER_CLK( + .cell.name = "clk_slow_sys", + .cell.parent_name = "xosc", + .cell.flags = RT_CLK_F_IS_CRITICAL, + .num_std_parents = 1, + .num_aux_parents = 0, + .ctrl_reg = CLK_SLOW_SYS_CTRL, + .div_int_reg = CLK_SLOW_SYS_DIV_INT, + .sel_reg = CLK_SLOW_SYS_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(1, 4), + .clk_src_mask = 0x1), + + [RP1_CLK_DMA] = REGISTER_CLK( + .cell.name = "clk_dma", + .cell.parent_names = (const char *[]){ "pll_sys_pri_ph", "pll_video", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_DMA_CTRL, + .div_int_reg = CLK_DMA_DIV_INT, + .sel_reg = CLK_DMA_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(2, 2)), + + [RP1_CLK_UART] = REGISTER_CLK( + .cell.name = "clk_uart", + .cell.parent_names = (const char *[]){ "pll_sys_pri_ph", "pll_video", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_UART_CTRL, + .div_int_reg = CLK_UART_DIV_INT, + .sel_reg = CLK_UART_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(6, 7)), + + [RP1_CLK_ETH] = REGISTER_CLK( + .cell.name = "clk_eth", + .cell.parent_names = (const char *[]){ "pll_sys_sec", "pll_sys", "pll_video_sec" }, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_ETH_CTRL, + .div_int_reg = CLK_ETH_DIV_INT, + .sel_reg = CLK_ETH_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 125 * MHz, + .fc0_src = FC_NUM(4, 6)), + + [RP1_CLK_PWM0] = REGISTER_CLK( + .cell.name = "clk_pwm0", + .cell.parent_names = (const char *[]){ "", "pll_video_sec", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_PWM0_CTRL, + .div_int_reg = CLK_PWM0_DIV_INT, + .div_frac_reg = CLK_PWM0_DIV_FRAC, + .sel_reg = CLK_PWM0_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 76800 * KHz, + .fc0_src = FC_NUM(0, 5)), + + [RP1_CLK_PWM1] = REGISTER_CLK( + .cell.name = "clk_pwm1", + .cell.parent_names = (const char *[]){ "", "pll_video_sec", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_PWM1_CTRL, + .div_int_reg = CLK_PWM1_DIV_INT, + .div_frac_reg = CLK_PWM1_DIV_FRAC, + .sel_reg = CLK_PWM1_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 76800 * KHz, + .fc0_src = FC_NUM(1, 5)), + + [RP1_CLK_AUDIO_IN] = REGISTER_CLK( + .cell.name = "clk_audio_in", + .cell.parent_names = (const char *[]){ "", "", "", "pll_video_sec", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 5, + .ctrl_reg = CLK_AUDIO_IN_CTRL, + .div_int_reg = CLK_AUDIO_IN_DIV_INT, + .sel_reg = CLK_AUDIO_IN_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 76800 * KHz, + .fc0_src = FC_NUM(2, 5)), + + [RP1_CLK_AUDIO_OUT] = REGISTER_CLK( + .cell.name = "clk_audio_out", + .cell.parent_names = (const char *[]){ "", "pll_audio_sec", "pll_video_sec", "xosc" }, + .num_std_parents = 0, + .num_aux_parents = 4, + .ctrl_reg = CLK_AUDIO_OUT_CTRL, + .div_int_reg = CLK_AUDIO_OUT_DIV_INT, + .sel_reg = CLK_AUDIO_OUT_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 153600 * KHz, + .fc0_src = FC_NUM(3, 5)), + + [RP1_CLK_I2S] = REGISTER_CLK( + .cell.name = "clk_i2s", + .cell.parent_names = (const char *[]){ "xosc", "pll_audio", "pll_audio_sec" }, + .cell.flags = RT_CLK_F_SET_RATE_PARENT, + .num_std_parents = 0, + .num_aux_parents = 3, + .ctrl_reg = CLK_I2S_CTRL, + .div_int_reg = CLK_I2S_DIV_INT, + .sel_reg = CLK_I2S_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(4, 4)), + + [RP1_CLK_MIPI0_CFG] = REGISTER_CLK( + .cell.name = "clk_mipi0_cfg", + .cell.parent_name = "xosc", + .num_std_parents = 0, + .num_aux_parents = 1, + .ctrl_reg = CLK_MIPI0_CFG_CTRL, + .div_int_reg = CLK_MIPI0_CFG_DIV_INT, + .sel_reg = CLK_MIPI0_CFG_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(4, 5)), + + [RP1_CLK_MIPI1_CFG] = REGISTER_CLK( + .cell.name = "clk_mipi1_cfg", + .cell.parent_name = "xosc", + .num_std_parents = 0, + .num_aux_parents = 1, + .ctrl_reg = CLK_MIPI1_CFG_CTRL, + .div_int_reg = CLK_MIPI1_CFG_DIV_INT, + .sel_reg = CLK_MIPI1_CFG_SEL, + .clk_src_mask = 1, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(5, 6)), + + [RP1_CLK_ETH_TSU] = REGISTER_CLK( + .cell.name = "clk_eth_tsu", + .cell.parent_names = (const char *[]){ "xosc", "pll_video_sec", "", "", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 8, + .ctrl_reg = CLK_ETH_TSU_CTRL, + .div_int_reg = CLK_ETH_TSU_DIV_INT, + .sel_reg = CLK_ETH_TSU_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(5, 7)), + + [RP1_CLK_ADC] = REGISTER_CLK( + .cell.name = "clk_adc", + .cell.parent_name = "xosc", + .num_std_parents = 0, + .num_aux_parents = 1, + .ctrl_reg = CLK_ADC_CTRL, + .div_int_reg = CLK_ADC_DIV_INT, + .sel_reg = CLK_ADC_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(5, 5)), + + [RP1_CLK_SDIO_TIMER] = REGISTER_CLK( + .cell.name = "clk_sdio_timer", + .cell.parent_name = "xosc", + .num_std_parents = 0, + .num_aux_parents = 1, + .ctrl_reg = CLK_SDIO_TIMER_CTRL, + .div_int_reg = CLK_SDIO_TIMER_DIV_INT, + .sel_reg = CLK_SDIO_TIMER_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 50 * MHz, + .fc0_src = FC_NUM(3, 4)), + + [RP1_CLK_SDIO_ALT_SRC] = REGISTER_CLK( + .cell.name = "clk_sdio_alt_src", + .cell.parent_name = "pll_sys", + .num_std_parents = 0, + .num_aux_parents = 1, + .ctrl_reg = CLK_SDIO_ALT_SRC_CTRL, + .div_int_reg = CLK_SDIO_ALT_SRC_DIV_INT, + .sel_reg = CLK_SDIO_ALT_SRC_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(5, 4)), + + [RP1_CLK_GP0] = REGISTER_CLK( + .cell.name = "clk_gp0", + .cell.parent_names = (const char *[]){ "xosc", "", "", "", "", "", "pll_sys", "", "", "", "clk_i2s", "clk_adc", "", "", "", "clk_sys" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(0), + .ctrl_reg = CLK_GP0_CTRL, + .div_int_reg = CLK_GP0_DIV_INT, + .div_frac_reg = CLK_GP0_DIV_FRAC, + .sel_reg = CLK_GP0_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(0, 1)), + + [RP1_CLK_GP1] = REGISTER_CLK( + .cell.name = "clk_gp1", + .cell.parent_names = (const char *[]){ "clk_sdio_timer", "", "", "", "", "", "pll_sys_pri_ph", "", "", "", "clk_adc", "clk_dpi", "clk_pwm0", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(1), + .ctrl_reg = CLK_GP1_CTRL, + .div_int_reg = CLK_GP1_DIV_INT, + .div_frac_reg = CLK_GP1_DIV_FRAC, + .sel_reg = CLK_GP1_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(1, 1)), + + [RP1_CLK_GP2] = REGISTER_CLK( + .cell.name = "clk_gp2", + .cell.parent_names = (const char *[]){ "clk_sdio_alt_src", "", "", "", "", "", "pll_sys_sec", "", "pll_video", "clk_audio_in", "clk_dpi", "clk_pwm0", "clk_pwm1", "clk_mipi0_dpi", "clk_mipi1_cfg", "clk_sys" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(2), + .ctrl_reg = CLK_GP2_CTRL, + .div_int_reg = CLK_GP2_DIV_INT, + .div_frac_reg = CLK_GP2_DIV_FRAC, + .sel_reg = CLK_GP2_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(2, 1)), + + [RP1_CLK_GP3] = REGISTER_CLK( + .cell.name = "clk_gp3", + .cell.parent_names = (const char *[]){ "xosc", "", "", "", "", "", "", "", "pll_video_pri_ph", "clk_audio_out", "", "", "clk_mipi1_dpi", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(3), + .ctrl_reg = CLK_GP3_CTRL, + .div_int_reg = CLK_GP3_DIV_INT, + .div_frac_reg = CLK_GP3_DIV_FRAC, + .sel_reg = CLK_GP3_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(3, 1)), + + [RP1_CLK_GP4] = REGISTER_CLK( + .cell.name = "clk_gp4", + .cell.parent_names = (const char *[]){ "xosc", "", "", "", "", "", "", "pll_video_sec", "", "", "", "clk_mipi0_cfg", "clk_uart", "", "", "clk_sys" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(4), + .ctrl_reg = CLK_GP4_CTRL, + .div_int_reg = CLK_GP4_DIV_INT, + .div_frac_reg = CLK_GP4_DIV_FRAC, + .sel_reg = CLK_GP4_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(4, 1)), + + [RP1_CLK_GP5] = REGISTER_CLK( + .cell.name = "clk_gp5", + .cell.parent_names = (const char *[]){ "xosc", "", "", "", "", "", "", "pll_video_sec", "clk_eth_tsu", "", "clk_vec", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 16, + .oe_mask = RT_BIT(5), + .ctrl_reg = CLK_GP5_CTRL, + .div_int_reg = CLK_GP5_DIV_INT, + .div_frac_reg = CLK_GP5_DIV_FRAC, + .sel_reg = CLK_GP5_SEL, + .div_int_max = DIV_INT_16BIT_MAX, + .max_freq = 100 * MHz, + .fc0_src = FC_NUM(5, 1)), + + [RP1_CLK_VEC] = REGISTER_CLK( + .cell.name = "clk_vec", + .cell.parent_names = (const char *[]){ "pll_sys_pri_ph", "pll_video_sec", "pll_video", "", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 8, + .ctrl_reg = VIDEO_CLK_VEC_CTRL, + .div_int_reg = VIDEO_CLK_VEC_DIV_INT, + .sel_reg = VIDEO_CLK_VEC_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 108 * MHz, + .fc0_src = FC_NUM(0, 6)), + + [RP1_CLK_DPI] = REGISTER_CLK( + .cell.name = "clk_dpi", + .cell.parent_names = (const char *[]){ "pll_sys", "pll_video_sec", "pll_video", "", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 8, + .ctrl_reg = VIDEO_CLK_DPI_CTRL, + .div_int_reg = VIDEO_CLK_DPI_DIV_INT, + .sel_reg = VIDEO_CLK_DPI_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(1, 6)), + + [RP1_CLK_MIPI0_DPI] = REGISTER_CLK( + .cell.name = "clk_mipi0_dpi", + .cell.parent_names = (const char *[]){ "pll_sys", "pll_video_sec", "pll_video", "clksrc_mipi0_dsi_byteclk", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 8, + .ctrl_reg = VIDEO_CLK_MIPI0_DPI_CTRL, + .div_int_reg = VIDEO_CLK_MIPI0_DPI_DIV_INT, + .div_frac_reg = VIDEO_CLK_MIPI0_DPI_DIV_FRAC, + .sel_reg = VIDEO_CLK_MIPI0_DPI_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(2, 6)), + + [RP1_CLK_MIPI1_DPI] = REGISTER_CLK( + .cell.name = "clk_mipi1_dpi", + .cell.parent_names = (const char *[]){ "pll_sys", "pll_video_sec", "pll_video", "clksrc_mipi1_dsi_byteclk", "", "", "", "" }, + .num_std_parents = 0, + .num_aux_parents = 8, + .ctrl_reg = VIDEO_CLK_MIPI1_DPI_CTRL, + .div_int_reg = VIDEO_CLK_MIPI1_DPI_DIV_INT, + .div_frac_reg = VIDEO_CLK_MIPI1_DPI_DIV_FRAC, + .sel_reg = VIDEO_CLK_MIPI1_DPI_SEL, + .div_int_max = DIV_INT_8BIT_MAX, + .max_freq = 200 * MHz, + .fc0_src = FC_NUM(3, 6)), + + [RP1_CLK_MIPI0_DSI_BYTECLOCK] = REGISTER_VARSRC( + .cell.name = "clksrc_mipi0_dsi_byteclk"), + [RP1_CLK_MIPI1_DSI_BYTECLOCK] = REGISTER_VARSRC( + .cell.name = "clksrc_mipi1_dsi_byteclk"), +}; + +static rt_err_t rp1_clk_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rp1_clockman *clockman = rt_calloc(1, sizeof(*clockman)); + + if (!clockman) + { + return -RT_ENOMEM; + } + + clockman->regs = rt_dm_dev_iomap(dev, 0); + + if (!clockman->regs) + { + LOG_E("%s: ioremap failed", rt_ofw_node_full_name(dev->ofw_node)); + err = -RT_EIO; + goto _free; + } + + clockman->clk_cell_i2s = rp1_clk_cell[RP1_CLK_I2S]; + clockman->clk_cell_slow_sys = rp1_clk_cell[RP1_CLK_SLOW_SYS]; + + for (int i = 0; i < RT_ARRAY_SIZE(rp1_clk_cell); ++i) + { + struct rp1_clk_common *common; + struct rt_clk_cell *cell = rp1_clk_cell[i]; + + if (!cell) + { + continue; + } + + common = rt_container_of(cell, struct rp1_clk_common, cell); + + if (common->init) + { + common->init(clockman, cell); + } + } + + clockman->parent.dev = dev; + clockman->parent.cells = rp1_clk_cell; + clockman->parent.cells_nr = RT_ARRAY_SIZE(rp1_clk_cell); + + for (int i = 0; i < RT_ARRAY_SIZE(rp1_clk_cell); ++i) + { + struct rt_clk_cell *cell = rp1_clk_cell[i]; + + if (cell) + { + cell->clk_np = &clockman->parent; + } + } + + clockman->clk_cell_xosc = rt_clk_cell_get_parent_by_index(clockman->clk_cell_i2s, 0); + clockman->clk_cell_audio = rt_clk_cell_get_parent_by_index(clockman->clk_cell_i2s, 1); + + if ((err = rt_clk_register(&clockman->parent))) + { + LOG_E("%s: rt_clk_register failed err=%s", + rt_ofw_node_full_name(dev->ofw_node), rt_strerror(err)); + goto _free; + } + + return RT_EOK; + +_free: + if (clockman->regs) + { + rt_iounmap(clockman->regs); + } + + rt_free(clockman); + + return err; +} + +static const struct rt_ofw_node_id rp1_clk_ofw_ids[] = +{ + { .compatible = "raspberrypi,rp1-clocks" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rp1_clk_driver = +{ + .name = "clk-rp1", + .ids = rp1_clk_ofw_ids, + + .probe = rp1_clk_probe, +}; + +static int rp1_clk_register(void) +{ + rt_platform_driver_register(&rp1_clk_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rp1_clk_register); diff --git a/bsp/raspberry-pi/dm/clock_time/Kconfig b/bsp/raspberry-pi/dm/clock_time/Kconfig new file mode 100755 index 0000000000..f903a973d6 --- /dev/null +++ b/bsp/raspberry-pi/dm/clock_time/Kconfig @@ -0,0 +1,3 @@ +config RT_CLOCK_TIME_BCM2835 + bool "BCM2835 Timer" + default y diff --git a/bsp/raspberry-pi/dm/clock_time/SConscript b/bsp/raspberry-pi/dm/clock_time/SConscript new file mode 100755 index 0000000000..c6026dac73 --- /dev/null +++ b/bsp/raspberry-pi/dm/clock_time/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_CLOCK_TIME_BCM2835']): + src += ['clock_time-bcm2835_timer.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/clock_time/clock_time-bcm2835_timer.c b/bsp/raspberry-pi/dm/clock_time/clock_time-bcm2835_timer.c new file mode 100755 index 0000000000..9b011bd070 --- /dev/null +++ b/bsp/raspberry-pi/dm/clock_time/clock_time-bcm2835_timer.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define REG_CONTROL 0x00 +#define REG_COUNTER_LO 0x04 +#define REG_COUNTER_HI 0x08 +#define REG_COMPARE(n) (0x0c + (n) * 4) +#define MAX_TIMER 4 + +struct bcm2835_timer; + +struct bcm2835_timer_device +{ + struct rt_clock_timer_device parent; + + int id; + int irq; + void *compare; + + struct bcm2835_timer *timer; +}; + +struct bcm2835_timer +{ + void *base; + + struct bcm2835_timer_device device[MAX_TIMER]; + struct rt_clock_timer_info info; +}; + +#define raw_to_bcm2835_timer(raw) rt_container_of(raw, struct bcm2835_timer_device, parent) + +static void bcm2835_timer_init(struct rt_clock_timer_device *timer, rt_uint32_t state) +{ + RT_UNUSED(timer); + RT_UNUSED(state); +} + +static rt_err_t bcm2835_timer_start(struct rt_clock_timer_device *timer, rt_uint32_t cnt, rt_clock_timer_mode_t mode) +{ + rt_err_t err = RT_EOK; + struct bcm2835_timer_device *timer_dev = raw_to_bcm2835_timer(timer); + + switch (mode) + { + case CLOCK_TIMER_MODE_ONESHOT: + HWREG32(timer_dev->compare) = HWREG32(timer_dev->timer->base + REG_COUNTER_LO) + cnt; + break; + + case CLOCK_TIMER_MODE_PERIOD: + err = -RT_ENOSYS; + break; + + default: + err = -RT_EINVAL; + break; + } + + if (!err) + { + timer->cycles = cnt; + timer->mode = mode; + } + + return err; +} + +static void bcm2835_timer_stop(struct rt_clock_timer_device *timer) +{ + RT_UNUSED(timer); +} + +static rt_uint32_t bcm2835_timer_count_get(struct rt_clock_timer_device *timer) +{ + struct bcm2835_timer_device *timer_dev = raw_to_bcm2835_timer(timer); + + return HWREG32(timer_dev->timer->base + REG_COUNTER_LO); +} + +static rt_err_t bcm2835_timer_ctrl(struct rt_clock_timer_device *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct bcm2835_timer_device *timer_dev = raw_to_bcm2835_timer(timer); + + switch (cmd) + { + case CLOCK_TIMER_CTRL_FREQ_SET: + err = -RT_ENOSYS; + break; + + case CLOCK_TIMER_CTRL_STOP: + bcm2835_timer_stop(timer); + break; + + case CLOCK_TIMER_CTRL_INFO_GET: + if (args) + { + rt_memcpy(args, &timer_dev->timer->info, sizeof(timer_dev->timer->info)); + } + else + { + err = -RT_EINVAL; + } + break; + + case CLOCK_TIMER_CTRL_MODE_SET: + err = bcm2835_timer_start(timer, timer->cycles, (rt_clock_timer_mode_t)(rt_ubase_t)args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_clock_timer_ops bcm2835_timer_ops = +{ + .init = bcm2835_timer_init, + .start = bcm2835_timer_start, + .stop = bcm2835_timer_stop, + .count_get = bcm2835_timer_count_get, + .control = bcm2835_timer_ctrl, +}; + +static void bcm2835_timer_isr(int irqno, void *param) +{ + struct bcm2835_timer_device *timer_dev = param; + struct bcm2835_timer *timer = timer_dev->timer; + + RT_UNUSED(irqno); + + if (HWREG32(timer->base + REG_CONTROL) & RT_BIT(timer_dev->id)) + { + /* ACK */ + HWREG32(timer->base + REG_CONTROL) = RT_BIT(timer_dev->id); + + rt_clock_timer_isr(&timer_dev->parent); + } +} + +static rt_err_t bcm2835_timer_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_uint32_t freq; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct bcm2835_timer *timer = rt_calloc(1, sizeof(*timer)); + + if (!timer) + { + return -RT_ENOMEM; + } + + timer->base = rt_dm_dev_iomap(dev, 0); + + if (!timer->base) + { + err = -RT_EIO; + + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "clock-frequency", &freq)) + { + err = -RT_EIO; + goto _fail; + } + + timer->info.maxfreq = freq; + timer->info.minfreq = freq; + timer->info.maxcnt = 0xffffffff; + timer->info.cntmode = CLOCK_TIMER_CNTMODE_UP; + + for (int i = 0; i < RT_ARRAY_SIZE(timer->device); ++i) + { + struct bcm2835_timer_device *timer_dev = &timer->device[i]; + + if ((timer_dev->irq = rt_dm_dev_get_irq(dev, i)) < 0) + { + continue; + } + + timer_dev->id = i; + timer_dev->compare = timer->base + REG_COMPARE(i); + timer_dev->timer = timer; + + timer_dev->parent.ops = &bcm2835_timer_ops; + timer_dev->parent.info = &timer->info; + timer_dev->parent.freq = freq; + + rt_dm_dev_set_name_auto(&timer_dev->parent.parent, "timer"); + dev_name = rt_dm_dev_get_name(&timer_dev->parent.parent); + + rt_clock_timer_register(&timer_dev->parent, dev_name, RT_NULL); + rt_pic_attach_irq(timer_dev->irq, bcm2835_timer_isr, timer_dev, dev_name, RT_IRQ_F_NONE); + rt_pic_irq_unmask(timer_dev->irq); + } + + dev->user_data = timer; + + return RT_EOK; + +_fail: + if (timer->base) + { + rt_iounmap(timer->base); + } + rt_free(timer); + + return err; +} + +static rt_err_t bcm2835_timer_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_timer *timer = pdev->parent.user_data; + + for (int i = 0; i < RT_ARRAY_SIZE(timer->device); ++i) + { + struct bcm2835_timer_device *timer_dev = &timer->device[i]; + + if (timer_dev->irq < 0) + { + continue; + } + + bcm2835_timer_stop(&timer_dev->parent); + + rt_pic_irq_mask(timer_dev->irq); + rt_pic_detach_irq(timer_dev->irq, timer_dev); + + rt_device_unregister(&timer_dev->parent.parent); + } + + rt_iounmap(timer->base); + rt_free(timer); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_timer_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-system-timer", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_timer_driver = +{ + .name = "clock_timer-bcm2835", + .ids = bcm2835_timer_ofw_ids, + + .probe = bcm2835_timer_probe, + .remove = bcm2835_timer_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_timer_driver); diff --git a/bsp/raspberry-pi/dm/dma/Kconfig b/bsp/raspberry-pi/dm/dma/Kconfig new file mode 100755 index 0000000000..ad1f7f595e --- /dev/null +++ b/bsp/raspberry-pi/dm/dma/Kconfig @@ -0,0 +1,3 @@ +config RT_DMA_BCM2835 + bool "BCM2835 DMA" + default n diff --git a/bsp/raspberry-pi/dm/dma/SConscript b/bsp/raspberry-pi/dm/dma/SConscript new file mode 100755 index 0000000000..f6dfdc5466 --- /dev/null +++ b/bsp/raspberry-pi/dm/dma/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_DMA_BCM2835']): + src += ['dma-bcm2835.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/dma/dma-bcm2835.c b/bsp/raspberry-pi/dm/dma/dma-bcm2835.c new file mode 100755 index 0000000000..b62adb926d --- /dev/null +++ b/bsp/raspberry-pi/dm/dma/dma-bcm2835.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "dma.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#define BCM2835_DMA_CS 0x00 +#define BCM2835_DMA_ADDR 0x04 +#define BCM2835_DMA_TI 0x08 +#define BCM2835_DMA_SOURCE_AD 0x0c +#define BCM2835_DMA_DEST_AD 0x10 +#define BCM2835_DMA_LEN 0x14 +#define BCM2835_DMA_STRIDE 0x18 +#define BCM2835_DMA_NEXTCB 0x1c +#define BCM2835_DMA_DEBUG 0x20 + +/* DMA CS Control and Status bits */ +#define BCM2835_DMA_ACTIVE RT_BIT(0) /* Activate the DMA */ +#define BCM2835_DMA_END RT_BIT(1) /* Current CB has ended */ +#define BCM2835_DMA_INT RT_BIT(2) /* Interrupt status */ +#define BCM2835_DMA_DREQ RT_BIT(3) /* DREQ state */ +#define BCM2835_DMA_ISPAUSED RT_BIT(4) /* Pause requested or not active */ +#define BCM2835_DMA_ISHELD RT_BIT(5) /* Is held by DREQ flow control */ +#define BCM2835_DMA_WAITING_FOR_WRITES RT_BIT(6) /* Waiting for last AXI-write to ack */ +#define BCM2835_DMA_ERR RT_BIT(8) +#define BCM2835_DMA_PRIORITY(x) ((x & 15) << 16) /* AXI priority */ +#define BCM2835_DMA_PANIC_PRIORITY(x) ((x & 15) << 20) /* Panic priority */ +#define BCM2835_DMA_WAIT_FOR_WRITES RT_BIT(28) +#define BCM2835_DMA_DIS_DEBUG RT_BIT(29) /* Disable debug pause signal */ +#define BCM2835_DMA_ABORT RT_BIT(30) /* Stop current CB, go to next, WO */ +#define BCM2835_DMA_RESET RT_BIT(31) /* WO, self clearing */ + +#define BCM2835_DMA_DEBUG_LITE RT_BIT(28) + +#define BCM2835_DMA_INT_EN RT_BIT(0) +#define BCM2835_DMA_TDMODE RT_BIT(1) /* 2D-Mode */ +#define BCM2835_DMA_WAIT_RESP RT_BIT(3) /* wait for AXI-write to be acked */ +#define BCM2835_DMA_D_INC RT_BIT(4) +#define BCM2835_DMA_D_WIDTH RT_BIT(5) /* 128bit writes if set */ +#define BCM2835_DMA_D_DREQ RT_BIT(6) /* Enable DREQ for destination */ +#define BCM2835_DMA_D_IGNORE RT_BIT(7) /* Ignore destination writes */ +#define BCM2835_DMA_S_INC RT_BIT(8) +#define BCM2835_DMA_S_WIDTH RT_BIT(9) /* 128bit writes if set */ +#define BCM2835_DMA_S_DREQ RT_BIT(10) /* Enable SREQ for source */ +#define BCM2835_DMA_S_IGNORE RT_BIT(11) /* Ignore source reads - read 0 */ +#define BCM2835_DMA_BURST_LENGTH(x) (((x) & 15) << 12) +#define BCM2835_DMA_GET_BURST_LENGTH(x) (((x) >> 12) & 15) +#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | BCM2835_DMA_PANIC_PRIORITY(15) | \ + BCM2835_DMA_WAIT_FOR_WRITES | BCM2835_DMA_DIS_DEBUG)) + +#define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */ +#define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* Add DMA-wait cycles */ +#define BCM2835_DMA_NO_WIDE_BURSTS RT_BIT(26) /* No 2 beat write bursts */ + +/* A fake bit to request that the driver doesn't set the WAIT_RESP bit. */ +#define BCM2835_DMA_NO_WAIT_RESP RT_BIT(27) +#define WAIT_RESP(x) ((x & BCM2835_DMA_NO_WAIT_RESP) ? 0 : BCM2835_DMA_WAIT_RESP) + +/* A fake bit to request that the driver requires wide reads */ +#define BCM2835_DMA_WIDE_SOURCE RT_BIT(24) +#define WIDE_SOURCE(x) ((x & BCM2835_DMA_WIDE_SOURCE) ? BCM2835_DMA_S_WIDTH : 0) + +/* A fake bit to request that the driver requires wide writes */ +#define BCM2835_DMA_WIDE_DEST RT_BIT(25) +#define WIDE_DEST(x) ((x & BCM2835_DMA_WIDE_DEST) ? BCM2835_DMA_D_WIDTH : 0) + +/* A fake bit to request that the driver requires multi-beat burst */ +#define BCM2835_DMA_BURST RT_BIT(30) +#define BURST_LENGTH(x) ((x & BCM2835_DMA_BURST) ? BCM2835_DMA_BURST_LENGTH(3) : 0) + +/* Valid only for channels 0 - 14, 15 has its own base address */ +#define BCM2835_DMA_CHAN_SIZE 0x100 +#define BCM2835_DMA_CHAN(n) ((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */ +#define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n)) + +/* 40-bit DMA support */ +#define BCM2711_DMA40_CS 0x00 +#define BCM2711_DMA40_CB 0x04 +#define BCM2711_DMA40_DEBUG 0x0c +#define BCM2711_DMA40_TI 0x10 +#define BCM2711_DMA40_SRC 0x14 +#define BCM2711_DMA40_SRCI 0x18 +#define BCM2711_DMA40_DEST 0x1c +#define BCM2711_DMA40_DESTI 0x20 +#define BCM2711_DMA40_LEN 0x24 +#define BCM2711_DMA40_NEXT_CB 0x28 +#define BCM2711_DMA40_DEBUG2 0x2c + +#define BCM2711_DMA40_DEBUG_RESET RT_BIT(23) + +#define BCM2711_DMA40_ACTIVE RT_BIT(0) +#define BCM2711_DMA40_END RT_BIT(1) +#define BCM2711_DMA40_INT RT_BIT(2) +#define BCM2711_DMA40_DREQ RT_BIT(3) /* DREQ state */ +#define BCM2711_DMA40_RD_PAUSED RT_BIT(4) /* Reading is paused */ +#define BCM2711_DMA40_WR_PAUSED RT_BIT(5) /* Writing is paused */ +#define BCM2711_DMA40_DREQ_PAUSED RT_BIT(6) /* Is paused by DREQ flow control */ +#define BCM2711_DMA40_WAITING_FOR_WRITES RT_BIT(7) /* Waiting for last write */ +#define BCM2711_DMA40_PROT (RT_BIT(8) | RT_BIT(9)) +#define BCM2711_DMA40_ERR RT_BIT(10) +#define BCM2711_DMA40_QOS(x) (((x) & 0x1f) << 16) +#define BCM2711_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20) +#define BCM2711_DMA40_TRANSACTIONS RT_BIT(25) +#define BCM2711_DMA40_WAIT_FOR_WRITES RT_BIT(28) +#define BCM2711_DMA40_DISDEBUG RT_BIT(29) +#define BCM2711_DMA40_ABORT RT_BIT(30) +#define BCM2711_DMA40_HALT RT_BIT(31) + +#define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | BCM2711_DMA40_PANIC_QOS(15) | \ + BCM2711_DMA40_WAIT_FOR_WRITES | BCM2711_DMA40_DISDEBUG)) + +#define BCM2711_DMA40_INTEN RT_BIT(0) +#define BCM2711_DMA40_TDMODE RT_BIT(1) /* 2D-Mode */ +#define BCM2711_DMA40_WAIT_RESP RT_BIT(2) /* Wait for AXI write to be acked */ +#define BCM2711_DMA40_WAIT_RD_RESP RT_BIT(3) /* Wait for AXI read to complete */ +#define BCM2711_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */ +#define BCM2711_DMA40_S_DREQ RT_BIT(14) /* Enable SREQ for source */ +#define BCM2711_DMA40_D_DREQ RT_BIT(15) /* Enable DREQ for destination */ +#define BCM2711_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* Add DMA read-wait cycles */ +#define BCM2711_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* Add DMA write-wait cycles */ + +#define BCM2711_DMA40_BURST_LEN(x) (((x) & 15) << 8) +#define BCM2711_DMA40_INC RT_BIT(12) +#define BCM2711_DMA40_SIZE_32 (0 << 13) +#define BCM2711_DMA40_SIZE_64 (1 << 13) +#define BCM2711_DMA40_SIZE_128 (2 << 13) +#define BCM2711_DMA40_SIZE_256 (3 << 13) +#define BCM2711_DMA40_IGNORE RT_BIT(15) +#define BCM2711_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */ + +#define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 +#define BCM2835_DMA_CHAN_NAME_SIZE 8 +#define BCM2835_DMA_BULK_MASK RT_BIT(0) +#define BCM2711_DMA_MEMCPY_CHAN 14 + +#define MAX_DMA_LEN SIZE_GB +#define MAX_LITE_DMA_LEN (64 * SIZE_KB - 4) + +struct bcm2835_dma_control_block +{ + rt_uint32_t info; + rt_uint32_t src; + rt_uint32_t dst; + rt_uint32_t length; + rt_uint32_t stride; + rt_uint32_t next; + rt_uint32_t padding[2]; +}; + +struct bcm2711_dma40_control_block +{ + rt_uint32_t ti; + rt_uint32_t src; + rt_uint32_t srci; + rt_uint32_t dst; + rt_uint32_t dsti; + rt_uint32_t len; + rt_uint32_t next_cb; + rt_uint32_t rsvd; +}; + +struct bcm2835_dma_soc_data +{ + rt_uint32_t chan_40bit_mask; + rt_uint64_t dma_mask; +}; + +struct bcm2835_chan +{ + struct rt_dma_chan parent; + + int irq; + void *base; + + rt_size_t size; + rt_uint32_t dreq; + rt_bool_t enabled; + + void *control_block; + rt_ubase_t control_block_dma; +}; + +struct bcm2835_dma +{ + struct rt_dma_controller parent; + const struct bcm2835_dma_soc_data *data; + + void *base; + rt_uint32_t num_chans; + struct bcm2835_chan *chans; + + rt_size_t max_frame_length; + + rt_bool_t is_2712; + rt_bool_t is_40bit; +}; +#define raw_to_bcm2835_dma(raw) rt_container_of(raw, struct bcm2835_dma, parent) +#define raw_to_bcm2835_dma_chan(raw) rt_container_of(raw, struct bcm2835_chan, parent) + +rt_inline rt_ubase_t to_40bit_cbaddr(rt_ubase_t addr) +{ + return addr >> 5; +} + +rt_inline rt_uint32_t to_bcm2711_ti(rt_uint32_t info) +{ + return ((info & BCM2835_DMA_INT_EN) ? BCM2711_DMA40_INTEN : 0) | + ((info & BCM2835_DMA_WAIT_RESP) ? BCM2711_DMA40_WAIT_RESP : 0) | + ((info & BCM2835_DMA_S_DREQ) ? + (BCM2711_DMA40_S_DREQ | BCM2711_DMA40_WAIT_RD_RESP) : 0) | + ((info & BCM2835_DMA_D_DREQ) ? BCM2711_DMA40_D_DREQ : 0) | + BCM2711_DMA40_PER_MAP((info >> 16) & 0x1f); +} + +rt_inline rt_uint32_t to_bcm2711_srci(rt_uint32_t info) +{ + return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0) | + ((info & BCM2835_DMA_S_WIDTH) ? BCM2711_DMA40_SIZE_128 : 0) | + BCM2711_DMA40_BURST_LEN(BCM2835_DMA_GET_BURST_LENGTH(info)); +} + +rt_inline rt_uint32_t to_bcm2711_dsti(rt_uint32_t info) +{ + return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0) | + ((info & BCM2835_DMA_D_WIDTH) ? BCM2711_DMA40_SIZE_128 : 0) | + BCM2711_DMA40_BURST_LEN(BCM2835_DMA_GET_BURST_LENGTH(info)); +} + +rt_inline rt_size_t bcm2835_dma_frames_for_length(rt_size_t len, rt_size_t max_len) +{ + return RT_DIV_ROUND_UP(len, max_len); +} + +static rt_err_t bcm2835_dma_fill_prep(struct bcm2835_chan *chan, enum rt_dma_transfer_direction dir, + rt_bool_t cyclic, rt_uint32_t info, rt_uint32_t finalextrainfo, rt_size_t frames, + rt_ubase_t src, rt_ubase_t dst, rt_size_t buf_len, rt_size_t period_len) +{ + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->parent.ctrl); + + if (frames > 1) + { + /* + * Should create dma buffer and fill the CB list if enable, + * This demand is rare or even non-existent on RT-thread. + */ + return -RT_ENOSYS; + } + info |= finalextrainfo; + + if (dma->is_40bit) + { + struct bcm2711_dma40_control_block *cb = chan->control_block; + + cb->ti = to_bcm2711_ti(info); + cb->src = rt_lower_32_bits(src); + cb->srci = rt_upper_32_bits(src) | to_bcm2711_srci(info); + cb->dst = rt_lower_32_bits(dst); + cb->dsti = rt_upper_32_bits(dst) | to_bcm2711_dsti(info); + cb->len = buf_len; + cb->next_cb = 0; + } + else + { + struct bcm2835_dma_control_block *cb = chan->control_block; + + cb->info = info; + cb->src = src; + cb->dst = dst; + cb->length = buf_len; + + if (dma->is_2712) + { + cb->stride = (rt_upper_32_bits(dst) << 8) | rt_upper_32_bits(src); + } + else + { + cb->stride = 0; + } + + cb->next = 0; + } + + return RT_EOK; +} + +static struct rt_dma_chan *bcm2835_dma_request_chan(struct rt_dma_controller *ctrl, + struct rt_device *slave, void *fw_data) +{ + rt_size_t size; + struct bcm2835_chan *chan = RT_NULL; + struct bcm2835_dma *dma = raw_to_bcm2835_dma(ctrl); + struct rt_ofw_cell_args *args = fw_data; + + for (int i = 0; i < dma->num_chans; ++i) + { + if (!dma->chans[i].enabled) + { + chan = &dma->chans[i]; + break; + } + } + + if (!chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + if (dma->is_40bit) + { + size = sizeof(struct bcm2711_dma40_control_block); + } + else + { + size = sizeof(struct bcm2835_dma_control_block); + } + + chan->control_block = rt_dma_alloc_coherent(slave, size, &chan->control_block_dma); + + if (!chan->control_block) + { + return rt_err_ptr(-RT_ENOMEM); + } + + chan->dreq = args ? args->args[0] : 0; + chan->enabled = RT_TRUE; + + return &chan->parent; +} + +static rt_err_t bcm2835_dma_release_chan(struct rt_dma_chan *chan) +{ + rt_size_t size; + struct bcm2835_chan *bcm_chan = rt_container_of(chan, struct bcm2835_chan, parent); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + bcm_chan->enabled = RT_FALSE; + + if (dma->is_40bit) + { + size = sizeof(struct bcm2711_dma40_control_block); + } + else + { + size = sizeof(struct bcm2835_dma_control_block); + } + + rt_dma_free_coherent(chan->slave, size, + bcm_chan->control_block, bcm_chan->control_block_dma); + + return RT_EOK; +} + +static rt_err_t bcm2835_dma_start(struct rt_dma_chan *chan) +{ + void *base; + rt_ubase_t cb_dma; + struct bcm2835_chan *bcm_chan = raw_to_bcm2835_dma_chan(chan); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + base = bcm_chan->base; + cb_dma = bcm_chan->control_block_dma; + + if (dma->is_40bit) + { + HWREG32(base + BCM2711_DMA40_CB) = to_40bit_cbaddr(cb_dma); + HWREG32(base + BCM2711_DMA40_CS) = + BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(bcm_chan->dreq); + } + else + { + HWREG32(base + BCM2835_DMA_CS) = RT_BIT(31); + HWREG32(base + BCM2835_DMA_ADDR) = dma->is_2712 ? to_40bit_cbaddr(cb_dma) : cb_dma; + HWREG32(base + BCM2835_DMA_CS) = BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(bcm_chan->dreq); + } + + return RT_EOK; +} + +static rt_err_t bcm2835_dma_stop(struct rt_dma_chan *chan) +{ + void *base; + rt_uint32_t timeout = 100; + struct bcm2835_chan *bcm_chan = raw_to_bcm2835_dma_chan(chan); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + base = bcm_chan->base; + + if (dma->is_40bit) + { + if (!HWREG32(base + BCM2711_DMA40_CB)) + { + return RT_EOK; + } + + /* Pause the current DMA */ + HWREG32(base + BCM2711_DMA40_CS) = HWREG32(base + BCM2711_DMA40_CS) & ~BCM2711_DMA40_ACTIVE; + + /* wait for outstanding transactions to complete */ + while ((HWREG32(base + BCM2711_DMA40_CS) & BCM2711_DMA40_TRANSACTIONS) && --timeout) + { + rt_hw_cpu_relax(); + } + + /* Peripheral might be stuck and fail to complete */ + if (!timeout) + { + LOG_E("Failed to complete pause on dma[%d] CS:%08x", bcm_chan - dma->chans, + HWREG32(base + BCM2711_DMA40_CS)); + } + + /* Set CS back to default state */ + HWREG32(base + BCM2711_DMA40_CS) = BCM2711_DMA40_PROT; + + /* Reset the DMA */ + HWREG32(base + BCM2711_DMA40_DEBUG) |= BCM2711_DMA40_DEBUG_RESET; + } + else + { + if (!HWREG32(base + BCM2835_DMA_ADDR)) + { + return RT_EOK; + } + + /* We need to clear the next DMA block pending */ + HWREG32(base + BCM2835_DMA_NEXTCB) = 0; + + /* Abort the DMA, which needs to be enabled to complete */ + HWREG32(base + BCM2835_DMA_CS) = + HWREG32(base + BCM2835_DMA_CS) | BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE; + + /* Wait for DMA to be aborted */ + while ((HWREG32(base + BCM2835_DMA_CS) & BCM2835_DMA_ABORT) && --timeout) + { + rt_hw_cpu_relax(); + } + + /* Write 0 to the active bit - Pause the DMA */ + HWREG32(base + BCM2835_DMA_CS) = + HWREG32(base + BCM2835_DMA_CS) & ~BCM2835_DMA_ACTIVE; + + if (!timeout && !(HWREG32(base + BCM2835_DMA_TI) & + (BCM2835_DMA_S_DREQ | BCM2835_DMA_D_DREQ))) + { + LOG_E("Failed to complete pause on dma[%d] CS:%08x", bcm_chan - dma->chans, + HWREG32(base + BCM2835_DMA_CS)); + } + + /* Set CS back to default state and reset the DMA */ + HWREG32(base + BCM2835_DMA_CS) = BCM2835_DMA_RESET; + } + + return RT_EOK; +} + +static rt_err_t bcm2835_dma_config(struct rt_dma_chan *chan, + struct rt_dma_slave_config *conf) +{ + return RT_EOK; +} + +static rt_err_t bcm2835_dma_prep_memcpy(struct rt_dma_chan *chan, + rt_ubase_t dma_addr_src, rt_ubase_t dma_addr_dst, rt_size_t len) +{ + rt_size_t frames; + rt_uint32_t info, extra; + struct bcm2835_chan *bcm_chan = raw_to_bcm2835_dma_chan(chan); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC | + WAIT_RESP(bcm_chan->dreq) | WIDE_SOURCE(bcm_chan->dreq) | + WIDE_DEST(bcm_chan->dreq) | BURST_LENGTH(bcm_chan->dreq); + extra = BCM2835_DMA_INT_EN; + frames = bcm2835_dma_frames_for_length(len, dma->max_frame_length); + + bcm_chan->size = len; + + return bcm2835_dma_fill_prep(bcm_chan, RT_DMA_MEM_TO_MEM, RT_FALSE, + info, extra, frames, dma_addr_src, dma_addr_dst, len, 0); +} + +static rt_err_t bcm2835_dma_prep_cyclic(struct rt_dma_chan *chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, rt_size_t period_len, + enum rt_dma_transfer_direction dir) +{ + rt_size_t frames; + rt_ubase_t src, dst; + rt_uint32_t info, extra; + struct bcm2835_chan *bcm_chan = raw_to_bcm2835_dma_chan(chan); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + info = WAIT_RESP(bcm_chan->dreq) | WIDE_SOURCE(bcm_chan->dreq) | + WIDE_DEST(bcm_chan->dreq) | BURST_LENGTH(bcm_chan->dreq); + extra = 0; + + if (bcm_chan->dreq) + { + info |= BCM2835_DMA_PER_MAP(bcm_chan->dreq); + } + + if (dir == RT_DMA_DEV_TO_MEM) + { + if (chan->conf.src_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + return -RT_EINVAL; + } + + src = chan->conf.src_addr; + dst = dma_buf_addr; + info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; + } + else + { + if (chan->conf.dst_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + return -RT_EINVAL; + } + + dst = chan->conf.dst_addr; + src = dma_buf_addr; + info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; + } + + frames = RT_DIV_ROUND_UP(buf_len, period_len) * + bcm2835_dma_frames_for_length(period_len, dma->max_frame_length); + + bcm_chan->size = buf_len; + + return bcm2835_dma_fill_prep(bcm_chan, dir, RT_TRUE, + info, extra, frames, src, dst, buf_len, period_len); +} + +static rt_err_t bcm2835_dma_prep_single(struct rt_dma_chan *chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, + enum rt_dma_transfer_direction dir) +{ + rt_size_t frames; + rt_ubase_t src, dst; + rt_uint32_t info, extra; + struct bcm2835_chan *bcm_chan = raw_to_bcm2835_dma_chan(chan); + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->ctrl); + + info = WAIT_RESP(bcm_chan->dreq) | WIDE_SOURCE(bcm_chan->dreq) | + WIDE_DEST(bcm_chan->dreq) | BURST_LENGTH(bcm_chan->dreq); + extra = BCM2835_DMA_INT_EN; + + if (bcm_chan->dreq) + { + info |= BCM2835_DMA_PER_MAP(bcm_chan->dreq); + } + + if (dir == RT_DMA_DEV_TO_MEM) + { + if (chan->conf.src_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + return -RT_EINVAL; + } + + dst = dma_buf_addr; + src = chan->conf.src_addr; + info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; + } + else + { + if (chan->conf.dst_addr_width != RT_DMA_SLAVE_BUSWIDTH_4_BYTES) + { + return -RT_EINVAL; + } + + dst = chan->conf.dst_addr; + src = dma_buf_addr; + info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; + } + + frames = bcm2835_dma_frames_for_length(buf_len, dma->max_frame_length); + bcm_chan->size = buf_len; + + return bcm2835_dma_fill_prep(bcm_chan, dir, RT_FALSE, + info, extra, frames, src, dst, buf_len, 0); +} + +static const struct rt_dma_controller_ops bcm2835_dma_ops = +{ + .request_chan = bcm2835_dma_request_chan, + .release_chan = bcm2835_dma_release_chan, + .start = bcm2835_dma_start, + .stop = bcm2835_dma_stop, + .config = bcm2835_dma_config, + .prep_memcpy = bcm2835_dma_prep_memcpy, + .prep_cyclic = bcm2835_dma_prep_cyclic, + .prep_single = bcm2835_dma_prep_single, +}; + +static void bcm2835_dma_isr(int irq, void *param) +{ + struct bcm2835_chan *chan = param; + struct bcm2835_dma *dma = raw_to_bcm2835_dma(chan->parent.ctrl); + + /* Check for share IRQ */ + if (!(HWREG32(chan->base + BCM2835_DMA_CS) & BCM2835_DMA_INT)) + { + return; + } + + if (dma->is_40bit) + { + HWREG32(chan->base + BCM2711_DMA40_CS) = + BCM2835_DMA_INT | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | + BCM2711_DMA40_CS_FLAGS(chan->dreq); + } + else + { + HWREG32(chan->base + BCM2835_DMA_CS) = + BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | + BCM2835_DMA_CS_FLAGS(chan->dreq); + } + + rt_dma_chan_done(&chan->parent, chan->size); +} + +static rt_err_t bcm2835_dma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t addr, size; + rt_uint32_t channel_mask = ~0U; + struct rt_device *dev = &pdev->parent; + struct bcm2835_dma *dma = rt_calloc(1, sizeof(*dma)); + + if (!dma) + { + return -RT_ENOMEM; + } + dma->data = pdev->id->data; + + if (dma->data->dma_mask == RT_DMA_ADDR_MASK(40)) + { + dma->is_2712 = RT_TRUE; + } + + rt_ofw_prop_read_u32(dev->ofw_node, "brcm,dma-channel-mask", &channel_mask); + dma->is_40bit = !!(dma->data->chan_40bit_mask & channel_mask); + + if ((err = rt_dm_dev_get_address(dev, 0, &addr, &size))) + { + goto _fail; + } + + if (!(dma->base = rt_ioremap((void *)addr, size))) + { + err = -RT_EIO; + goto _fail; + } + + if (HWREG32(dma->base + BCM2835_DMA_DEBUG) & BCM2835_DMA_DEBUG_LITE) + { + dma->max_frame_length = MAX_LITE_DMA_LEN; + } + else + { + dma->max_frame_length = MAX_DMA_LEN; + } + + dma->num_chans = size / BCM2835_DMA_CHAN_SIZE; + + dma->chans = rt_calloc(dma->num_chans, sizeof(dma->chans[0])); + + if (!dma->chans) + { + err = -RT_ENOMEM; + goto _fail; + } + + for (int i = 0; i < dma->num_chans; ++i) + { + struct bcm2835_chan *chan = &dma->chans[i]; + + chan->irq = rt_dm_dev_get_irq(dev, i); + + if (chan->irq < 0) + { + err = chan->irq; + goto _fail; + } + } + + dma->parent.dev = dev; + dma->parent.ops = &bcm2835_dma_ops; + rt_dma_controller_add_direction(&dma->parent, RT_DMA_MEM_TO_MEM); + rt_dma_controller_add_direction(&dma->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_add_direction(&dma->parent, RT_DMA_DEV_TO_MEM); + rt_dma_controller_set_addr_mask(&dma->parent, dma->data->dma_mask); + + if ((err = rt_dma_controller_register(&dma->parent))) + { + goto _fail; + } + + for (int i = 0; i < dma->num_chans; ++i) + { + char isr_name[RT_NAME_MAX]; + struct bcm2835_chan *chan = &dma->chans[i]; + + chan->base = dma->base + i * BCM2835_DMA_CHAN_SIZE; + + rt_sprintf(isr_name, "dma-%u", i); + + rt_hw_interrupt_install(chan->irq, bcm2835_dma_isr, chan, isr_name); + rt_hw_interrupt_umask(chan->irq); + } + + dev->user_data = dma; + + return err; + +_fail: + if (dma->chans) + { + rt_free(dma->chans); + } + + if (dma->base) + { + rt_iounmap(dma->base); + } + + rt_free(dma); + + return err; +} + +static rt_err_t bcm2835_dma_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_dma *dma = pdev->parent.user_data; + + rt_dma_controller_unregister(&dma->parent); + + for (int i = 0; i < dma->num_chans; ++i) + { + struct bcm2835_chan *chan = &dma->chans[i]; + + rt_hw_interrupt_mask(chan->irq); + rt_pic_detach_irq(chan->irq, chan); + } + + rt_free(dma->chans); + rt_iounmap(dma->base); + + rt_free(dma); + + return RT_EOK; +} + +static const struct bcm2835_dma_soc_data bcm2835_dma_data = +{ + .chan_40bit_mask = 0, + .dma_mask = RT_DMA_ADDR_MASK(32), +}; + +static const struct bcm2835_dma_soc_data bcm2711_dma_data = +{ + .chan_40bit_mask = RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14), + .dma_mask = RT_DMA_ADDR_MASK(36), +}; + +static const struct bcm2835_dma_soc_data bcm2712_dma_data = +{ + .chan_40bit_mask = RT_BIT(6) | RT_BIT(7) | RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11), + .dma_mask = RT_DMA_ADDR_MASK(40), +}; + +static const struct rt_ofw_node_id bcm2835_dma_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_data }, + { .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_data }, + { .compatible = "brcm,bcm2712-dma", .data = &bcm2712_dma_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_dma_driver = +{ + .name = "dma-bcm2835", + .ids = bcm2835_dma_ofw_ids, + + .probe = bcm2835_dma_probe, + .remove = bcm2835_dma_remove, +}; + +static int bcm2835_dma_drv_register(void) +{ + rt_platform_driver_register(&bcm2835_dma_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_dma_drv_register); diff --git a/bsp/raspberry-pi/dm/dts/bcm2711-rpi-4-b.dts b/bsp/raspberry-pi/dm/dts/bcm2711-rpi-4-b.dts new file mode 100755 index 0000000000..68d9bfd1d5 --- /dev/null +++ b/bsp/raspberry-pi/dm/dts/bcm2711-rpi-4-b.dts @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +/dts-v1/; +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * NOTE: Just for QEMU, not the really board! + */ + +/* + * firmware-provided startup stubs live here, where the secondary CPUs are + * spinning. + */ +/memreserve/ 0x00000000 0x00001000; + +/ { + compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; + model = "Raspberry Pi 4 Model B Rev 1.2"; + #address-cells = <2>; + #size-cells = <1>; + interrupt-parent = <&gicv2>; + + aliases { + serial0 = "/soc/serial@7e215040"; + serial1 = "/soc/serial@7e201000"; + mmc0 = "/soc/mmcnr@7e300000"; + spi0 = "/soc/spi@7e204000"; + i2c0 = "/soc/i2c@7e205000"; + i2c1 = "/soc/i2c@7e804000"; + i2c2 = "/soc/i2c@7e805000"; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + /* For ARM 32-bit */ + enable-method = "brcm,bcm2836-smp"; + + /* + * Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/100095/0003 + * /Level-1-Memory-System/About-the-L1-memory-system?lang=en + * Source for d/i-cache-size + * https://www.raspberrypi.com/documentation/computers + * /processors.html#bcm2711 + */ + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000d8>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <1>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000e0>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set + next-level-cache = <&l2>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <2>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000e8>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set + next-level-cache = <&l2>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <3>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000f0>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set + next-level-cache = <&l2>; + }; + + /* + * Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/100095/0003 + * /Level-2-Memory-System/About-the-L2-memory-system?lang=en + * Source for d/i-cache-size + * https://www.raspberrypi.com/documentation/computers + * /processors.html#bcm2711 + */ + l2: l2-cache0 { + compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; // 1MiB(size)/64(line-size)=16384ways/16-way set + cache-level = <2>; + }; + }; + + arm-pmu { + compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3", "arm,cortex-a7-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + /* This only applies to the ARMv7 stub */ + arm,cpu-registers-not-fw-configured; + }; + + thermal-zones { + + cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <1000>; + thermal-sensors = <&thermal>; + coefficients = <(-487) 410040>; + + trips { + cpu-crit { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + /* + * Defined ranges: + * Common BCM283x peripherals + * BCM2711-specific peripherals + * ARM-local peripherals + */ + ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, + <0x7c000000 0x0 0xfc000000 0x02000000>, + <0x40000000 0x0 0xff800000 0x00800000>; + /* Emulate a contiguous 30-bit address range for DMA */ + dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>, + <0x7c000000 0x0 0xfc000000 0x03800000>; + + system_timer: timer@7e003000 { + compatible = "brcm,bcm2835-system-timer"; + reg = <0x7e003000 0x1000>; + interrupts = , + , + , + ; + /* + * This could be a reference to BCM2835_CLOCK_TIMER, + * but we don't have the driver using the common clock + * support yet. + */ + clock-frequency = <1000000>; + }; + + dsi0: dsi@7e209000 { + compatible = "brcm,bcm2711-dsi0","brcm,bcm2835-dsi0"; + reg = <0x7e209000 0x78>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + clocks = <&clocks BCM2835_PLLA_DSI0>, + <&clocks BCM2835_CLOCK_DSI0E>, + <&clocks BCM2835_CLOCK_DSI0P>; + clock-names = "phy", "escape", "pixel"; + clock-output-names = "dsi0_byte", "dsi0_ddr2", "dsi0_ddr"; + status = "disabled"; + }; + + dsi1: dsi@7e700000 { + compatible = "brcm,bcm2711-dsi1","brcm,bcm2835-dsi1"; + reg = <0x7e700000 0x8c>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + clocks = <&clocks BCM2835_PLLD_DSI1>, + <&clocks BCM2835_CLOCK_DSI1E>, + <&clocks BCM2835_CLOCK_DSI1P>; + clock-names = "phy", "escape", "pixel"; + clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr"; + status = "disabled"; + }; + + clocks: cprman@7e101000 { + compatible = "brcm,bcm2835-cprman"; + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + + /* + * CPRMAN derives almost everything from the + * platform's oscillator. However, the DSI + * pixel clocks come from the DSI analog PHY. + */ + clocks = <&clk_osc>, + <&dsi0 0>,<&dsi0 1>,<&dsi0 2>, + <&dsi1 0>,<&dsi1 1>,<&dsi1 2>; + firmware = <&firmware>; + }; + + mailbox: mailbox@7e00b880 { + compatible = "brcm,bcm2835-mbox"; + reg = <0x7e00b880 0x40>; + interrupts = ; + #mbox-cells = <0>; + }; + + gpio: gpio@7e200000 { + compatible = "brcm,bcm2711-gpio"; + reg = <0x7e200000 0xb4>; + interrupts = , + ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&gpio 0 0 58>; + pinctrl-names = "default"; + + /* + * Parts taken from rpi_SCH_4b_4p0_reduced.pdf and + * the official GPU firmware DT blob. + * + * Legend: + * "FOO" = GPIO line named "FOO" on the schematic + * "FOO_N" = GPIO line named "FOO" on schematic, active low + */ + gpio-line-names = "ID_SDA", /* 0 */ + "ID_SCL", + "SDA1", + "SCL1", + "GPIO_GCLK", + "GPIO5", /* 5 */ + "GPIO6", + "SPI_CE1_N", + "SPI_CE0_N", + "SPI_MISO", + "SPI_MOSI", /* 10 */ + "SPI_SCLK", + "GPIO12", + "GPIO13", + /* Serial port */ + "TXD1", + "RXD1", /* 15 */ + "GPIO16", + "GPIO17", + "GPIO18", + "GPIO19", + "GPIO20", /* 20 */ + "GPIO21", + "GPIO22", + "GPIO23", + "GPIO24", + "GPIO25", /* 25 */ + "GPIO26", + "GPIO27", + "RGMII_MDIO", + "RGMIO_MDC", + /* Used by BT module */ + "CTS0", /* 30 */ + "RTS0", + "TXD0", + "RXD0", + /* Used by Wifi */ + "SD1_CLK", + "SD1_CMD", /* 35 */ + "SD1_DATA0", + "SD1_DATA1", + "SD1_DATA2", + "SD1_DATA3", + /* Shared with SPI flash */ + "PWM0_MISO", /* 40 */ + "PWM1_MOSI", + "STATUS_LED_G_CLK", + "SPIFLASH_CE_N", + "SDA0", + "SCL0", /* 45 */ + "RGMII_RXCLK", + "RGMII_RXCTL", + "RGMII_RXD0", + "RGMII_RXD1", + "RGMII_RXD2", /* 50 */ + "RGMII_RXD3", + "RGMII_TXCLK", + "RGMII_TXCTL", + "RGMII_TXD0", + "RGMII_TXD1", /* 55 */ + "RGMII_TXD2", + "RGMII_TXD3"; + + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = ; + }; + + spi0_cs_pins: spi0_cs_pins { + brcm,pins = <8 7>; + brcm,function = ; + }; + + i2c0_gpio0: i2c0_gpio0 { + brcm,pins = <0 1>; + brcm,function = ; + }; + + i2c1_gpio2: i2c1_gpio2 { + brcm,pins = <2 3>; + brcm,function = ; + brcm,pull = ; + }; + + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = ; + brcm,pull = , + , + , + , + , + ; + }; + + bt_pins: bt_pins { + brcm,pins = "-"; + brcm,function = <0>; + brcm,pull = ; + }; + + uart0_pins: uart0_pins { + brcm,pins = <32 33>; + brcm,function = ; + brcm,pull = ; + }; + + uart0_gpio14: uart0-gpio14 { + brcm,pins = <14 15>; + brcm,function = ; + }; + + uart1_pins: uart1_pins { + brcm,pins; + brcm,function; + brcm,pull; + }; + }; + + serial@7e201000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x7e201000 0x200>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; + arm,primecell-periphid = <0x241011>; + cts-event-workaround; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins &bt_pins>; + uart-has-rtscts; + skip-init; + }; + + spi@7e204000 { + compatible = "brcm,bcm2835-spi"; + reg = <0x7e204000 0x200>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&dma 6>, <&dma 7>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins &spi0_cs_pins>; + cs-gpios = <&gpio 8 1>, <&gpio 7 1>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x00>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; + }; + + i2c@7e205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x200>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_gpio0>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "st,m41t00", "dallas,ds1338"; + reg = <0x68>; + }; + }; + + i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_gpio2>; + clock-frequency = <100000>; + }; + + i2c@7e805000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e805000 0x1000>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; + + aux: aux@7e215000 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; + reg = <0x7e215000 0x8>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + }; + + serial@7e215040 { + compatible = "brcm,bcm2835-aux-uart"; + reg = <0x7e215040 0x40>; + interrupts = ; + clocks = <&aux BCM2835_AUX_CLOCK_UART>; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + skip-init; + }; + + usb: usb@7e980000 { + compatible = "brcm,bcm2708-usb"; + reg = <0x7e980000 0x10000>, + <0x7e00b200 0x200>; + interrupts = , + ; + interrupt-names = "usb", "soft"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_usb>; + clock-names = "otg"; + phys = <&usbphy>; + phy-names = "usb2-phy"; + power-domains = <&power RPI_POWER_DOMAIN_USB>; + }; + + /* + * This node is the provider for the enable-method for + * bringing up secondary cores. + */ + local_intc: local_intc@40000000 { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + }; + + gicv2: interrupt-controller@40041000 { + interrupt-controller; + #interrupt-cells = <3>; + compatible = "arm,gic-400"; + reg = <0x40041000 0x1000>, + <0x40042000 0x2000>, + <0x40044000 0x2000>, + <0x40046000 0x2000>; + interrupts = ; + }; + + avs_monitor: avs-monitor@7d5d2000 { + compatible = "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd"; + reg = <0x7d5d2000 0xf00>; + + thermal: thermal { + compatible = "brcm,bcm2711-thermal"; + #thermal-sensor-cells = <0>; + }; + }; + + dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xb00>; + interrupts = , + , + , + , + , + , + , + /* DMA lite 7 - 10 */ + , + , + , + ; + interrupt-names = "dma0", + "dma1", + "dma2", + "dma3", + "dma4", + "dma5", + "dma6", + "dma7", + "dma8", + "dma9", + "dma10"; + #dma-cells = <1>; + brcm,dma-channel-mask = <0x07f5>; + }; + + pm: watchdog@7e100000 { + compatible = "brcm,bcm2711-pm", "brcm,bcm2835-pm-wdt"; + #power-domain-cells = <1>; + #reset-cells = <1>; + reg = <0x7e100000 0x114>, + <0x7e00a000 0x24>, + <0x7ec11000 0x20>; + reg-names = "pm", "asb", "rpivid_asb"; + clocks = <&clocks BCM2835_CLOCK_V3D>, + <&clocks BCM2835_CLOCK_PERI_IMAGE>, + <&clocks BCM2835_CLOCK_H264>, + <&clocks BCM2835_CLOCK_ISP>; + clock-names = "v3d", "peri_image", "h264", "isp"; + system-power-controller; + }; + + random: rng@7e104000 { + compatible = "brcm,bcm2711-rng200"; + reg = <0x7e104000 0x28>; + }; + + dvp: clock@7ef00000 { + compatible = "brcm,brcm2711-dvp"; + reg = <0x7ef00000 0x10>; + clocks = <&clk_108MHz>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + aon_intr: interrupt-controller@7ef00100 { + compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; + reg = <0x7ef00100 0x30>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + status = "disabled"; + }; + + mmcnr@7e300000 { + compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci"; + reg = <0x7e300000 0x100>; + interrupts = ; + clocks = <&clocks BCM2835_CLOCK_EMMC>; + dmas = <&dma 11>; + dma-names = "rx-tx"; + brcm,overclock-50 = <0>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + bus-width = <4>; + }; + + firmware: firmware { + compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + mboxes = <&mailbox>; + dma-ranges; + + firmware_clocks: clocks { + compatible = "raspberrypi,firmware-clocks"; + #clock-cells = <1>; + }; + + expgpio: gpio { + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; + }; + + power: power { + compatible = "raspberrypi,bcm2835-power"; + firmware = <&firmware>; + #power-domain-cells = <1>; + }; + + fb: fb { + compatible = "brcm,bcm2708-fb"; + firmware = <&firmware>; + }; + }; + + clocks { + + clk_osc: clk-osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "osc"; + clock-frequency = <54000000>; + }; + + clk_usb: clk-usb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "otg"; + clock-frequency = <480000000>; + }; + }; + + usbphy: phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + clk_27MHz: clk-27M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + clock-output-names = "27MHz-clock"; + }; + + clk_108MHz: clk-108M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <108000000>; + clock-output-names = "108MHz-clock"; + }; + + scb { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, + <0x6 0x00000000 0x6 0x00000000 0x40000000>; + + pcie0: pcie@7d500000 { + compatible = "brcm,bcm2711-pcie"; + reg = <0x0 0x7d500000 0x9310>; + device_type = "pci"; + #address-cells = <3>; + #interrupt-cells = <1>; + #size-cells = <2>; + interrupts = , + ; + interrupt-names = "pcie", "msi"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &gicv2 GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &gicv2 GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &gicv2 GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>; + msi-controller; + msi-parent = <&pcie0>; + + ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>; + /* + * The wrapper around the PCIe block has a bug + * preventing it from accessing beyond the first 3GB of + * memory. + */ + dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x0 0xc0000000>; + brcm,enable-ssc; + + pci@0,0 { + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + reg = <0 0 0 0 0>; + + usb@0,0 { + reg = <0 0 0 0 0>; + resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; + }; + }; + }; + + genet: ethernet@7d580000 { + compatible = "brcm,bcm2711-genet-v5"; + reg = <0x0 0x7d580000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = , + ; + phy-handle = <&mdio_phy>; + phy-mode = "rgmii-rxid"; + + genet_mdio: mdio@e14 { + compatible = "brcm,genet-mdio-v5"; + reg = <0xe14 0x8>; + reg-names = "mdio"; + #address-cells = <1>; + #size-cells = <0>; + + mdio_phy: ethernet-phy@1 { + reg = <0x01>; + led-modes = <0x00 0x08>; /* link/activity link */ + }; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-act { + label = "ACT"; + default-state = "off"; + rt-thread,default-trigger = "mmc0"; + gpios = <&gpio 42 PIN_ACTIVE_HIGH>; + }; + + led-pwr { + label = "PWR"; + default-state = "off"; + gpios = <&expgpio 2 PIN_ACTIVE_LOW>; + rt-thread,default-trigger = "default-on"; + }; + }; +}; diff --git a/bsp/raspberry-pi/dm/dts/bcm283x-rpi-3-b.dts b/bsp/raspberry-pi/dm/dts/bcm283x-rpi-3-b.dts new file mode 100755 index 0000000000..ff3d3f8f6b --- /dev/null +++ b/bsp/raspberry-pi/dm/dts/bcm283x-rpi-3-b.dts @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +/dts-v1/; +#include +#include +#include +#include +#include +#include +#include + +/* + * NOTE: Just for QEMU, not the really board! + */ + +/* + * firmware-provided startup stubs live here, where the secondary CPUs are + * spinning. + */ +/memreserve/ 0x00000000 0x00001000; + +/ { + compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; + model = "Raspberry Pi 3 Model B"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; + + aliases { + serial0 = "/soc/serial@7e215040"; + serial1 = "/soc/serial@7e201000"; + mmc0 = "/soc/mmcnr@7e300000"; + spi0 = "/soc/spi@7e204000"; + i2c0 = "/soc/i2c@7e205000"; + i2c1 = "/soc/i2c@7e804000"; + i2c2 = "/soc/i2c@7e805000"; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + /* For ARM 32-bit */ + enable-method = "brcm,bcm2836-smp"; + + /* + * Source for d/i-cache-line-size and d/i-cache-sets + * https://developer.arm.com/documentation/ddi0500/e/level-1-memory-system + * /about-the-l1-memory-system?lang=en + * + * Source for d/i-cache-size + * https://magpi.raspberrypi.com/articles/raspberry-pi-3-specs-benchmarks + */ + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000d8>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <1>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000e0>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + next-level-cache = <&l2>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <2>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000e8>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + next-level-cache = <&l2>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <3>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x000000f0>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set + next-level-cache = <&l2>; + }; + + /* + * Source for cache-line-size + cache-sets + * https://developer.arm.com/documentation/ddi0500 + * /e/level-2-memory-system/about-the-l2-memory-system?lang=en + * Source for cache-size + * https://datasheets.raspberrypi.com/cm/cm1-and-cm3-datasheet.pdf + */ + l2: l2-cache0 { + compatible = "cache"; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <512>; // 512KiB(size)/64(line-size)=8192ways/16-way set + cache-level = <2>; + }; + }; + + arm-pmu { + compatible = "arm,cortex-a53-pmu", "arm,cortex-a7-pmu"; + interrupt-parent = <&local_intc>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH>; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupt-parent = <&local_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI + <1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI + <3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI + <2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI + always-on; + }; + + thermal-zones { + + cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <1000>; + thermal-sensors = <&thermal>; + coefficients = <(-538) 412000>; + + trips { + cpu-crit { + temperature = <90000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x7e000000 0x3f000000 0x1000000>, + <0x40000000 0x40000000 0x00001000>; + dma-ranges = <0xc0000000 0x00000000 0x3f000000>, + <0x7e000000 0x3f000000 0x01000000>; + + system_timer: timer@7e003000 { + compatible = "brcm,bcm2835-system-timer"; + reg = <0x7e003000 0x1000>; + interrupts = <1 0>, <1 1>, <1 2>, <1 3>; + /* + * This could be a reference to BCM2835_CLOCK_TIMER, + * but we don't have the driver using the common clock + * support yet. + */ + clock-frequency = <1000000>; + }; + + clocks: cprman@7e101000 { + compatible = "brcm,bcm2835-cprman"; + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + + /* + * CPRMAN derives almost everything from the + * platform's oscillator. However, the DSI + * pixel clocks come from the DSI analog PHY. + */ + clocks = <&clk_osc>; + }; + + mailbox: mailbox@7e00b880 { + compatible = "brcm,bcm2835-mbox"; + reg = <0x7e00b880 0x40>; + interrupts = <0 1>; + #mbox-cells = <0>; + }; + + gpio: gpio@7e200000 { + compatible = "brcm,bcm2835-gpio"; + reg = <0x7e200000 0xb4>; + interrupts = <2 17>, <2 18>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&gpio 0 0 54>; + pinctrl-names = "default"; + gpio-line-names = "ID_SDA", + "ID_SCL", + "SDA1", + "SCL1", + "GPIO_GCLK", + "GPIO5", + "GPIO6", + "SPI_CE1_N", + "SPI_CE0_N", + "SPI_MISO", + "SPI_MOSI", + "SPI_SCLK", + "GPIO12", + "GPIO13", + /* Serial port */ + "TXD1", + "RXD1", + "GPIO16", + "GPIO17", + "GPIO18", + "GPIO19", + "GPIO20", + "GPIO21", + "GPIO22", + "GPIO23", + "GPIO24", + "GPIO25", + "GPIO26", + "GPIO27", + "NC", /* GPIO 28 */ + "LAN_RUN_BOOT", + /* Used by BT module */ + "CTS0", + "RTS0", + "TXD0", + "RXD0", + /* Used by Wifi */ + "SD1_CLK", + "SD1_CMD", + "SD1_DATA0", + "SD1_DATA1", + "SD1_DATA2", + "SD1_DATA3", + "PWM0_OUT", + "PWM1_OUT", + "ETH_CLK", + "WIFI_CLK", + "SDA0", + "SCL0", + "SMPS_SCL", + "SMPS_SDA", + /* Used by SD Card */ + "SD_CLK_R", + "SD_CMD_R", + "SD_DATA0_R", + "SD_DATA1_R", + "SD_DATA2_R", + "SD_DATA3_R"; + + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = ; + }; + + spi0_cs_pins: spi0_cs_pins { + brcm,pins = <8 7>; + brcm,function = ; + }; + + i2c0_gpio0: i2c0_gpio0 { + brcm,pins = <0 1>; + brcm,function = ; + }; + + i2c1_gpio2: i2c1_gpio2 { + brcm,pins = <2 3>; + brcm,function = ; + }; + + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = ; + brcm,pull = , + , + , + , + , + ; + }; + + bt_pins: bt_pins { + brcm,pins = <43>; + brcm,function = ; + brcm,pull = ; + }; + + uart0_pins: uart0_pins { + brcm,pins = <32 33>; + brcm,function = ; + brcm,pull = ; + }; + + uart1_pins: uart1_pins { + brcm,pins; + brcm,function; + brcm,pull; + }; + }; + + serial@7e201000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x7e201000 0x200>; + interrupts = <2 25>; + clocks = <&clocks BCM2835_CLOCK_UART>, + <&clocks BCM2835_CLOCK_VPU>; + clock-names = "uartclk", "apb_pclk"; + arm,primecell-periphid = <0x00241011>; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>, <&bt_pins>; + skip-init; + }; + + spi@7e204000 { + compatible = "brcm,bcm2835-spi"; + reg = <0x7e204000 0x200>; + interrupts = <2 22>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&dma 6>, <&dma 7>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>, <&spi0_cs_pins>; + cs-gpios = <&gpio 8 1>, <&gpio 7 1>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x00>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; + }; + + i2c@7e205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x200>; + interrupts = <2 21>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_gpio0>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "st,m41t00", "dallas,ds1338"; + reg = <0x68>; + }; + }; + + i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; + interrupts = <2 21>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_gpio2>; + clock-frequency = <100000>; + }; + + i2c@7e805000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e805000 0x1000>; + interrupts = <2 21>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; + + aux: aux@7e215000 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; + reg = <0x7e215000 0x8>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + }; + + serial@7e215040 { + compatible = "brcm,bcm2835-aux-uart"; + reg = <0x7e215040 0x40>; + interrupts = <1 29>; + clocks = <&aux BCM2835_AUX_CLOCK_UART>; + skip-init; + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + }; + + usb: usb@7e980000 { + compatible = "brcm,bcm2835-usb"; + reg = <0x7e980000 0x10000>, + <0x7e006000 0x1000>; + interrupts = <1 9>, <2 0>; + interrupt-names = "usb", "soft"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_usb>; + clock-names = "otg"; + phys = <&usbphy>; + phy-names = "usb2-phy"; + power-domains = <&power RPI_POWER_DOMAIN_USB>; + }; + + dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xf00>; + interrupts = <1 16>, + <1 17>, + <1 18>, + <1 19>, + <1 20>, + <1 21>, + <1 22>, + <1 23>, + <1 24>, + <1 25>, + <1 26>, + /* dma channel 11-14 share one irq */ + <1 27>, + <1 27>, + <1 27>, + <1 27>, + /* unused shared irq for all channels */ + <1 28>; + interrupt-names = "dma0", + "dma1", + "dma2", + "dma3", + "dma4", + "dma5", + "dma6", + "dma7", + "dma8", + "dma9", + "dma10", + "dma11", + "dma12", + "dma13", + "dma14", + "dma-shared-all"; + #dma-cells = <1>; + brcm,dma-channel-mask = <0x7f35>; + }; + + intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2836-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-parent = <&local_intc>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pm: watchdog@7e100000 { + compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; + #power-domain-cells = <1>; + #reset-cells = <1>; + reg = <0x7e100000 0x114>, + <0x7e00a000 0x24>; + reg-names = "pm", "asb"; + clocks = <&clocks BCM2835_CLOCK_V3D>, + <&clocks BCM2835_CLOCK_PERI_IMAGE>, + <&clocks BCM2835_CLOCK_H264>, + <&clocks BCM2835_CLOCK_ISP>; + clock-names = "v3d", "peri_image", "h264", "isp"; + system-power-controller; + }; + + random: rng@7e104000 { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; + interrupts = <2 29>; + }; + + thermal: thermal@7e212000 { + compatible = "brcm,bcm2837-thermal"; + reg = <0x7e212000 0x8>; + clocks = <&clocks BCM2835_CLOCK_TSENS>; + #thermal-sensor-cells = <0>; + }; + + local_intc: local_intc@40000000 { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&local_intc>; + }; + + mmcnr@7e300000 { + compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci"; + reg = <0x7e300000 0x100>; + interrupts = <2 30>; + clocks = <&clocks BCM2835_CLOCK_EMMC>; + dmas = <&dma 11>; + dma-names = "rx-tx"; + brcm,overclock-50 = <0>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + bus-width = <4>; + }; + + firmware: firmware { + compatible = "raspberrypi,bcm2835-firmware", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + mboxes = <&mailbox>; + ranges; + + clocks { + compatible = "raspberrypi,firmware-clocks"; + #clock-cells = <1>; + }; + + expgpio: expgpio { + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "BT_ON", + "WL_ON", + "STATUS_LED", + "LAN_RUN", + "HDMI_HPD_N", + "CAM_GPIO0", + "CAM_GPIO1", + "PWR_LOW_N"; + }; + }; + + power: power { + compatible = "raspberrypi,bcm2835-power"; + firmware = <&firmware>; + #power-domain-cells = <1>; + }; + + fb: fb { + compatible = "brcm,bcm2708-fb"; + firmware = <&firmware>; + }; + + virtgpio: virtgpio { + compatible = "brcm,bcm2835-virtgpio"; + gpio-controller; + #gpio-cells = <2>; + firmware = <&firmware>; + }; + + nvmem { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + nvmem_otp: nvmem_otp { + compatible = "raspberrypi,rpi-otp"; + firmware = <&firmware>; + reg = <0 166>; + }; + + nvmem_cust: nvmem_cust { + compatible = "raspberrypi,rpi-otp"; + firmware = <&firmware>; + reg = <1 8>; + }; + + nvmem_priv: nvmem_priv { + compatible = "raspberrypi,rpi-otp"; + firmware = <&firmware>; + reg = <3 8>; + }; + }; + }; + + clocks { + + /* The oscillator is the root of the clock tree. */ + clk_osc: clk-osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "osc"; + clock-frequency = <19200000>; + }; + + clk_usb: clk-usb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "otg"; + clock-frequency = <480000000>; + }; + }; + + usbphy: phy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + leds { + compatible = "gpio-leds"; + + led-act { + label = "ACT"; + default-state = "off"; + rt-thread,default-trigger = "mmc0"; + gpios = <&virtgpio 0 0>; + }; + + led-pwr { + label = "PWR"; + default-state = "off"; + rt-thread,default-trigger = "input"; + gpios = <&expgpio 7 0>; + }; + }; +}; diff --git a/bsp/raspberry-pi/dm/dvfs/Kconfig b/bsp/raspberry-pi/dm/dvfs/Kconfig new file mode 100755 index 0000000000..2ad5f6ca25 --- /dev/null +++ b/bsp/raspberry-pi/dm/dvfs/Kconfig @@ -0,0 +1,4 @@ +config RT_DVFS_RASPBERRY_CPUFREQ + bool "Raspberry firmware CPUfreq driver" + depends on RT_USING_DVFS + default n diff --git a/bsp/raspberry-pi/dm/dvfs/SConscript b/bsp/raspberry-pi/dm/dvfs/SConscript new file mode 100755 index 0000000000..fa9ea116d4 --- /dev/null +++ b/bsp/raspberry-pi/dm/dvfs/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_DVFS_RASPBERRY_CPUFREQ']): + src += ['dvfs-raspberrypi-cpufreq.c'] + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DVFS'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/dvfs/dvfs-raspberrypi-cpufreq.c b/bsp/raspberry-pi/dm/dvfs/dvfs-raspberrypi-cpufreq.c new file mode 100755 index 0000000000..a915842656 --- /dev/null +++ b/bsp/raspberry-pi/dm/dvfs/dvfs-raspberrypi-cpufreq.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "dvfs.raspberrypi-cpufreq" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +#define RASPBERRYPI_FREQ_INTERVAL 100000000 + +static rt_err_t raspberrypi_firmware_clk_rate(struct rpi_firmware *rpi_fw, + rt_uint32_t tag, rt_uint32_t id, rt_uint32_t *rate) +{ + struct rpi_firmware_clk_rate_request msg = + { + .id = rt_cpu_to_le32(id), + }; + + if (!rpi_fw || !rate) + { + return -RT_EINVAL; + } + + if (rpi_firmware_property(rpi_fw, tag, &msg, sizeof(msg))) + { + return -RT_EIO; + } + + *rate = rt_le32_to_cpu(msg.rate); + + return RT_EOK; +} + +static rt_err_t raspberrypi_arm_clk_get_range(struct rt_clk *arm_clk, + struct rpi_firmware *rpi_fw, rt_ubase_t *min, rt_ubase_t *max) +{ + rt_uint32_t min_hz = 0, max_hz = 0; + + if (!arm_clk || !min || !max) + { + return -RT_EINVAL; + } + + if (arm_clk->min_rate && arm_clk->max_rate) + { + *min = arm_clk->min_rate; + *max = arm_clk->max_rate; + return RT_EOK; + } + + if (!rpi_fw) + { + LOG_E("ARM clk range missing and no firmware handle"); + return -RT_EINVAL; + } + + if (raspberrypi_firmware_clk_rate(rpi_fw, RPI_FIRMWARE_GET_MIN_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, &min_hz)) + { + LOG_E("firmware %s for ARM failed", "GET_MIN_CLOCK_RATE"); + return -RT_EIO; + } + + if (raspberrypi_firmware_clk_rate(rpi_fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, &max_hz)) + { + LOG_E("firmware %s for ARM failed", "GET_MAX_CLOCK_RATE"); + return -RT_EIO; + } + + if (!min_hz || !max_hz || min_hz > max_hz) + { + LOG_E("firmware ARM range invalid: %u-%u Hz", min_hz, max_hz); + return -RT_EINVAL; + } + + rt_clk_set_rate_range(arm_clk, min_hz, max_hz); + *min = min_hz; + *max = max_hz; + + return RT_EOK; +} + +static void raspberrypi_cpufreq_cleanup(struct rt_dvfs_scaling *scaling, + struct rt_dvfs_cpufreq *cpufreq) +{ + if (scaling && scaling->opp_table) + { + rt_dvfs_scaling_remove_opp_all(scaling); + } + + rt_free(cpufreq); +} + +/* + * Board-specific helper: build the OPP table and hand the cpufreq object + * to the generic "ofw-cpufreq" platform driver (see dvfs-ofw.c). + */ +rt_err_t raspberrypi_cpufreq_register(struct rt_clk *arm_clk, struct rt_ofw_node *cpu_np, + struct rpi_firmware *rpi_fw) +{ + rt_err_t err; + rt_ubase_t min, max, rate; + rt_uint32_t opp_count = 0; + struct rt_dvfs_cpufreq *cpufreq; + struct rt_dvfs_scaling *scaling; + struct rt_platform_device *pdev; + + if (!arm_clk || rt_is_err_or_null(arm_clk) || !cpu_np) + { + return -RT_EINVAL; + } + + if (!(cpufreq = rt_calloc(1, sizeof(*cpufreq)))) + { + return -RT_ENOMEM; + } + + scaling = rt_dvfs_cpufreq_to_scaling(cpufreq); + scaling->clk = arm_clk; + /* + * VideoCore owns voltage/thermal mitigation; no extra settling time is + * needed after firmware clock changes. + */ + scaling->transition_latency = 0; + scaling->retry_delay = 100000; + rt_memset(cpufreq->cpus_map, 0xff, sizeof(cpufreq->cpus_map)); + + if ((err = raspberrypi_arm_clk_get_range(arm_clk, rpi_fw, &min, &max))) + { + LOG_E("ARM clock range unavailable: %s", rt_strerror(err)); + raspberrypi_cpufreq_cleanup(scaling, cpufreq); + return err; + } + + min = rt_roundup(min, RASPBERRYPI_FREQ_INTERVAL); + max = rt_roundup(max, RASPBERRYPI_FREQ_INTERVAL); + + if (!min || !max || min > max) + { + LOG_E("invalid ARM clock range: %lu-%lu Hz", min, max); + raspberrypi_cpufreq_cleanup(scaling, cpufreq); + return -RT_EINVAL; + } + + for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) + { + if (!rt_dvfs_scaling_add_opp(scaling, rate, 0)) + { + LOG_E("failed to add OPP %lu Hz (added %u so far)", rate, opp_count); + raspberrypi_cpufreq_cleanup(scaling, cpufreq); + return -RT_ERROR; + } + + ++opp_count; + } + + /* + * Keep the current boot frequency. ofw_dvfs_setup() eventually calls + * rt_dvfs_scaling_register(), which skips dvfs_scaling_init_frequency() + * when cur_freq is already set. + */ + rate = rt_clk_get_rate(arm_clk); + + if (rate) + { + struct rt_dvfs_opp *opp = rt_dvfs_scaling_find_floor_opp(scaling, rate); + + if (!opp) + { + opp = rt_dvfs_scaling_find_ceil_opp(scaling, rate); + } + + if (opp) + { + scaling->cur_freq = opp->freq; + } + else + { + LOG_W("no matching OPP for current rate %lu Hz", rate); + } + } + + if (!(pdev = rt_platform_device_alloc("ofw-cpufreq"))) + { + LOG_E("alloc ofw-cpufreq failed"); + err = -RT_ENOMEM; + goto _free_cpufreq; + } + + pdev->priv = cpufreq; + + rt_dm_dev_set_name_auto(&pdev->parent, "cpufreq"); + + if ((err = rt_device_register(&pdev->parent, rt_dm_dev_get_name(&pdev->parent), + RT_DEVICE_FLAG_DEACTIVATE))) + { + goto _free; + } + + if ((err = rt_platform_device_register(pdev))) + { + goto _unregister; + } + + if (!pdev->parent.drv) + { + err = -RT_ERROR; + goto _free_bus; + } + + return RT_EOK; +_free_bus: + rt_bus_remove_device(&pdev->parent); +_unregister: + rt_device_unregister(&pdev->parent); +_free: + rt_free(pdev); +_free_cpufreq: + raspberrypi_cpufreq_cleanup(scaling, cpufreq); + return err; +} + +static int raspberrypi_dvfs_cpufreq_init(void) +{ + rt_err_t err; + struct rt_clk *arm_clk; + struct rt_ofw_node *cpu_np, *fw_np; + struct rpi_firmware *rpi_fw = RT_NULL; + + if (!(arm_clk = raspberrypi_arm_clk_get())) + { + LOG_E("ARM clock not ready, skip cpufreq"); + return 0; + } + + if (!(cpu_np = rt_ofw_get_next_cpu_node(RT_NULL))) + { + LOG_E("no CPU node, skip cpufreq"); + return 0; + } + + if ((fw_np = rpi_firmware_find_node())) + { + rpi_fw = rpi_firmware_get(fw_np); + } + + err = raspberrypi_cpufreq_register(arm_clk, cpu_np, rpi_fw); + + if (rpi_fw) + { + rpi_firmware_put(rpi_fw); + } + rt_ofw_node_put(cpu_np); + + if (err) + { + LOG_W("cpufreq init failed: %s", rt_strerror(err)); + } + + return 0; +} +INIT_ENV_EXPORT(raspberrypi_dvfs_cpufreq_init); diff --git a/bsp/raspberry-pi/dm/ethernet/Kconfig b/bsp/raspberry-pi/dm/ethernet/Kconfig new file mode 100755 index 0000000000..c481be0cef --- /dev/null +++ b/bsp/raspberry-pi/dm/ethernet/Kconfig @@ -0,0 +1,3 @@ +config RT_ETHERNET_BCMGENET + bool "BCMGENET V5 Ethernet MAC" + default n diff --git a/bsp/raspberry-pi/dm/ethernet/SConscript b/bsp/raspberry-pi/dm/ethernet/SConscript new file mode 100755 index 0000000000..47abea403d --- /dev/null +++ b/bsp/raspberry-pi/dm/ethernet/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_ETHERNET_BCMGENET']): + src += ['eth-bcmgenet.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/ethernet/eth-bcmgenet.c b/bsp/raspberry-pi/dm/ethernet/eth-bcmgenet.c new file mode 100755 index 0000000000..a15796f7bd --- /dev/null +++ b/bsp/raspberry-pi/dm/ethernet/eth-bcmgenet.c @@ -0,0 +1,1219 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "eth.bcmgenet" +#define DBG_LVL DBG_WARNING +#include + +#include +#include +#include +#include +#ifdef RT_USING_SYSTEM_WORKQUEUE +#include +#endif +#include + +#define SYS_REV_CTRL 0x00 + +#define SYS_PORT_CTRL 0x04 +#define PORT_MODE_EXT_GPHY 3 + +#define GENET_SYS_OFF 0x0000 +#define SYS_RBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x08) +#define SYS_TBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x0c) + +#define GENET_EXT_OFF 0x0080 +#define EXT_RGMII_OOB_CTRL (GENET_EXT_OFF + 0x0c) +#define RGMII_LINK RT_BIT(4) +#define OOB_DISABLE RT_BIT(5) +#define RGMII_MODE_EN RT_BIT(6) +#define ID_MODE_DIS RT_BIT(16) + +#define GENET_RBUF_OFF 0x0300 +#define RBUF_CTRL (GENET_RBUF_OFF + 0x00) +#define RBUF_64B_EN RT_BIT(0) +#define RBUF_ALIGN_2B RT_BIT(1) +#define RBUF_CHK_CTRL (GENET_RBUF_OFF + 0x14) +#define RBUF_RXCHK_EN RT_BIT(0) +#define RBUF_L3_PARSE_DIS RT_BIT(1) +#define RBUF_TBUF_SIZE_CTRL (GENET_RBUF_OFF + 0xb4) + +#define GENET_TBUF_OFF 0x0600 +#define TBUF_CTRL (GENET_TBUF_OFF + 0x00) +#define TBUF_64B_EN RT_BIT(0) + +#define GENET_UMAC_OFF 0x0800 +#define UMAC_MIB_CTRL (GENET_UMAC_OFF + 0x580) +#define UMAC_MAX_FRAME_LEN (GENET_UMAC_OFF + 0x014) +#define UMAC_MAC0 (GENET_UMAC_OFF + 0x00c) +#define UMAC_MAC1 (GENET_UMAC_OFF + 0x010) +#define UMAC_CMD (GENET_UMAC_OFF + 0x008) +#define MDIO_CMD (GENET_UMAC_OFF + 0x614) +#define UMAC_TX_FLUSH (GENET_UMAC_OFF + 0x334) +#define MDIO_START_BUSY RT_BIT(29) +#define MDIO_READ_FAIL RT_BIT(28) +#define MDIO_RD (2 << 26) +#define MDIO_WR RT_BIT(26) +#define MDIO_PMD_SHIFT 21 +#define MDIO_PMD_MASK 0x1f +#define MDIO_REG_SHIFT 16 +#define MDIO_REG_MASK 0x1f + +#define CMD_TX_EN RT_BIT(0) +#define CMD_RX_EN RT_BIT(1) +#define UMAC_SPEED_10 0 +#define UMAC_SPEED_100 1 +#define UMAC_SPEED_1000 2 +#define UMAC_SPEED_2500 3 +#define CMD_SPEED_SHIFT 2 +#define CMD_SPEED_MASK 3 +#define CMD_HD_EN RT_BIT(10) +#define CMD_RX_PAUSE_IGNORE RT_BIT(8) +#define CMD_TX_PAUSE_IGNORE RT_BIT(28) +#define CMD_SW_RESET RT_BIT(13) +#define CMD_LCL_LOOP_EN RT_BIT(15) +#define CMD_PROMISC RT_BIT(4) + +#define UMAC_MDF_CTRL (GENET_UMAC_OFF + 0x650) +#define UMAC_MDF_ADDR (GENET_UMAC_OFF + 0x654) +#define MAX_MDF_FILTER 17 + +#define MIB_RESET_RX RT_BIT(0) +#define MIB_RESET_RUNT RT_BIT(1) +#define MIB_RESET_TX RT_BIT(2) + +/* Total number of Buffer Descriptors, same for Rx/Tx */ +#define TOTAL_DESCS 256 +#define RX_DESCS TOTAL_DESCS +#define DESC_INDEX 16 +#define DEFAULT_RING 16 +#define TX_DESCS TOTAL_DESCS + +/* Per-ring register block size and total ring control area (rings 0..16). */ +#define DMA_RING_SIZE 0x40 +#define DMA_RINGS_SIZE (DMA_RING_SIZE * (DESC_INDEX + 1)) + +/* + * Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528. + * 1536 is multiple of 256 bytes + */ +#define ENET_BRCM_TAG_LEN 6 +#define ENET_PAD 8 +#define ENET_DATA_LEN 1500 /* Max. octets in payload */ +#define ENET_HLEN 14 /* Total octets in header */ +#define ENET_FCS_LEN 4 /* Octets in the FCS */ +#define ENET_VLAN_HLEN 4 +#define ENET_MAX_MTU_SIZE (ENET_DATA_LEN + ENET_HLEN + ENET_VLAN_HLEN + ENET_BRCM_TAG_LEN + ENET_FCS_LEN + ENET_PAD) + +/* Tx/Rx Dma Descriptor common bits */ +#define DMA_EN RT_BIT(0) +#define DMA_RING_BUF_EN_SHIFT 0x01 +#define DMA_RING_BUF_EN_MASK 0xffff +#define DMA_BUFLENGTH_MASK 0x0fff +#define DMA_BUFLENGTH_SHIFT 16 +#define DMA_RING_SIZE_SHIFT 16 +#define DMA_OWN 0x8000 +#define DMA_EOP 0x4000 +#define DMA_SOP 0x2000 +#define DMA_WRAP 0x1000 +#define DMA_MAX_BURST_LENGTH 0x8 +/* Tx specific DMA descriptor bits */ +#define DMA_TX_UNDERRUN 0x0200 +#define DMA_TX_APPEND_CRC 0x0040 +#define DMA_TX_OW_CRC 0x0020 +#define DMA_TX_DO_CSUM 0x0010 +#define DMA_TX_QTAG_SHIFT 7 + +/* DMA descriptor */ +#define DMA_DESC_LENGTH_STATUS 0x00 +#define DMA_DESC_ADDRESS_LO 0x04 +#define DMA_DESC_ADDRESS_HI 0x08 +#define DMA_DESC_SIZE 12 + +#define GENET_RX_OFF 0x2000 +#define GENET_RDMA_REG_OFF (GENET_RX_OFF + TOTAL_DESCS * DMA_DESC_SIZE) +#define GENET_TX_OFF 0x4000 +#define GENET_TDMA_REG_OFF (GENET_TX_OFF + TOTAL_DESCS * DMA_DESC_SIZE) + +#define DMA_FC_THRESH_HI (RX_DESCS >> 4) +#define DMA_FC_THRESH_LO 5 +#define DMA_FC_THRESH_VALUE ((DMA_FC_THRESH_LO << 16) | DMA_FC_THRESH_HI) + +#define DMA_XOFF_THRESHOLD_SHIFT 16 + +#define TDMA_RING_REG_BASE (GENET_TDMA_REG_OFF + DEFAULT_RING * DMA_RING_SIZE) +#define TDMA_READ_PTR (TDMA_RING_REG_BASE + 0x00) +#define TDMA_CONS_INDEX (TDMA_RING_REG_BASE + 0x08) +#define TDMA_PROD_INDEX (TDMA_RING_REG_BASE + 0x0c) +#define DMA_RING_BUF_SIZE 0x10 +#define DMA_START_ADDR 0x14 +#define DMA_END_ADDR 0x1c +#define DMA_MBUF_DONE_THRESH 0x24 +#define TDMA_FLOW_PERIOD (TDMA_RING_REG_BASE + 0x28) +#define TDMA_WRITE_PTR (TDMA_RING_REG_BASE + 0x2c) + +#define RDMA_RING_REG_BASE (GENET_RDMA_REG_OFF + DEFAULT_RING * DMA_RING_SIZE) +#define RDMA_WRITE_PTR (RDMA_RING_REG_BASE + 0x00) +#define RDMA_PROD_INDEX (RDMA_RING_REG_BASE + 0x08) +#define RDMA_CONS_INDEX (RDMA_RING_REG_BASE + 0x0c) +#define RDMA_XON_XOFF_THRESH (RDMA_RING_REG_BASE + 0x28) +#define RDMA_READ_PTR (RDMA_RING_REG_BASE + 0x2c) + +#define TDMA_REG_BASE (GENET_TDMA_REG_OFF + DMA_RINGS_SIZE) +#define RDMA_REG_BASE (GENET_RDMA_REG_OFF + DMA_RINGS_SIZE) +#define DMA_RING_CFG 0x00 +#define DMA_CTRL 0x04 +#define DMA_SCB_BURST_SIZE 0x0c + +#define DMA_P_INDEX_MASK 0xffff + +#define RX_BUF_LENGTH 2048 +#define RX_TOTAL_BUFSIZE (RX_BUF_LENGTH * RX_DESCS) +#define TX_TOTAL_BUFSIZE RX_TOTAL_BUFSIZE +#define GENET_RX_RSB_SIZE 66 +#define GENET_TX_TSB_SIZE 64 +#define RX_BUF_OFFSET 2 + +#define PHY_RETRY_INTERVAL_MS 2000 +#define PHY_RETRY_MAX 15 + +#define GENET_INTRL2_0_OFF 0x0200 +#define GENET_INTRL2_1_OFF 0x0240 +/* uniMac intrl2 registers */ +#define INTRL2_CPU_STAT 0x00 +#define INTRL2_CPU_SET 0x04 +#define INTRL2_CPU_CLEAR 0x08 +#define INTRL2_CPU_MASK_STATUS 0x0c +#define INTRL2_CPU_MASK_SET 0x10 +#define INTRL2_CPU_MASK_CLEAR 0x14 + +/* INTRL2 instance 0 definitions */ +#define UMAC_IRQ_SCB RT_BIT(0) +#define UMAC_IRQ_EPHY RT_BIT(1) +#define UMAC_IRQ_PHY_DET_R RT_BIT(2) +#define UMAC_IRQ_PHY_DET_F RT_BIT(3) +#define UMAC_IRQ_LINK_UP RT_BIT(4) +#define UMAC_IRQ_LINK_DOWN RT_BIT(5) +#define UMAC_IRQ_LINK_EVENT (UMAC_IRQ_LINK_UP | UMAC_IRQ_LINK_DOWN) +#define UMAC_IRQ_UMAC RT_BIT(6) +#define UMAC_IRQ_UMAC_TSV RT_BIT(7) +#define UMAC_IRQ_TBUF_UNDERRUN RT_BIT(8) +#define UMAC_IRQ_RBUF_OVERFLOW RT_BIT(9) +#define UMAC_IRQ_HFB_SM RT_BIT(10) +#define UMAC_IRQ_HFB_MM RT_BIT(11) +#define UMAC_IRQ_MPD_R RT_BIT(12) +#define UMAC_IRQ_WAKE_EVENT (UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM | UMAC_IRQ_MPD_R) +#define UMAC_IRQ_RXDMA_MBDONE RT_BIT(13) +#define UMAC_IRQ_RXDMA_PDONE RT_BIT(14) +#define UMAC_IRQ_RXDMA_BDONE RT_BIT(15) +#define UMAC_IRQ_RXDMA_DONE UMAC_IRQ_RXDMA_MBDONE +#define UMAC_IRQ_TXDMA_MBDONE RT_BIT(16) +#define UMAC_IRQ_TXDMA_PDONE RT_BIT(17) +#define UMAC_IRQ_TXDMA_BDONE RT_BIT(18) +#define UMAC_IRQ_TXDMA_DONE UMAC_IRQ_TXDMA_MBDONE + +/* Only valid for GENETv3+ */ +#define UMAC_IRQ_MDIO_DONE RT_BIT(23) +#define UMAC_IRQ_MDIO_ERROR RT_BIT(24) + +/* INTRL2 instance 1 definitions */ +#define UMAC_IRQ1_RX_INTR_SHIFT 16 +#define UMAC_IRQ1_TX_INTR(ring) RT_BIT(ring) +#define UMAC_IRQ1_RX_INTR(ring) RT_BIT(UMAC_IRQ1_RX_INTR_SHIFT + (ring)) + +#define HWREGCLR32(reg, clr) HWREG32(reg) &= ~(clr) +#define HWREGSET32(reg, set) HWREG32(reg) |= (set) +#define HWREGCLRSET32(reg, clr, set) HWREG32(reg) = (HWREG32(reg) & ~(clr)) | (set) + +struct bcmgenet_eth +{ + struct eth_device parent; + struct rt_phy_device *phy; + struct rt_device *dev; + + void *base; + void *tx_desc_base; + void *rx_desc_base; + int irq0, irq1; + + rt_uint8_t mac[6]; + rt_uint32_t speed; + rt_phy_interface interface; + + int tx_index; + int rx_index; + int c_index; + rt_uint8_t *rxbuffer; + rt_uint8_t *txbuffer; + rt_ubase_t rxbuffer_dma; + rt_ubase_t txbuffer_dma; + + struct rt_semaphore tx_done; + +#ifdef RT_USING_SYSTEM_WORKQUEUE + struct rt_work link_work; + struct rt_work phy_retry_work; + int phy_retry_count; +#endif + + rt_size_t dma_buf_size; + +#ifdef RT_USING_OFW + struct rt_ofw_node *phy_np; +#endif +}; + +#define raw_to_bcmgenet_eth(raw) \ + rt_container_of(rt_container_of(raw, struct eth_device, parent), struct bcmgenet_eth, parent) + +static void bcmgenet_umac_reset(struct bcmgenet_eth *eth) +{ + rt_uint32_t reg; + + reg = HWREG32(eth->base + SYS_RBUF_FLUSH_CTRL); + reg |= RT_BIT(1); + HWREG32(eth->base + SYS_RBUF_FLUSH_CTRL) = reg; + rt_hw_us_delay(10); + + reg &= ~RT_BIT(1); + HWREG32(eth->base + SYS_RBUF_FLUSH_CTRL) = reg; + rt_hw_us_delay(10); + + HWREG32(eth->base + SYS_RBUF_FLUSH_CTRL) = 0; + rt_hw_us_delay(10); + + HWREG32(eth->base + UMAC_CMD) = 0; + + HWREG32(eth->base + UMAC_CMD) = CMD_SW_RESET | CMD_LCL_LOOP_EN; + rt_hw_us_delay(2); + HWREG32(eth->base + UMAC_CMD) = 0; + + /* Clear tx/rx counter */ + HWREG32(eth->base + UMAC_MIB_CTRL) = MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT; + HWREG32(eth->base + UMAC_MIB_CTRL) = 0; + + HWREG32(eth->base + UMAC_MAX_FRAME_LEN) = ENET_MAX_MTU_SIZE; + + /* Enable 64-byte transmit status block */ + reg = HWREG32(eth->base + TBUF_CTRL); + reg |= TBUF_64B_EN; + HWREG32(eth->base + TBUF_CTRL) = reg; + + /* Enable 2-byte IP align (matches working raspi4 drv_eth, no 64B RSB). */ + reg = HWREG32(eth->base + RBUF_CTRL); + reg |= RBUF_ALIGN_2B; + reg &= ~RBUF_64B_EN; + HWREG32(eth->base + RBUF_CTRL) = reg; + + reg = HWREG32(eth->base + RBUF_CHK_CTRL); + reg |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS; + HWREG32(eth->base + RBUF_CHK_CTRL) = reg; + + HWREG32(eth->base + RBUF_TBUF_SIZE_CTRL) = 1; +} + +static void bcmgenet_gmac_write_hwaddr(struct bcmgenet_eth *eth) +{ + rt_uint32_t reg; + rt_uint8_t *addr = eth->mac; + + reg = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3]; + HWREG32(eth->base + UMAC_MAC0) = reg; + rt_hw_wmb(); + + reg = addr[4] << 8 | addr[5]; + HWREG32(eth->base + UMAC_MAC1) = reg; + rt_hw_wmb(); +} + +static void bcmgenet_disable_dma(struct bcmgenet_eth *eth) +{ + HWREGCLR32(eth->base + TDMA_REG_BASE + DMA_CTRL, DMA_EN); + HWREGCLR32(eth->base + RDMA_REG_BASE + DMA_CTRL, DMA_EN); + + HWREG32(eth->base + UMAC_TX_FLUSH) = 1; + rt_hw_us_delay(10); + HWREG32(eth->base + UMAC_TX_FLUSH) = 0; +} + +static void bcmgenet_enable_dma(struct bcmgenet_eth *eth) +{ + rt_uint32_t dma_ctrl = (1 << (DEFAULT_RING + DMA_RING_BUF_EN_SHIFT)) | DMA_EN; + + HWREG32(eth->base + TDMA_REG_BASE + DMA_CTRL) = dma_ctrl; + HWREGSET32(eth->base + RDMA_REG_BASE + DMA_CTRL, dma_ctrl); +} + +static void bcmgenet_rx_descs_init(struct bcmgenet_eth *eth) +{ + void *desc = eth->rx_desc_base; + rt_ubase_t rxbuffs_dma = eth->rxbuffer_dma; + rt_uint32_t len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN; + + for (int i = 0; i < RX_DESCS; ++i) + { + HWREG32(desc + DMA_DESC_ADDRESS_LO) = rt_lower_32_bits(rxbuffs_dma); + HWREG32(desc + DMA_DESC_ADDRESS_HI) = rt_upper_32_bits(rxbuffs_dma); + HWREG32(desc + DMA_DESC_LENGTH_STATUS) = len_stat; + + desc += DMA_DESC_SIZE; + rxbuffs_dma += RX_BUF_LENGTH; + } +} + +static void bcmgenet_rx_ring_init(struct bcmgenet_eth *eth) +{ + HWREG32(eth->base + RDMA_REG_BASE + DMA_SCB_BURST_SIZE) = DMA_MAX_BURST_LENGTH; + + HWREG32(eth->base + RDMA_RING_REG_BASE + DMA_START_ADDR) = 0x0; + HWREG32(eth->base + RDMA_READ_PTR) = 0x0; + HWREG32(eth->base + RDMA_WRITE_PTR) = 0x0; + HWREG32(eth->base + RDMA_RING_REG_BASE + DMA_END_ADDR) = RX_DESCS * DMA_DESC_SIZE / 4 - 1; + + HWREG32(eth->base + RDMA_PROD_INDEX) = 0; + HWREG32(eth->base + RDMA_CONS_INDEX) = 0; + eth->c_index = 0; + eth->rx_index = 0; + + HWREG32(eth->base + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE) = + (RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH; + HWREG32(eth->base + RDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH) = 0x1; + HWREG32(eth->base + RDMA_XON_XOFF_THRESH) = + (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) | DMA_FC_THRESH_HI; + HWREG32(eth->base + RDMA_REG_BASE + DMA_RING_CFG) = 1 << DEFAULT_RING; +} + +static void bcmgenet_tx_ring_init(struct bcmgenet_eth *eth) +{ + HWREG32(eth->base + TDMA_REG_BASE + DMA_SCB_BURST_SIZE) = DMA_MAX_BURST_LENGTH; + + HWREG32(eth->base + TDMA_RING_REG_BASE + DMA_START_ADDR) = 0x0; + HWREG32(eth->base + TDMA_READ_PTR) = 0x0; + HWREG32(eth->base + TDMA_WRITE_PTR) = 0x0; + HWREG32(eth->base + TDMA_RING_REG_BASE + DMA_END_ADDR) = TX_DESCS * DMA_DESC_SIZE / 4 - 1; + + HWREG32(eth->base + TDMA_PROD_INDEX) = 0; + HWREG32(eth->base + TDMA_CONS_INDEX) = 0; + eth->tx_index = 0; + + HWREG32(eth->base + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH) = 0x1; + HWREG32(eth->base + TDMA_FLOW_PERIOD) = 0x0; + HWREG32(eth->base + TDMA_RING_REG_BASE + DMA_RING_BUF_SIZE) = + (TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH; + + HWREG32(eth->base + TDMA_REG_BASE + DMA_RING_CFG) = 1 << DEFAULT_RING; +} + +static void bcmgenet_mii_config(struct bcmgenet_eth *eth) +{ + rt_uint32_t reg; + + HWREG32(eth->base + SYS_PORT_CTRL) = PORT_MODE_EXT_GPHY; + + reg = HWREG32(eth->base + EXT_RGMII_OOB_CTRL); + reg &= ~OOB_DISABLE; + reg &= ~ID_MODE_DIS; + if (eth->interface == RT_PHY_INTERFACE_MODE_RGMII) + reg |= ID_MODE_DIS; + reg |= RGMII_MODE_EN; + HWREG32(eth->base + EXT_RGMII_OOB_CTRL) = reg; +} + +static void bcmgenet_set_rx_mode(struct bcmgenet_eth *eth) +{ + /* Promiscuous: bypass MDF until full multicast/uc filter support. */ + HWREGSET32(eth->base + UMAC_CMD, CMD_PROMISC); + HWREG32(eth->base + UMAC_MDF_CTRL) = 0; +} + +static rt_err_t bcmgenet_adjust_link(struct bcmgenet_eth *eth, rt_bool_t link_up) +{ + rt_uint32_t reg, cmd_bits = 0; + struct rt_phy_device *phy = eth->phy; + + reg = HWREG32(eth->base + EXT_RGMII_OOB_CTRL); + if (link_up) + reg |= RGMII_LINK; + else + reg &= ~RGMII_LINK; + HWREG32(eth->base + EXT_RGMII_OOB_CTRL) = reg; + + if (!link_up) + return RT_EOK; + + switch (phy->speed) + { + case SPEED_1000: + cmd_bits = UMAC_SPEED_1000; + break; + + case SPEED_100: + cmd_bits = UMAC_SPEED_100; + break; + + case SPEED_10: + cmd_bits = UMAC_SPEED_10; + break; + + default: + LOG_E("Unsupported PHY speed: %d", phy->speed); + return -RT_EINVAL; + } + cmd_bits <<= CMD_SPEED_SHIFT; + + if (phy->duplex != DUPLEX_FULL) + cmd_bits |= CMD_HD_EN | CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE; + + reg = HWREG32(eth->base + UMAC_CMD); + reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) | + CMD_HD_EN | CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE); + reg |= cmd_bits; + reg |= CMD_TX_EN | CMD_RX_EN; + HWREG32(eth->base + UMAC_CMD) = reg; + + return RT_EOK; +} + +#ifdef RT_USING_SYSTEM_WORKQUEUE +static rt_bool_t bcmgenet_phy_poll_link(struct bcmgenet_eth *eth) +{ + int bmsr; + + bmsr = rt_phy_read(eth->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0) + { + return RT_FALSE; + } + + bmsr = rt_phy_read(eth->phy, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (!(bmsr & RT_BMSR_LSTATUS)) + { + eth->phy->link = 0; + return RT_FALSE; + } + + eth->phy->link = 1; + if (rt_genphy_parse_link(eth->phy)) + { + eth->phy->link = 0; + return RT_FALSE; + } + + return RT_TRUE; +} + +static void bcmgenet_phy_link_up(struct bcmgenet_eth *eth) +{ + if (bcmgenet_adjust_link(eth, RT_TRUE)) + { + LOG_E("Adjust PHY link failed"); + return; + } + + bcmgenet_set_rx_mode(eth); + LOG_I("Link up speed=%d duplex=%d", eth->phy->speed, eth->phy->duplex); + eth_device_linkchange(ð->parent, RT_TRUE); +} + +static void bcmgenet_phy_link_down(struct bcmgenet_eth *eth) +{ + eth->phy->link = 0; + + if (bcmgenet_adjust_link(eth, RT_FALSE)) + { + LOG_E("Adjust PHY link failed"); + return; + } + + LOG_W("Link down"); + eth_device_linkchange(ð->parent, RT_FALSE); +} + +static void bcmgenet_phy_retry_work(struct rt_work *work, void *work_data) +{ + struct bcmgenet_eth *eth = work_data; + + RT_UNUSED(work); + + if (eth->phy->link) + { + eth->phy_retry_count = 0; + return; + } + + if (bcmgenet_phy_poll_link(eth)) + { + eth->phy_retry_count = 0; + bcmgenet_phy_link_up(eth); + return; + } + + eth->phy_retry_count++; + if (eth->phy_retry_count < PHY_RETRY_MAX) + { + rt_work_submit(ð->phy_retry_work, + rt_tick_from_millisecond(PHY_RETRY_INTERVAL_MS)); + } + else + { + LOG_W("PHY link retry stopped, wait for link IRQ"); + eth->phy_retry_count = 0; + } +} + +static void bcmgenet_link_work(struct rt_work *work, void *work_data) +{ + struct bcmgenet_eth *eth = work_data; + rt_bool_t link_up; + + RT_UNUSED(work); + + link_up = bcmgenet_phy_poll_link(eth); + eth->phy_retry_count = 0; + + if (link_up) + { + bcmgenet_phy_link_up(eth); + } + else + { + bcmgenet_phy_link_down(eth); + } +} +#endif + +static struct pbuf *bcmgenet_eth_rx(rt_device_t dev); + +static void bcmgenet_enable_intr(struct bcmgenet_eth *eth) +{ + rt_uint32_t intr; + + /* Ring 16 (raspi4 drv_eth): TX/RX done on INTRL2_0 bits 16/13. */ + intr = UMAC_IRQ_LINK_EVENT; + intr |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR; + intr |= UMAC_IRQ_RXDMA_DONE | UMAC_IRQ_TXDMA_DONE; + HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_MASK_CLEAR) = intr; + +#if DEFAULT_RING <= 15 + intr = UMAC_IRQ1_TX_INTR(DEFAULT_RING) | UMAC_IRQ1_RX_INTR(DEFAULT_RING); + HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_MASK_CLEAR) = intr; +#endif +} + +static void bcmgenet_disable_intr(struct bcmgenet_eth *eth) +{ + HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_MASK_SET) = 0xffffffff; + HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_CLEAR) = 0xffffffff; + HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_MASK_SET) = 0xffffffff; + HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_CLEAR) = 0xffffffff; +} + +static rt_err_t bcmgenet_start(struct bcmgenet_eth *eth) +{ + rt_err_t err; + + eth->tx_desc_base = eth->base + GENET_TX_OFF; + eth->rx_desc_base = eth->base + GENET_RX_OFF; + + bcmgenet_umac_reset(eth); + + bcmgenet_gmac_write_hwaddr(eth); + + /* Disable RX/TX DMA and flush TX queues */ + bcmgenet_disable_dma(eth); + + bcmgenet_rx_ring_init(eth); + bcmgenet_rx_descs_init(eth); + + bcmgenet_tx_ring_init(eth); + + /* Enable RX/TX DMA */ + bcmgenet_enable_dma(eth); + + /* Sync RX ring indices with hardware (raspi4 drv_eth). */ + eth->c_index = HWREG32(eth->base + RDMA_PROD_INDEX) & DMA_P_INDEX_MASK; + eth->rx_index = eth->c_index % RX_DESCS; + HWREG32(eth->base + RDMA_CONS_INDEX) = eth->c_index; + HWREG32(eth->base + RDMA_PROD_INDEX) = eth->c_index; + + if ((err = rt_phy_config(eth->phy))) + { + LOG_E("PHY config failed: %s", rt_strerror(err)); + return err; + } + + if ((err = rt_phy_startup(eth->phy))) + { + LOG_E("PHY startup failed: %s", rt_strerror(err)); + return err; + } + + /* Update MAC registers based on PHY property */ + if ((err = bcmgenet_adjust_link(eth, eth->phy->link))) + { + LOG_E("Adjust PHY link failed: %s", rt_strerror(err)); + return err; + } + + /* Enable Rx/Tx */ + HWREGSET32(eth->base + UMAC_CMD, CMD_TX_EN | CMD_RX_EN); + + bcmgenet_set_rx_mode(eth); + bcmgenet_enable_intr(eth); + + LOG_I("Started: link=%d speed=%d duplex=%d", + eth->phy->link, eth->phy->speed, eth->phy->duplex); + + return RT_EOK; +} + +static void bcmgenet_stop(struct bcmgenet_eth *eth) +{ + HWREGCLR32(eth->base + UMAC_CMD, CMD_TX_EN | CMD_RX_EN); + + bcmgenet_disable_intr(eth); + + bcmgenet_disable_dma(eth); +} + +static void bcmgenet_rx_refill_desc(struct bcmgenet_eth *eth, void *desc, rt_ubase_t packet_dma) +{ + rt_uint32_t len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN; + + HWREG32(desc + DMA_DESC_ADDRESS_LO) = rt_lower_32_bits(packet_dma); + HWREG32(desc + DMA_DESC_ADDRESS_HI) = rt_upper_32_bits(packet_dma); + HWREG32(desc + DMA_DESC_LENGTH_STATUS) = len_stat; +} + +static void bcmgenet_tx_wait_done(struct bcmgenet_eth *eth, rt_uint32_t prod_index) +{ + rt_uint32_t cons; + rt_tick_t start = rt_tick_get(); + rt_tick_t limit = rt_tick_from_millisecond(50); + + while (rt_tick_get() - start < limit) + { + cons = HWREG32(eth->base + TDMA_CONS_INDEX) & 0xffff; + if (cons == prod_index) + { + return; + } + rt_thread_mdelay(1); + } + + if (rt_sem_take(ð->tx_done, rt_tick_from_millisecond(50)) == RT_EOK) + { + return; + } + + LOG_W("TX timeout prod=%u cons=%u", prod_index, + HWREG32(eth->base + TDMA_CONS_INDEX) & 0xffff); +} + +static rt_err_t bcmgenet_eth_tx(rt_device_t dev, struct pbuf *p) +{ + void *desc, *packet; + rt_ubase_t packet_dma; + rt_uint32_t len_stat, prod_index, cons_index, n; + struct bcmgenet_eth *eth = raw_to_bcmgenet_eth(dev); + + prod_index = HWREG32(eth->base + TDMA_PROD_INDEX) & 0xffff; + cons_index = HWREG32(eth->base + TDMA_CONS_INDEX) & 0xffff; + + for (n = 0; ((prod_index + 1) & 0xffff) == cons_index && n < 50; n++) + { + cons_index = HWREG32(eth->base + TDMA_CONS_INDEX) & 0xffff; + rt_thread_mdelay(1); + } + + if (((prod_index + 1) & 0xffff) == cons_index) + { + LOG_W("TX ring full prod=%u cons=%u", prod_index, cons_index); + return -RT_EBUSY; + } + + packet = eth->txbuffer + eth->tx_index * RX_BUF_LENGTH; + packet_dma = eth->txbuffer_dma + (packet - (void *)eth->txbuffer); + + rt_memset(packet, 0, GENET_TX_TSB_SIZE); + pbuf_copy_partial(p, packet + GENET_TX_TSB_SIZE, p->tot_len, 0); + + len_stat = (GENET_TX_TSB_SIZE + p->tot_len) << DMA_BUFLENGTH_SHIFT; + len_stat |= 0x3f << DMA_TX_QTAG_SHIFT; + len_stat |= DMA_TX_APPEND_CRC | DMA_SOP | DMA_EOP; + desc = eth->tx_desc_base + eth->tx_index * DMA_DESC_SIZE; + + HWREG32(desc + DMA_DESC_ADDRESS_LO) = rt_lower_32_bits(packet_dma); + HWREG32(desc + DMA_DESC_ADDRESS_HI) = rt_upper_32_bits(packet_dma); + HWREG32(desc + DMA_DESC_LENGTH_STATUS) = len_stat; + + if (++eth->tx_index >= TX_DESCS) + { + eth->tx_index = 0; + } + + prod_index = (prod_index + 1) & 0xffff; + HWREG32(eth->base + TDMA_PROD_INDEX) = prod_index; + + bcmgenet_tx_wait_done(eth, prod_index); + eth_device_ready(ð->parent); + + return RT_EOK; +} + +static struct pbuf *bcmgenet_eth_rx(rt_device_t dev) +{ + void *desc, *packet; + rt_uint64_t packet_dma; + rt_uint32_t prod_index, length, length_status; + struct pbuf *p = RT_NULL; + struct bcmgenet_eth *eth = raw_to_bcmgenet_eth(dev); + + prod_index = HWREG32(eth->base + RDMA_PROD_INDEX) & DMA_P_INDEX_MASK; + + HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_CLEAR) = + UMAC_IRQ_RXDMA_DONE; +#if DEFAULT_RING <= 15 + HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_CLEAR) = + UMAC_IRQ1_RX_INTR(DEFAULT_RING); +#endif + + if (prod_index == eth->c_index) + { + return RT_NULL; + } + + desc = eth->rx_desc_base + eth->rx_index * DMA_DESC_SIZE; + + rt_hw_rmb(); + length_status = HWREG32(desc + DMA_DESC_LENGTH_STATUS); + + length = (length_status >> DMA_BUFLENGTH_SHIFT) & DMA_BUFLENGTH_MASK; + + packet_dma = HWREG32(desc + DMA_DESC_ADDRESS_HI); + packet_dma <<= 32; + packet_dma |= HWREG32(desc + DMA_DESC_ADDRESS_LO); + packet = eth->rxbuffer + (packet_dma - eth->rxbuffer_dma); + + if (length <= RX_BUF_OFFSET) + { + goto _repost; + } + + packet += RX_BUF_OFFSET; + + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, packet, length); + + if (!(p = pbuf_alloc(PBUF_RAW, length, PBUF_RAM))) + { + goto _repost; + } + + rt_memcpy(p->payload, packet, length); + +_repost: + packet_dma = HWREG32(desc + DMA_DESC_ADDRESS_HI); + packet_dma <<= 32; + packet_dma |= HWREG32(desc + DMA_DESC_ADDRESS_LO); + + bcmgenet_rx_refill_desc(eth, desc, packet_dma); + + eth->c_index = (eth->c_index + 1) & 0xffff; + HWREG32(eth->base + RDMA_CONS_INDEX) = eth->c_index; + + if (++eth->rx_index >= RX_DESCS) + { + eth->rx_index = 0; + } + + return p; +} + +static rt_err_t bcmgenet_eth_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct bcmgenet_eth *eth = raw_to_bcmgenet_eth(dev); + + switch (cmd) + { + case NIOCTL_GADDR: + if (args) + { + rt_memcpy(args, eth->mac, sizeof(eth->mac)); + } + else + { + err = -RT_EINVAL; + } + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops bcmgenet_eth_ops = +{ + .control = bcmgenet_eth_control, +}; +#endif + +/* Handle Rx and Tx default queues + other stuff */ +static void bcmgenet_eth_isr0(int irq, void *param) +{ + rt_uint32_t status; + struct bcmgenet_eth *eth = param; + + /* Read irq status */ + status = HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_STAT) & + ~HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_MASK_STATUS); + + /* Clear interrupts */ + HWREG32(eth->base + GENET_INTRL2_0_OFF + INTRL2_CPU_CLEAR) = status; + + if (status & UMAC_IRQ_TXDMA_DONE) + { + rt_sem_release(ð->tx_done); + } + + if (status & UMAC_IRQ_RXDMA_DONE) + { + eth_device_ready(ð->parent); + } + + if (status & UMAC_IRQ_RBUF_OVERFLOW) + { + LOG_W("RX buffer overflow"); + } + + status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_PHY_DET_R); + if (status & UMAC_IRQ_LINK_EVENT) + { +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_submit(ð->link_work, 0); +#endif + } +} + +/* Handle Rx and Tx priority queues */ +static void bcmgenet_eth_isr1(int irq, void *param) +{ + rt_uint32_t status; + struct bcmgenet_eth *eth = param; + + /* Read irq status */ + status = HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_STAT) & + ~HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_MASK_STATUS); + + /* Clear interrupts */ + HWREG32(eth->base + GENET_INTRL2_1_OFF + INTRL2_CPU_CLEAR) = status; + +#if DEFAULT_RING <= 15 + if (status & UMAC_IRQ1_TX_INTR(DEFAULT_RING)) + { + rt_sem_release(ð->tx_done); + } +#endif + +#if DEFAULT_RING <= 15 + if (status & UMAC_IRQ1_RX_INTR(DEFAULT_RING)) + { + eth_device_ready(ð->parent); + } +#endif +} + +static rt_err_t bcmgenet_eth_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t value; + struct mii_bus *bus; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *mdio_np, *phy_np, *fw_np; + struct bcmgenet_eth *eth = rt_calloc(1, sizeof(*eth)); + + if (!eth) + { + return -RT_ENOMEM; + } + + eth->dev = dev; + eth->dma_buf_size = RX_TOTAL_BUFSIZE + TX_TOTAL_BUFSIZE; + + if (!(eth->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + value = HWREG32(eth->base + SYS_REV_CTRL); + value = (value >> 24) & 0x0f; + + if (value != 6) + { + if (value == 5) + { + value = 4; + } + else if (value == 0) + { + value = 1; + } + + LOG_E("Unsupported GENETv%d.%d", + value, (HWREG32(eth->base + SYS_REV_CTRL) >> 16) & 0x0f); + + err = -RT_ENOSYS; + goto _fail; + } + + if ((eth->irq0 = rt_dm_dev_get_irq(dev, 0)) < 0) + { + err = eth->irq0; + goto _fail; + } + + if ((eth->irq1 = rt_dm_dev_get_irq(dev, 1)) < 0) + { + err = eth->irq1; + goto _fail; + } + + /* For PHY & MDIO */ + mdio_np = rt_ofw_get_child_by_tag(np, "mdio"); + rt_platform_ofw_device_probe_child(mdio_np); + rt_ofw_node_put(mdio_np); + + if (!(bus = rt_mdio_get_bus_by_name("unimac MII bus"))) + { + err = -RT_ENOSYS; + goto _fail; + } + + if (!(phy_np = rt_ofw_parse_phandle(np, "phy-handle", 0))) + { + err = -RT_EINVAL; + goto _fail; + } + + if (rt_ofw_prop_read_u32(phy_np, "reg", &value)) + { + rt_ofw_node_put(phy_np); + err = -RT_EINVAL; + goto _fail; + } + + if (!(eth->phy = rt_phy_find_by_mask(bus, 1 << value))) + { + rt_ofw_node_put(phy_np); + err = -RT_ENOSYS; + goto _fail; + } + + eth->phy_np = phy_np; + eth->phy->node = phy_np; + + rt_ofw_get_interface(np, ð->interface); + eth->phy->interface = eth->interface; + + switch (eth->interface) + { + case RT_PHY_INTERFACE_MODE_RGMII: + case RT_PHY_INTERFACE_MODE_RGMII_RXID: + break; + + default: + LOG_E("Unknown PHY mode: %d", eth->interface); + err = -RT_ENOSYS; + goto _fail; + } + + bcmgenet_mii_config(eth); + + HWREG32(eth->base + SYS_RBUF_FLUSH_CTRL) = 0; + rt_hw_us_delay(10); + /* Disable MAC while updating its registers */ + HWREG32(eth->base + UMAC_CMD) = 0; + /* Issue soft reset with (rg)mii loopback to ensure a stable rxclk */ + HWREG32(eth->base + UMAC_CMD) = CMD_SW_RESET | CMD_LCL_LOOP_EN; + + /* Connect PHY */ + if (!rt_dm_dev_prop_read_u32(dev, "max-speed", ð->speed)) + { + if ((err = rt_phy_set_supported(eth->phy, eth->speed))) + { + goto _fail; + } + } + + /* PHY config/startup deferred until MAC rings are ready in bcmgenet_start() */ + + /* For MAC address */ + if ((fw_np = rpi_firmware_find_node())) + { + struct rpi_firmware *rpi_fw = rpi_firmware_get(fw_np); + + err = rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS, + eth->mac, sizeof(eth->mac)); + + rt_ofw_node_put(fw_np); + rpi_firmware_put(rpi_fw); + } + + if ((!fw_np || err) && (err = rt_ofw_get_mac_addr(np, eth->mac))) + { + goto _fail; + } + + if (!(eth->rxbuffer = rt_dma_alloc_coherent(dev, eth->dma_buf_size, ð->rxbuffer_dma))) + { + err = -RT_ENOMEM; + goto _fail; + } + eth->txbuffer = eth->rxbuffer + RX_TOTAL_BUFSIZE; + eth->txbuffer_dma = eth->rxbuffer_dma + RX_TOTAL_BUFSIZE; + + rt_sem_init(ð->tx_done, "genet_tx", 0, RT_IPC_FLAG_FIFO); + + if ((err = bcmgenet_start(eth))) + { + goto _fail; + } + +#ifdef RT_USING_DEVICE_OPS + eth->parent.parent.ops = &bcmgenet_eth_ops; +#else + eth->parent.parent.control = bcmgenet_eth_control; +#endif + eth->parent.eth_tx = bcmgenet_eth_tx; + eth->parent.eth_rx = bcmgenet_eth_rx; + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_init(ð->link_work, bcmgenet_link_work, eth); + rt_work_init(ð->phy_retry_work, bcmgenet_phy_retry_work, eth); +#endif + + dev->user_data = eth; + + if ((err = rt_dm_dev_set_name_auto(ð->parent.parent, "e")) < 0) + { + goto _stop; + } + + if ((err = eth_device_init(ð->parent, rt_dm_dev_get_name(ð->parent.parent)))) + { + goto _stop; + } + + rt_hw_interrupt_install(eth->irq0, bcmgenet_eth_isr0, eth, "bcmgenet0"); + rt_hw_interrupt_umask(eth->irq0); + + rt_hw_interrupt_install(eth->irq1, bcmgenet_eth_isr1, eth, "bcmgenet1"); + rt_hw_interrupt_umask(eth->irq1); + + if (eth->phy->link) + { + eth_device_linkchange(ð->parent, RT_TRUE); + } + else + { +#ifdef RT_USING_SYSTEM_WORKQUEUE + eth->phy_retry_count = 0; + rt_work_submit(ð->phy_retry_work, + rt_tick_from_millisecond(PHY_RETRY_INTERVAL_MS)); +#endif + } + + return RT_EOK; + +_stop: + bcmgenet_stop(eth); + rt_sem_detach(ð->tx_done); + +_fail: + if (eth && eth->phy_np) + { + rt_ofw_node_put(eth->phy_np); + } + + if (eth && eth->base) + { + rt_iounmap(eth->base); + } + + if (eth->rxbuffer) + { + rt_dma_free_coherent(eth->dev, eth->dma_buf_size, + eth->rxbuffer, eth->rxbuffer_dma); + } + + rt_free(eth); + + return err; +} + +static rt_err_t bcmgenet_eth_remove(struct rt_platform_device *pdev) +{ + struct bcmgenet_eth *eth = pdev->parent.user_data; + + eth_device_linkchange(ð->parent, RT_FALSE); + eth_device_deinit(ð->parent); + +#ifdef RT_USING_SYSTEM_WORKQUEUE + rt_work_cancel(ð->link_work); + rt_work_cancel(ð->phy_retry_work); +#endif + + rt_sem_detach(ð->tx_done); + bcmgenet_stop(eth); + + rt_hw_interrupt_mask(eth->irq0); + rt_pic_detach_irq(eth->irq0, eth); + + rt_hw_interrupt_mask(eth->irq1); + rt_pic_detach_irq(eth->irq1, eth); + + if (eth->phy_np) + { + rt_ofw_node_put(eth->phy_np); + } + + rt_dma_free_coherent(eth->dev, eth->dma_buf_size, eth->rxbuffer, eth->rxbuffer_dma); + + rt_free(eth); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcmgenet_eth_ofw_ids[] = +{ + { .compatible = "brcm,genet-v5" }, + { .compatible = "brcm,bcm2711-genet-v5" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcmgenet_eth_driver = +{ + .name = "eth-bcmgenet", + .ids = bcmgenet_eth_ofw_ids, + + .probe = bcmgenet_eth_probe, + .remove = bcmgenet_eth_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcmgenet_eth_driver); diff --git a/bsp/raspberry-pi/dm/firmware/Kconfig b/bsp/raspberry-pi/dm/firmware/Kconfig new file mode 100755 index 0000000000..33ccccceb8 --- /dev/null +++ b/bsp/raspberry-pi/dm/firmware/Kconfig @@ -0,0 +1,6 @@ +config RT_FIRMWARE_RASPBERRYPI + bool "Raspberrypi Firmware" + depends on RT_USING_OFW + depends on RT_USING_MBOX + depends on RT_USING_DMA + default n diff --git a/bsp/raspberry-pi/dm/firmware/SConscript b/bsp/raspberry-pi/dm/firmware/SConscript new file mode 100755 index 0000000000..64797072ab --- /dev/null +++ b/bsp/raspberry-pi/dm/firmware/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_FIRMWARE_RASPBERRYPI']): + src += ['firmware-raspberrypi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/firmware/firmware-raspberrypi.c b/bsp/raspberry-pi/dm/firmware/firmware-raspberrypi.c new file mode 100755 index 0000000000..95130886af --- /dev/null +++ b/bsp/raspberry-pi/dm/firmware/firmware-raspberrypi.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "fw.raspberrypi" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) +#define MBOX_CHAN(msg) ((msg) & 0xf) +#define MBOX_DATA28(msg) ((msg) & ~0xf) +#define MBOX_CHAN_PROPERTY 8 + +struct rpi_firmware +{ + struct rt_mbox_client parent; + + /* The property channel. */ + struct rt_mbox_chan *chan; + rt_bool_t done; + rt_uint32_t enabled; + + struct rt_ref consumers; + rt_uint32_t get_throttled; + + struct rt_spinlock transaction_lock; +}; + +static struct rt_device *rpi_firmware_dma_dev(struct rpi_firmware *rpi_fw) +{ + if (rpi_fw && rpi_fw->chan && rpi_fw->chan->ctrl && rpi_fw->chan->ctrl->dev) + { + return rpi_fw->chan->ctrl->dev; + } + + return rpi_fw ? rpi_fw->parent.dev : RT_NULL; +} + +static rt_err_t rpi_firmware_transaction(struct rpi_firmware *rpi_fw, + rt_uint32_t chan, rt_uint32_t data) +{ + rt_ssize_t res; + rt_uint32_t message = MBOX_MSG(chan, data); + + rt_hw_spin_lock(&rpi_fw->transaction_lock.lock); + + rpi_fw->done = RT_FALSE; + res = rt_mbox_send(rpi_fw->chan, &message, RT_WAITING_FOREVER); + + rt_hw_rmb(); + + if (res == RT_EOK) + { + if (!rpi_fw->done) + { + res = -RT_ETIMEOUT; + LOG_W("Firmware transaction timeout"); + } + } + else if (res == -RT_ETIMEOUT && rpi_fw->done) + { + res = RT_EOK; + } + else if (res == -RT_ETIMEOUT) + { + LOG_W("Firmware transaction timeout"); + } + else + { + LOG_E("Mailbox send message error = %s", rt_strerror(res)); + } + + rt_hw_spin_unlock(&rpi_fw->transaction_lock.lock); + + return res; +} + +/* RPI made the F*CKING hardware so I written the F*CKING code:) */ +void *rpi_firmware_property_raw_alloc(struct rpi_firmware *rpi_fw, + rt_size_t max_header_tag_size, rt_ubase_t *out_bus_addr) +{ + void *buf; + rt_size_t size = max_header_tag_size + 12; + + buf = rt_dma_alloc_coherent(rpi_firmware_dma_dev(rpi_fw), + RT_ALIGN(size, ARCH_PAGE_SIZE), out_bus_addr); + + return buf ? buf + 8 : RT_NULL; +} + +void rpi_firmware_property_raw_free(struct rpi_firmware *rpi_fw, + rt_size_t max_header_tag_size, void *buf, rt_ubase_t bus_addr) +{ + rt_size_t size = max_header_tag_size + 12; + + rt_dma_free_coherent(rpi_firmware_dma_dev(rpi_fw), + RT_ALIGN(size, ARCH_PAGE_SIZE), buf - 8, bus_addr); +} + +rt_err_t rpi_firmware_property(struct rpi_firmware *rpi_fw, + rt_uint32_t tag, void *tag_data, rt_size_t buf_size) +{ + rt_err_t err; + void *buf; + rt_ubase_t bus_addr; + rt_size_t max_size; + struct rpi_firmware_property_tag_header *header; + + max_size = sizeof(*header) + buf_size; + buf = rpi_firmware_property_raw_alloc(rpi_fw, max_size, &bus_addr); + + if (!buf) + { + return -RT_ENOMEM; + } + + rt_memcpy(buf + sizeof(*header), tag_data, buf_size); + err = rpi_firmware_property_raw(rpi_fw, tag, bus_addr, buf, max_size); + + if (!err) + { + rt_memcpy(tag_data, buf + sizeof(*header), buf_size); + } + + rpi_firmware_property_raw_free(rpi_fw, max_size, buf, bus_addr); + + return err; +} + +rt_err_t rpi_firmware_property_raw(struct rpi_firmware *rpi_fw, rt_uint32_t tag, + rt_ubase_t bus_addr, struct rpi_firmware_property_tag_header *header, rt_size_t req_size) +{ + header->tag = tag; + header->buf_size = req_size - sizeof(*header); + header->req_resp_size = 0; + + return rpi_firmware_property_list_raw(rpi_fw, bus_addr, (void *)header, req_size); +} + +rt_err_t rpi_firmware_property_list(struct rpi_firmware *rpi_fw, + void *data, rt_size_t tag_size) +{ + rt_err_t err; + rt_ubase_t bus_addr; + void *buf = rpi_firmware_property_raw_alloc(rpi_fw, tag_size, &bus_addr); + + if (!buf) + { + return -RT_ENOMEM; + } + + rt_memcpy(buf, data, tag_size); + + if (!(err = rpi_firmware_property_list_raw(rpi_fw, bus_addr, buf, tag_size))) + { + rt_memcpy(data, buf, tag_size); + } + + rpi_firmware_property_raw_free(rpi_fw, tag_size, buf, bus_addr); + + return err; +} + +rt_err_t rpi_firmware_property_list_raw(struct rpi_firmware *rpi_fw, + rt_ubase_t bus_addr, void *data, rt_size_t tag_size) +{ + rt_err_t err; + rt_uint32_t *buf = data - 8; + rt_size_t size = tag_size + 12; + + /* Packets are processed a dword at a time. */ + if (size & 3) + { + return -RT_EINVAL; + } + + buf[0] = size; + buf[1] = RPI_FIRMWARE_STATUS_REQUEST; + buf[size / 4 - 1] = RPI_FIRMWARE_PROPERTY_END; + rt_hw_wmb(); + + err = rpi_firmware_transaction(rpi_fw, MBOX_CHAN_PROPERTY, bus_addr); + + rt_hw_rmb(); + + if (err == RT_EOK && !(buf[1] & RPI_FIRMWARE_STATUS_SUCCESS)) + { + /* + * The tag name here might not be the one causing the + * error, if there were multiple tags in the request. + * But single-tag is the most common, so go with it. + */ + LOG_E("Request 0x%08x returned status 0x%08x", buf[2], buf[1]); + err = -RT_EINVAL; + } + else if (err == RT_EOK && buf[1] == RPI_FIRMWARE_STATUS_ERROR) + { + LOG_E("Request 0x%08x returned error status 0x%08x", buf[2], buf[1]); + err = -RT_EINVAL; + } + + return err; +} + +rt_uint32_t rpi_firmware_clk_get_max_rate(struct rpi_firmware *rpi_fw, rt_uint32_t id) +{ + struct rpi_firmware_clk_rate_request msg = RPI_FIRMWARE_CLK_RATE_REQUEST(id); + + if (rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + &msg, sizeof(msg))) + { + return RT_UINT32_MAX; + } + + return rt_le32_to_cpu(msg.rate); +} + +static const struct rt_ofw_node_id rpi_firmware_ofw_ids[]; + +struct rt_ofw_node *rpi_firmware_find_node(void) +{ + return rt_ofw_find_node_by_ids(RT_NULL, rpi_firmware_ofw_ids); +} + +struct rpi_firmware *rpi_firmware_get(struct rt_ofw_node *fw_np) +{ + struct rpi_firmware *rpi_fw = rt_ofw_data(fw_np); + + if (!rpi_fw) + { + rt_platform_ofw_request(fw_np); + rpi_fw = rt_ofw_data(fw_np); + } + + if (!rpi_fw) + { + return RT_NULL; + } + + if (!rt_ref_get_unless_zero(&rpi_fw->consumers)) + { + return RT_NULL; + } + + return rpi_fw; +} + +static void rpi_firmware_release(struct rt_ref *ref) +{ + struct rpi_firmware *rpi_fw = rt_container_of(ref, struct rpi_firmware, consumers); + + rt_mbox_release(rpi_fw->chan); + rt_free(rpi_fw); +} + +void rpi_firmware_put(struct rpi_firmware *rpi_fw) +{ + rt_ref_put(&rpi_fw->consumers, rpi_firmware_release); +} + +static rt_err_t rpi_firmware_notify_reboot(struct rt_device *dev, char *cmd) +{ + rt_uint32_t reboot_flags = 0; + struct rpi_firmware *rpi_fw = dev->user_data; + + if (cmd && rt_strstr(cmd, "tryboot")) + { + reboot_flags |= 0x1; + } + + if (reboot_flags) + { + rpi_firmware_property(rpi_fw, RPI_FIRMWARE_SET_REBOOT_FLAGS, + &reboot_flags, sizeof(reboot_flags)); + } + + rpi_firmware_property(rpi_fw, RPI_FIRMWARE_NOTIFY_REBOOT, RT_NULL, 0); + + return RT_EOK; +} + +static void rpi_firmware_rx_callback(struct rt_mbox_client *client, void *data) +{ + struct rpi_firmware *rpi_fw = rt_container_of(client, struct rpi_firmware, parent); + + rpi_fw->done = RT_TRUE; + rt_hw_wmb(); +} + +static void rpi_firmware_check_revision_info(struct rpi_firmware *rpi_fw) +{ + struct tm *tm; + rt_uint32_t revision, variant, hash[5]; + static const char * const variant_strs[] = + { + "unknown", + "start", + "start_x", + "start_db", + "start_cd", + }; + const char *variant_str = "cmd unsupported"; + + if (rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_FIRMWARE_REVISION, + &revision, sizeof(revision))) + { + goto _check_hash; + } + + tm = localtime((time_t *)&revision); + + if (!rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT, + &variant, sizeof(variant))) + { + if (variant >= RT_ARRAY_SIZE(variant_strs)) + { + variant = 0; + } + + variant_str = variant_strs[variant]; + } + + LOG_I("Attached to firmware from %04d-%02d-%02d %02d:%02d:%02d, variant %s", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, variant_str); + (void)tm; + (void)variant_str; + +_check_hash: + if (rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_FIRMWARE_HASH, + hash, sizeof(hash))) + { + return; + } + + LOG_I("Firmware hash is %08x%08x%08x%08x%08x", + hash[0], hash[1], hash[2], hash[3], hash[4]); +} + +static rt_err_t rpi_firmware_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t packet; + struct rt_device *dev = &pdev->parent; + struct rpi_firmware *rpi_fw = rt_calloc(1, sizeof(*rpi_fw)); + + if (!rpi_fw) + { + return -RT_ENOMEM; + } + + dev->user_data = rpi_fw; + rpi_fw->parent.dev = dev; + rpi_fw->parent.rx_callback = rpi_firmware_rx_callback; + + rpi_fw->chan = rt_mbox_request_by_index(&rpi_fw->parent, 0); + + if (rt_is_err_or_null(rpi_fw->chan)) + { + err = -RT_EINVAL; + LOG_E("Request mailbox fail"); + + goto _fail; + } + + if ((err = rt_dm_reboot_mode_register(dev, &rpi_firmware_notify_reboot))) + { + goto _fail; + } + + rt_ref_init(&rpi_fw->consumers); + rt_spin_lock_init(&rpi_fw->transaction_lock); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, rpi_fw); + + rpi_firmware_check_revision_info(rpi_fw); + + if (!rpi_firmware_property(rpi_fw, RPI_FIRMWARE_GET_THROTTLED, + &packet, sizeof(packet))) + { + struct rt_platform_device *voltage_monitor; + + if (!(voltage_monitor = rt_calloc(1, sizeof(*voltage_monitor)))) + { + LOG_E("No memory to create voltage monitor"); + + err = -RT_ENOMEM; + goto _fail; + } + + voltage_monitor->name = "raspberrypi-voltage-monitor"; + voltage_monitor->priv = dev; + + rt_bus_add_device(pdev->parent.bus, &voltage_monitor->parent); + } + + return RT_EOK; + +_fail: + if (!rt_is_err_or_null(rpi_fw->chan)) + { + rt_mbox_release(rpi_fw->chan); + } + + rt_free(rpi_fw); + + return err; +} + +static rt_err_t rpi_firmware_shutdown(struct rt_platform_device *pdev) +{ + struct rpi_firmware *rpi_fw = pdev->parent.user_data; + + rpi_firmware_property(rpi_fw, RPI_FIRMWARE_NOTIFY_REBOOT, RT_NULL, 0); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rpi_firmware_ofw_ids[] = +{ + { .compatible = "raspberrypi,bcm2835-firmware", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_firmware_driver = +{ + .name = "raspberrypi-firmware", + .ids = rpi_firmware_ofw_ids, + + .probe = rpi_firmware_probe, + .shutdown = rpi_firmware_shutdown, +}; + +static int rpi_firmware_drv_register(void) +{ + rt_platform_driver_register(&rpi_firmware_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rpi_firmware_drv_register); diff --git a/bsp/raspberry-pi/dm/graphic/SConscript b/bsp/raspberry-pi/dm/graphic/SConscript new file mode 100755 index 0000000000..3d15055d62 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/raspberry-pi/dm/graphic/backlight/Kconfig b/bsp/raspberry-pi/dm/graphic/backlight/Kconfig new file mode 100755 index 0000000000..d29076aaf5 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/backlight/Kconfig @@ -0,0 +1,5 @@ +config RT_GRAPHIC_BACKLIGHT_RPI + bool "Raspberry Pi display firmware driven backlight" + depends on RT_GRAPHIC_BACKLIGHT + depends on RT_FIRMWARE_RASPBERRYPI + default n diff --git a/bsp/raspberry-pi/dm/graphic/backlight/SConscript b/bsp/raspberry-pi/dm/graphic/backlight/SConscript new file mode 100755 index 0000000000..2a29615ad7 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/backlight/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_GRAPHIC_BACKLIGHT_RPI']): + src += ['backlight-rpi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/graphic/backlight/backlight-rpi.c b/bsp/raspberry-pi/dm/graphic/backlight/backlight-rpi.c new file mode 100755 index 0000000000..438e7d85f7 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/backlight/backlight-rpi.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "video.backlight.rpi" +#define DBG_LVL DBG_INFO +#include + +#include + +struct rpi_backlight +{ + struct rt_backlight_device parent; + + struct rpi_firmware *rpi_fw; +}; + +#define raw_to_rpi_backlight(raw) rt_container_of(raw, struct rpi_backlight, parent) + +static rt_err_t rpi_backlight_update_status(struct rt_backlight_device *bl) +{ + rt_err_t err; + struct rpi_backlight *rbl = raw_to_rpi_backlight(bl); + rt_uint32_t brightness = bl->props.brightness; + + if (bl->props.power != RT_BACKLIGHT_POWER_UNBLANK) + { + brightness = 0; + } + + err = rpi_firmware_property(rbl->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT, &brightness, sizeof(brightness)); + + if (err) + { + LOG_E("Failed to set brightness"); + + return err; + } + + if ((int)brightness < 0) + { + LOG_E("Backlight change failed"); + + return -RT_ERROR; + } + + return RT_EOK; +} + +static struct rt_backlight_ops rpi_backlight_ops = +{ + .update_status = rpi_backlight_update_status, +}; + +static rt_err_t rpi_backlight_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct rpi_firmware *rpi_fw; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_backlight *rbl = rt_calloc(1, sizeof(*rbl)); + + if (!rbl) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + dev->user_data = rbl; + + rbl->rpi_fw = rpi_fw; + rbl->parent.props.max_brightness = 255; + rbl->parent.ops = &rpi_backlight_ops; + + if ((err = rt_backlight_register(&rbl->parent))) + { + goto _fail; + } + + rt_backlight_set_brightness(&rbl->parent, 255); + + return RT_EOK; + +_fail: + if (rbl->rpi_fw) + { + rpi_firmware_put(rbl->rpi_fw); + } + + rt_free(rbl); + + return err; +} + +static rt_err_t rpi_backlight_remove(struct rt_platform_device *pdev) +{ + struct rpi_backlight *rbl = pdev->parent.user_data; + + rt_backlight_unregister(&rbl->parent); + + rpi_firmware_put(rbl->rpi_fw); + rt_free(rbl); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rpi_backlight_ofw_ids[] = +{ + { .compatible = "raspberrypi,rpi-backlight" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_backlight_driver = +{ + .name = "rpi-backlight", + .ids = rpi_backlight_ofw_ids, + + .probe = rpi_backlight_probe, + .remove = rpi_backlight_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpi_backlight_driver); diff --git a/bsp/raspberry-pi/dm/graphic/framebuffer/Kconfig b/bsp/raspberry-pi/dm/graphic/framebuffer/Kconfig new file mode 100755 index 0000000000..40c7d9e691 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/framebuffer/Kconfig @@ -0,0 +1,9 @@ +config RT_GRAPHIC_FB_BCM2708 + bool "BCM2708 framebuffer support" + depends on RT_FIRMWARE_RASPBERRYPI + default n + +config RT_GRAPHIC_FB_RPISENSE + bool "Raspberry Pi Sense HAT framebuffer" + depends on RT_MFD_RPI_SENSE + default n diff --git a/bsp/raspberry-pi/dm/graphic/framebuffer/SConscript b/bsp/raspberry-pi/dm/graphic/framebuffer/SConscript new file mode 100755 index 0000000000..d1329b7f90 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/framebuffer/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_GRAPHIC_FB_BCM2708']): + src += ['fb-bcm2708.c'] + +if GetDepend(['RT_GRAPHIC_FB_RPISENSE']): + src += ['fb-rpisense.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/graphic/framebuffer/fb-bcm2708.c b/bsp/raspberry-pi/dm/graphic/framebuffer/fb-bcm2708.c new file mode 100755 index 0000000000..90d282073c --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/framebuffer/fb-bcm2708.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "fb.bcm2708" +#define DBG_LVL DBG_INFO +#include + +#include + +#define MAX_FRAMEBUFFERS 3 +#define FRAMEBUFFER_ALIGNMENT 4096 + +struct fb_alloc_tags +{ + struct rpi_firmware_property_tag_header tag1; + rt_uint32_t xres, yres; + + struct rpi_firmware_property_tag_header tag2; + rt_uint32_t xres_virtual, yres_virtual; + + struct rpi_firmware_property_tag_header tag3; + rt_uint32_t bpp; + + struct rpi_firmware_property_tag_header tag4; + rt_uint32_t xoffset, yoffset; + + struct rpi_firmware_property_tag_header tag5; + rt_uint32_t base, screen_size; + + struct rpi_firmware_property_tag_header tag6; + rt_uint32_t pitch; +}; + +struct vc4_display_settings +{ + rt_uint32_t display_num; + rt_uint32_t width; + rt_uint32_t height; + rt_uint32_t depth; + rt_uint32_t pitch; + rt_uint32_t virtual_width; + rt_uint32_t virtual_height; + rt_uint32_t virtual_width_offset; + rt_uint32_t virtual_height_offset; + rt_ubase_t fb_bus_address; +}; + +struct bcm2708fb; + +struct bcm2708fb_display +{ + struct rt_graphic_device parent; + + struct bcm2708fb *fb; + + void *framebuffer; + rt_ubase_t framebuffer_dma; + rt_size_t framebuffer_size; + rt_size_t stride; + + struct vc4_display_settings display_settings; + struct { rt_uint32_t base, length; } gpu_mem; +}; + +struct bcm2708fb +{ + struct rpi_firmware *rpi_fw; + + struct bcm2708fb_display displays[MAX_FRAMEBUFFERS]; +}; + +static rt_err_t bcm2708fb_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + struct bcm2708fb_display *display; + + display = rt_container_of(plane->graphic, struct bcm2708fb_display, parent); + + plane->line_length = display->stride; + plane->bits_per_pixel = rt_graphic_mode_bpp(mode); + + plane->framebuffer = display->framebuffer; + plane->screen_len = display->framebuffer_size; + plane->framebuffer_len = display->framebuffer_size; + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops bcm2708fb_plane_ops = +{ + .fb_remap = bcm2708fb_plane_fb_remap, +}; + +static rt_err_t bcm2708fb_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms) +{ + rt_err_t err; + rt_uint32_t value; + struct bcm2708fb_display *display; + + display = rt_container_of(gdev, struct bcm2708fb_display, parent); + value = display->display_settings.display_num; + + if ((err = rpi_firmware_property(display->fb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, &value, sizeof(value)))) + { + return err; + } + + switch (dpms) + { + case RT_GRAPHIC_DPMS_ON: + value = 0; + break; + + case RT_GRAPHIC_DPMS_STANDBY: + case RT_GRAPHIC_DPMS_SUSPEND: + case RT_GRAPHIC_DPMS_OFF: + value = 1; + break; + } + + return rpi_firmware_property(display->fb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_BLANK, &value, sizeof(value)); +} + +static rt_err_t bcm2708fb_wait_vsync(struct rt_graphic_device *gdev) +{ + rt_err_t err; + rt_uint32_t value; + struct bcm2708fb_display *display; + + display = rt_container_of(gdev, struct bcm2708fb_display, parent); + value = display->display_settings.display_num; + + if ((err = rpi_firmware_property(display->fb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, &value, sizeof(value)))) + { + return err; + } + + return rpi_firmware_property(display->fb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC, &value, sizeof(value)); +} + +static struct rt_graphic_device_ops bcm2708fb_ops = +{ + .dpms_switch = bcm2708fb_dpms_switch, + .wait_vsync = bcm2708fb_wait_vsync, +}; + +static rt_uint32_t bcm2708fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_RGB565, + RTGRAPHIC_PIXEL_FORMAT_BGR888, + RTGRAPHIC_PIXEL_FORMAT_ABGR888, +}; + +static rt_err_t bcm2708fb_firmware_alloc(struct rpi_firmware *rpi_fw, + struct bcm2708fb_display *display, rt_uint32_t depth, + struct fb_alloc_tags *fbinfo) +{ + rt_err_t err; + + rt_memset(fbinfo, 0, sizeof(*fbinfo)); + + fbinfo->tag1 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, 8, 0, + }; + fbinfo->xres = display->display_settings.width; + fbinfo->yres = display->display_settings.height; + fbinfo->tag2 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, 8, 0, + }; + fbinfo->xres_virtual = display->display_settings.virtual_width; + fbinfo->yres_virtual = display->display_settings.virtual_height; + fbinfo->tag3 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0, + }; + fbinfo->bpp = depth; + fbinfo->tag4 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0, + }; + fbinfo->xoffset = display->display_settings.virtual_width_offset; + fbinfo->yoffset = display->display_settings.virtual_height_offset; + fbinfo->tag5 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0, + }; + fbinfo->base = FRAMEBUFFER_ALIGNMENT; + fbinfo->tag6 = (struct rpi_firmware_property_tag_header) + { + RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH, 4, 0, + }; + + err = rpi_firmware_property_list(rpi_fw, fbinfo, sizeof(*fbinfo)); + + if (!err && (!fbinfo->base || !fbinfo->screen_size || !fbinfo->pitch)) + { + err = -RT_ENOMEM; + } + + if (!err && (fbinfo->bpp != depth || + fbinfo->pitch < (fbinfo->xres_virtual * depth) / 8)) + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t bcm2708fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t num_displays; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct { rt_uint32_t base, length; } gpu_mem; + struct bcm2708fb *bfb = rt_calloc(1, sizeof(*bfb)); + + if (!bfb) + { + LOG_E("No memory for framebuffer state"); + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + LOG_E("Missing firmware phandle"); + err = -RT_EINVAL; + goto _fail; + } + + bfb->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!bfb->rpi_fw) + { + LOG_E("Raspberry Pi firmware is unavailable"); + err = -RT_EINVAL; + goto _fail; + } + + err = rpi_firmware_property(bfb->rpi_fw, RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, + &num_displays, sizeof(num_displays)); + + if (err) + { + LOG_E("GET_NUM_DISPLAYS failed: %s", rt_strerror(err)); + goto _fail; + } + + if (num_displays == 0) + { + LOG_E("Firmware reported no displays"); + err = -RT_EINVAL; + goto _fail; + } + + num_displays = rt_min_t(rt_uint32_t, num_displays, MAX_FRAMEBUFFERS); + LOG_I("Firmware reported %u display(s)", num_displays); + + rpi_firmware_property(bfb->rpi_fw, RPI_FIRMWARE_GET_VC_MEMORY, + &gpu_mem, sizeof(gpu_mem)); + + rt_uint32_t num_registered = 0; + + for (int i = 0; i < num_displays; ++i) + { + rt_uint32_t midx, value, requested_depth, effective_depth, stride_width; + struct fb_alloc_tags fbinfo; + struct bcm2708fb_display *display = &bfb->displays[i]; + + display->display_settings.display_num = i; + + err = rpi_firmware_property(bfb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS, + &display->display_settings, GET_DISPLAY_SETTINGS_PAYLOAD_SIZE); + + if (err) + { + goto _display_fail; + } + + if (!display->display_settings.width) + { + display->display_settings.width = 800; + display->display_settings.height = 480; + display->display_settings.depth = 32; + } + + if (!display->display_settings.virtual_width) + { + display->display_settings.virtual_width = display->display_settings.width; + } + + if (!display->display_settings.virtual_height) + { + display->display_settings.virtual_height = display->display_settings.height; + } + + requested_depth = display->display_settings.depth; + value = i; + + if ((err = rpi_firmware_property(bfb->rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, &value, sizeof(value)))) + { + goto _display_fail; + } + + err = bcm2708fb_firmware_alloc(bfb->rpi_fw, display, + requested_depth, &fbinfo); + + if (err && requested_depth != 16) + { + LOG_W("Display(%d) preferred %ubpp unavailable, trying 16bpp", + i, requested_depth); + requested_depth = 16; + err = bcm2708fb_firmware_alloc(bfb->rpi_fw, display, + requested_depth, &fbinfo); + } + + if (err) + { + LOG_E("Display(%d) firmware allocation failed: base=0x%08x size=%u pitch=%u", + i, fbinfo.base, fbinfo.screen_size, fbinfo.pitch); + goto _display_fail; + } + + fbinfo.base &= ~0xc0000000; + display->framebuffer_dma = fbinfo.base; + display->framebuffer_size = fbinfo.screen_size; + display->stride = fbinfo.pitch; + display->framebuffer = rt_ioremap_wt( + (void *)display->framebuffer_dma, display->framebuffer_size); + + if (!display->framebuffer) + { + err = -RT_ENOMEM; + goto _display_fail; + } + + LOG_I("Display(%d) firmware framebuffer: bpp=%u pitch=%u size=%u", + i, fbinfo.bpp, fbinfo.pitch, fbinfo.screen_size); + + if (!fbinfo.bpp || !fbinfo.pitch) + { + err = -RT_EINVAL; + goto _display_fail; + } + + effective_depth = fbinfo.bpp; + stride_width = fbinfo.xres_virtual ? fbinfo.xres_virtual : + display->display_settings.virtual_width; + + /* Pi 5 firmware can report stale bpp while returning the active pitch. */ + if (stride_width && fbinfo.pitch != (stride_width * fbinfo.bpp) / 8) + { + if (fbinfo.pitch == stride_width * 2) + { + effective_depth = 16; + } + else if (fbinfo.pitch == stride_width * 3) + { + effective_depth = 24; + } + else if (fbinfo.pitch == stride_width * 4) + { + effective_depth = 32; + } + + if (effective_depth != fbinfo.bpp) + { + LOG_W("Display(%d) inconsistent format: bpp=%u pitch=%u width=%u; using %ubpp", + i, fbinfo.bpp, fbinfo.pitch, stride_width, effective_depth); + } + } + + display->display_settings.depth = effective_depth; + display->stride = fbinfo.pitch; + + if (requested_depth != effective_depth) + { + LOG_W("Display(%d) depth adjusted by firmware: %u -> %u", + i, requested_depth, effective_depth); + } + + switch (display->display_settings.depth) + { + case 16: midx = 0; break; + case 24: midx = 1; break; + case 32: midx = 2; break; + default: + err = -RT_EINVAL; + goto _display_fail; + } + + display->fb = bfb; + display->gpu_mem.base = gpu_mem.base; + display->gpu_mem.length = gpu_mem.length; + + display->parent.ops = &bcm2708fb_ops; + + rt_memset(display->framebuffer, 0, display->framebuffer_size); + + if ((err = rt_graphic_device_simple_register(&display->parent, + display->display_settings.width, display->display_settings.height, 0, + &bcm2708fb_plane_ops, &bcm2708fb_modes[midx], 1))) + { + goto _display_fail; + } + + LOG_I("Display(%d) registered: %ux%u@%u, pitch=%u, fb=%p", + i, display->display_settings.width, display->display_settings.height, + display->display_settings.depth, (rt_uint32_t)display->stride, + display->framebuffer); + + num_registered++; + continue; + + _display_fail: + if (display->framebuffer) + { + rt_iounmap(display->framebuffer); + } + + display->display_settings.display_num = MAX_FRAMEBUFFERS; + LOG_W("Display(%d) init error = %s", i, rt_strerror(err)); + } + + if (!num_registered) + { + err = -RT_EINVAL; + goto _fail; + } + + pdev->parent.user_data = bfb; + + return RT_EOK; + +_fail: + if (bfb->rpi_fw) + { + rpi_firmware_put(bfb->rpi_fw); + } + + rt_free(bfb); + + return err; +} + +static rt_err_t bcm2708fb_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct bcm2708fb *bfb = dev->user_data; + + for (int i = 0; i < RT_ARRAY_SIZE(bfb->displays); ++i) + { + struct bcm2708fb_display *display = &bfb->displays[i]; + + if (display->display_settings.display_num == MAX_FRAMEBUFFERS) + { + continue; + } + + rt_graphic_device_simple_unregister(&display->parent); + + rt_iounmap(display->framebuffer); + } + + rpi_firmware_put(bfb->rpi_fw); + + rt_free(bfb); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2708fb_ofw_ids[] = +{ + { .compatible = "brcm,bcm2708-fb" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2708fb_driver = +{ + .name = "bcm2708-framebuffer", + .ids = bcm2708fb_ofw_ids, + + .probe = bcm2708fb_probe, + .remove = bcm2708fb_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2708fb_driver); diff --git a/bsp/raspberry-pi/dm/graphic/framebuffer/fb-rpisense.c b/bsp/raspberry-pi/dm/graphic/framebuffer/fb-rpisense.c new file mode 100755 index 0000000000..6640a9c31f --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/framebuffer/fb-rpisense.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#include +#include + +struct rpisense_framebuffer +{ + struct rt_graphic_device parent; + + struct rpisense *rpisense; + + rt_uint8_t *gamma; + + rt_uint8_t vram[128]; + rt_uint8_t vram_work[193]; + rt_uint8_t gamma_user[32]; +}; + +#define raw_to_rpisense_framebuffer(raw) rt_container_of(raw, struct rpisense_framebuffer, parent) + +static rt_uint8_t gamma_default[32] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x11, + 0x12, 0x14, 0x15, 0x17, 0x19, 0x1b, 0x1d, 0x1f, +}; + +static rt_uint8_t gamma_low[32] = +{ + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, + 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0a, +}; + +static void rpisense_fb_deferred_io(struct rpisense_framebuffer *rpisense_fb) +{ + rt_uint8_t *gamma = rpisense_fb->gamma; + rt_uint8_t *vram_work = rpisense_fb->vram_work; + rt_uint16_t *vram = (rt_uint16_t *)rpisense_fb->vram; + struct rt_graphic_plane *primary_plane = rpisense_fb->parent.primary_plane; + + vram_work[0] = 0; + + for (int y = 0; y < primary_plane->height; ++y) + { + for (int x = 0; x < primary_plane->width; ++x) + { + vram_work[(y * 24) + x + 1] = gamma[(vram[(y * 8) + x] >> 11) & 0x1f]; + vram_work[(y * 24) + (x + 8) + 1] = gamma[(vram[(y * 8) + x] >> 6) & 0x1f]; + vram_work[(y * 24) + (x + 16) + 1] = gamma[(vram[(y * 8) + x]) & 0x1f]; + } + } + + rpisense_block_write(rpisense_fb->rpisense, + (const void *)vram_work, sizeof(rpisense_fb->vram_work)); +} + +static rt_err_t rpisense_fb_plane_update(struct rt_graphic_plane *plane, + struct rt_device_rect_info *rect) +{ + struct rpisense_framebuffer *rpisense_fb = raw_to_rpisense_framebuffer(plane->graphic); + + rpisense_fb_deferred_io(rpisense_fb); + + return RT_EOK; +} + +static rt_err_t rpisense_fb_plane_fb_remap(struct rt_graphic_plane *plane, + rt_uint32_t mode, struct rt_device_rect_info *rect) +{ + struct rpisense_framebuffer *rpisense_fb = raw_to_rpisense_framebuffer(plane->graphic); + + plane->line_length = 16; + plane->bits_per_pixel = 16; + + plane->framebuffer = rpisense_fb->vram; + plane->screen_len = sizeof(rpisense_fb->vram); + plane->framebuffer_len = sizeof(rpisense_fb->vram); + + return RT_EOK; +} + +static const struct rt_graphic_plane_ops rpisense_fb_plane_ops = +{ + .update = rpisense_fb_plane_update, + .fb_remap = rpisense_fb_plane_fb_remap, +}; + +static rt_err_t rpisense_fb_wait_vsync(struct rt_graphic_device *gdev) +{ + struct rpisense_framebuffer *rpisense_fb = raw_to_rpisense_framebuffer(gdev); + + rpisense_fb_deferred_io(rpisense_fb); + + return RT_EOK; +} + +static rt_err_t rpisense_fb_control(struct rt_graphic_device *gdev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rpisense_framebuffer *rpisense_fb = raw_to_rpisense_framebuffer(gdev); + + switch (cmd) + { + case SENSEFB_FBIOGET_GAMMA: + rt_memcpy(args, rpisense_fb->gamma, sizeof(rpisense_fb->gamma_user)); + break; + + case SENSEFB_FBIOSET_GAMMA: + rt_memcpy(rpisense_fb->gamma_user, args, sizeof(rpisense_fb->gamma_user)); + rpisense_fb->gamma = rpisense_fb->gamma_user; + break; + + case SENSEFB_FBIORESET_GAMMA: + switch ((rt_ubase_t)args) + { + case 0: + rpisense_fb->gamma = gamma_default; + break; + + case 1: + rpisense_fb->gamma = gamma_low; + break; + + case 2: + rpisense_fb->gamma = rpisense_fb->gamma_user; + break; + + default: + err = -RT_EINVAL; + break; + } + break; + + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static const struct rt_graphic_device_ops rpisense_fb_ops = +{ + .wait_vsync = rpisense_fb_wait_vsync, + .control = rpisense_fb_control, +}; + +static rt_uint32_t rpisense_fb_modes[] = +{ + RTGRAPHIC_PIXEL_FORMAT_RGB565, +}; + +static rt_err_t rpisense_fb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rpisense *rpisense = pdev->priv; + struct rpisense_framebuffer *rpisense_fb = rt_calloc(1, sizeof(*rpisense_fb)); + + if (!rpisense_fb) + { + return -RT_ENOMEM; + } + + rpisense_fb->rpisense = rpisense; + rpisense_fb->gamma = gamma_default; + rpisense_fb->parent.ops = &rpisense_fb_ops; + + if ((err = rt_graphic_device_simple_register(&rpisense_fb->parent, + 8, 8, 0, &rpisense_fb_plane_ops, + rpisense_fb_modes, RT_ARRAY_SIZE(rpisense_fb_modes)))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(rpisense_fb); + + return err; +} + +static rt_err_t rpisense_fb_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + + rt_device_unregister(&pdev->parent); + + rt_free(rt_container_of(dev->user_data, struct rpisense_framebuffer, parent)); + + return RT_EOK; +} + +static struct rt_platform_driver rpisense_fb_driver = +{ + .name = "rpi-sense-fb", + + .probe = rpisense_fb_probe, + .remove = rpisense_fb_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpisense_fb_driver); diff --git a/bsp/raspberry-pi/dm/graphic/logo/Kconfig b/bsp/raspberry-pi/dm/graphic/logo/Kconfig new file mode 100755 index 0000000000..24d25996fe --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/logo/Kconfig @@ -0,0 +1,2 @@ +config RT_GRAPHIC_LOGO_RASPI_CLUT224 + bool "Standard 224-color Raspberry PI logo" diff --git a/bsp/raspberry-pi/dm/graphic/logo/Kconfig.path b/bsp/raspberry-pi/dm/graphic/logo/Kconfig.path new file mode 100755 index 0000000000..ff6fdbc075 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/logo/Kconfig.path @@ -0,0 +1,5 @@ +if RT_GRAPHIC_LOGO_RASPI_CLUT224 + config RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH + string + default "../dm/graphic/logo/logo-raspi-clut224.ppm" +endif diff --git a/bsp/raspberry-pi/dm/graphic/logo/logo-raspi-clut224.ppm b/bsp/raspberry-pi/dm/graphic/logo/logo-raspi-clut224.ppm new file mode 100755 index 0000000000..7626beb6a5 --- /dev/null +++ b/bsp/raspberry-pi/dm/graphic/logo/logo-raspi-clut224.ppm @@ -0,0 +1,883 @@ +P3 +63 80 +255 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +10 15 3 2 3 1 12 18 4 42 61 14 19 27 6 11 16 4 +38 55 13 10 15 3 3 4 1 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 +12 18 4 1 1 0 23 34 8 31 45 11 10 15 3 32 47 11 +34 49 12 3 4 1 3 4 1 3 4 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 10 15 3 29 42 10 26 37 9 12 18 4 +55 80 19 81 118 28 55 80 19 92 132 31 106 153 36 69 100 23 +100 144 34 80 116 27 42 61 14 81 118 28 23 34 8 27 40 9 +15 21 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 1 0 29 42 10 15 21 5 50 72 17 +74 107 25 45 64 15 102 148 35 80 116 27 84 121 28 111 160 38 +69 100 23 65 94 22 81 118 28 29 42 10 17 25 6 29 42 10 +23 34 8 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +15 21 5 15 21 5 34 49 12 101 146 34 111 161 38 97 141 33 +97 141 33 119 172 41 117 170 40 116 167 40 118 170 40 118 171 40 +117 169 40 118 170 40 111 160 38 118 170 40 96 138 32 89 128 30 +81 118 28 11 16 4 10 15 3 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 3 4 1 34 49 12 101 146 34 79 115 27 111 160 38 +114 165 39 113 163 39 118 170 40 117 169 40 118 171 40 117 169 40 +116 167 40 119 172 41 113 163 39 92 132 31 105 151 36 113 163 39 +75 109 26 19 27 6 16 23 5 11 16 4 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +80 116 27 106 153 36 105 151 36 114 165 39 118 170 40 118 171 40 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 117 169 40 118 170 40 118 170 40 +117 170 40 75 109 26 75 109 26 34 49 12 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 +64 92 22 65 94 22 100 144 34 118 171 40 118 170 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 41 118 170 40 117 169 40 +109 158 37 105 151 36 104 150 35 47 69 16 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42 61 14 115 167 39 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 96 138 32 17 25 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 69 16 +114 165 39 117 168 40 117 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 119 172 41 96 138 32 12 18 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 +32 47 11 105 151 36 118 170 40 117 169 40 117 169 40 116 168 40 +109 157 37 111 160 38 117 169 40 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 69 100 23 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 19 27 6 101 146 34 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 170 40 +118 171 40 115 166 39 107 154 36 111 161 38 117 169 40 117 169 40 +117 169 40 118 171 40 75 109 26 19 27 6 2 3 1 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 +89 128 30 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +111 160 38 92 132 31 79 115 27 96 138 32 115 166 39 119 171 41 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 109 157 37 26 37 9 +0 0 0 0 0 0 0 0 0 0 0 0 64 92 22 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 170 40 118 171 40 109 157 37 +89 128 30 81 118 28 100 144 34 115 166 39 117 169 40 117 169 40 +117 169 40 117 170 40 113 163 39 60 86 20 1 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +27 40 9 96 138 32 118 170 40 117 169 40 117 169 40 117 169 40 +117 170 40 117 169 40 101 146 34 67 96 23 55 80 19 84 121 28 +113 163 39 119 171 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 65 94 22 +0 0 0 0 0 0 0 0 0 15 21 5 101 146 34 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 118 171 40 104 150 35 69 100 23 53 76 18 +81 118 28 111 160 38 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 114 165 39 69 100 23 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +31 45 11 77 111 26 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 168 40 92 132 31 47 69 16 +38 55 13 81 118 28 113 163 39 119 171 41 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 41 92 132 31 +10 15 3 0 0 0 0 0 0 36 52 12 115 166 39 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +118 171 40 102 148 35 64 92 22 34 49 12 65 94 22 106 153 36 +118 171 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 170 40 107 154 36 55 80 19 15 21 5 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +29 42 10 101 146 34 118 171 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 113 163 39 +75 109 26 27 40 9 36 52 12 89 128 30 116 167 40 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 104 150 35 +16 23 5 0 0 0 0 0 0 53 76 18 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 109 157 37 +67 96 23 23 34 8 42 61 14 96 138 32 118 170 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 74 107 25 10 15 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 31 45 11 101 146 34 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 171 41 102 148 35 47 69 16 14 20 5 50 72 17 102 148 35 +118 171 40 117 169 40 117 169 40 117 169 40 118 170 40 102 148 35 +15 21 5 0 0 0 0 0 0 50 72 17 118 170 40 117 169 40 +117 169 40 117 169 40 118 170 40 116 167 40 84 121 28 27 40 9 +19 27 6 74 107 25 114 165 39 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 75 109 26 10 15 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 38 55 13 102 148 35 118 171 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 115 167 39 77 111 26 17 25 6 19 27 6 +77 111 26 115 166 39 118 170 40 117 169 40 119 172 41 81 118 28 +3 4 1 0 0 0 0 0 0 27 40 9 111 160 38 118 170 40 +117 169 40 118 171 40 105 151 36 50 72 17 10 15 3 38 55 13 +100 144 34 118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 79 115 27 15 21 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 10 15 3 64 92 22 111 160 38 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 118 171 40 96 138 32 32 47 11 +3 4 1 50 72 17 107 154 36 120 173 41 105 151 36 31 45 11 +0 0 0 0 0 0 0 0 0 3 4 1 65 94 22 117 169 40 +118 170 40 89 128 30 26 37 9 3 4 1 60 86 20 111 161 38 +118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +97 141 33 36 52 12 1 1 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 20 5 75 109 26 117 168 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 107 154 36 +45 64 15 2 3 1 31 45 11 75 109 26 32 47 11 0 1 0 +0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 55 80 19 +65 94 22 11 16 4 11 16 4 75 109 26 116 168 40 118 170 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 107 154 36 +47 69 16 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 12 18 4 69 100 23 111 161 38 118 171 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 +111 160 38 50 72 17 2 3 1 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 +1 1 0 12 18 4 81 118 28 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 170 40 118 171 40 101 146 34 +42 61 14 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 4 1 36 52 12 89 128 30 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 41 101 146 34 14 20 5 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 47 69 16 118 170 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 170 40 111 160 38 69 100 23 19 27 6 +0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 11 16 4 69 100 23 +115 167 39 119 172 41 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +119 172 41 75 109 26 3 4 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 23 34 8 106 153 36 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +117 169 40 118 170 40 119 172 41 105 151 36 42 61 14 2 3 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 15 21 5 +45 64 15 80 116 27 114 165 39 118 170 40 117 169 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 119 172 41 +97 141 33 20 30 7 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 1 0 53 76 18 114 165 39 118 171 40 117 169 40 +117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 +118 171 40 104 150 35 64 92 22 31 45 11 10 15 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 36 52 12 97 141 33 109 158 37 113 163 39 116 168 40 +117 169 40 117 170 40 118 170 40 119 172 41 115 167 39 84 121 28 +23 34 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 4 1 50 72 17 102 148 35 118 171 40 +119 171 41 118 170 40 117 169 40 117 169 40 115 166 39 111 161 38 +109 157 37 79 115 27 12 18 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 4 1 15 21 5 23 34 8 45 64 15 106 153 36 +116 167 40 111 160 38 101 146 34 79 115 27 42 61 14 10 15 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 1 0 20 30 7 60 86 20 +89 128 30 106 153 36 113 163 39 117 169 40 84 121 28 29 42 10 +19 27 6 10 15 3 2 3 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 38 55 13 +36 52 12 26 37 9 12 18 4 2 3 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 1 0 0 19 2 7 52 5 18 +78 7 27 88 8 31 81 7 29 56 5 19 25 2 9 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 4 1 19 27 6 31 45 11 38 55 13 32 47 11 3 4 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +9 0 3 12 1 4 9 0 3 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 28 3 10 99 9 35 156 14 55 182 16 64 +189 17 66 190 17 67 189 17 66 184 17 65 166 15 58 118 13 41 +45 4 16 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 11 1 4 52 5 18 101 9 35 134 12 47 +151 14 53 154 14 54 151 14 53 113 10 40 11 1 4 0 0 0 +3 0 1 67 6 24 159 14 56 190 17 67 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 191 17 67 +174 16 61 101 9 35 14 1 5 0 0 0 35 3 12 108 10 38 +122 11 43 122 11 43 112 10 39 87 8 30 50 5 17 13 1 5 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 56 5 19 141 13 49 182 16 64 191 17 67 191 17 67 +190 17 67 190 17 67 191 17 67 113 10 40 3 0 1 1 0 0 +79 7 28 180 16 63 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 188 17 66 122 11 43 11 1 4 41 4 14 176 16 62 +191 17 67 191 17 67 191 17 67 190 17 67 181 16 63 146 13 51 +75 7 26 10 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 2 +90 8 32 178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 41 4 14 +173 16 61 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 88 8 31 1 0 0 89 8 31 +185 17 65 189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +186 17 65 124 11 43 25 2 9 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 89 8 31 +184 17 65 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 151 14 53 34 3 12 0 0 0 0 0 0 79 7 28 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 146 13 51 9 1 3 7 1 2 +108 10 38 187 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 176 16 62 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 38 3 13 0 0 0 0 0 0 0 0 0 50 5 17 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 191 17 67 141 13 49 7 1 3 0 0 0 +11 1 4 112 10 39 187 17 66 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 113 10 40 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 7 1 3 132 12 46 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 +35 3 12 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +101 9 35 185 17 65 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 190 17 67 180 16 63 67 6 24 0 0 0 0 0 0 +0 0 0 11 1 4 108 10 38 186 17 65 189 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 44 4 15 177 16 62 189 17 66 +188 17 66 188 17 66 189 17 66 189 17 66 134 12 47 28 3 10 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 79 7 28 159 14 56 188 17 66 191 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 190 17 67 191 17 67 +188 17 66 158 14 55 72 7 25 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 8 1 3 95 9 33 182 16 64 189 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 122 11 43 3 0 1 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 88 8 31 190 17 67 188 17 66 +188 17 66 189 17 66 185 17 65 113 10 40 18 2 6 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 24 2 8 77 7 27 124 11 43 154 14 54 +168 15 59 173 16 61 173 16 61 168 15 59 154 14 54 124 11 43 +77 7 27 22 2 8 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 77 7 27 173 16 61 +190 17 67 188 17 66 188 17 66 190 17 67 164 15 57 23 2 8 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 118 13 41 191 17 67 188 17 66 +190 17 67 174 16 61 87 8 30 8 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 10 1 4 29 3 10 40 4 14 36 3 13 +18 2 6 2 0 1 0 0 0 0 0 0 3 0 1 14 1 5 +26 2 9 33 3 11 32 3 11 25 2 9 13 1 5 3 0 1 +0 0 0 14 1 5 56 5 19 95 9 33 109 10 38 101 9 35 +77 7 27 35 3 12 5 0 2 0 0 0 1 0 0 56 5 19 +156 14 55 190 17 67 188 17 66 188 17 66 182 16 64 50 5 17 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 189 17 66 +151 14 53 52 5 18 2 0 1 0 0 0 0 0 0 1 0 0 +28 3 10 90 8 32 146 13 51 170 15 60 178 16 62 174 16 61 +158 14 55 112 10 39 40 4 14 1 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 +56 5 19 146 13 51 183 17 64 191 17 67 191 17 67 191 17 67 +188 17 66 173 16 61 122 11 43 41 4 14 1 0 0 0 0 0 +30 3 10 124 11 43 185 17 65 190 17 67 187 17 66 67 6 24 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 6 1 2 134 12 47 168 15 59 99 9 35 +21 2 7 0 0 0 0 0 0 0 0 0 6 1 2 77 7 27 +162 15 57 190 17 67 191 17 67 189 17 66 189 17 66 189 17 66 +190 17 67 191 17 67 169 15 59 75 7 26 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 79 7 28 +178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 191 17 67 170 15 60 79 7 28 5 0 2 +0 0 0 10 1 3 78 7 27 159 14 56 188 17 66 75 7 26 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 1 0 0 35 3 12 29 3 10 2 0 1 +0 0 0 0 0 0 0 0 0 9 1 3 101 9 35 183 17 64 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 178 16 63 67 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 182 16 64 89 8 31 +4 0 1 0 0 0 0 0 0 25 2 9 73 7 26 31 3 11 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 4 0 1 98 9 34 187 17 66 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 25 2 9 +0 0 0 0 0 0 0 0 0 8 1 3 134 12 47 191 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 +68 6 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 6 1 2 19 2 7 3 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 65 6 23 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 83 8 29 +0 0 0 0 0 0 0 0 0 41 4 14 177 16 62 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +159 14 56 28 3 10 0 0 0 0 0 0 0 0 0 23 2 8 +41 4 14 5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +23 2 8 113 10 40 159 14 56 65 6 23 0 0 0 0 0 0 +0 0 0 16 1 6 146 13 51 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 132 12 46 +5 0 2 0 0 0 0 0 0 77 7 27 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 98 9 34 0 0 0 0 0 0 12 1 4 134 12 47 +178 16 63 108 10 38 16 1 6 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 3 10 +141 13 49 190 17 67 191 17 67 134 12 47 6 1 2 0 0 0 +0 0 0 68 6 24 186 17 65 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 156 14 55 +14 1 5 0 0 0 0 0 0 98 9 34 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 156 14 55 19 2 7 0 0 0 47 4 16 181 16 63 +190 17 67 189 17 66 126 14 44 17 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 16 1 6 134 12 47 +191 17 67 188 17 66 190 17 67 162 15 57 19 2 7 0 0 0 +3 0 1 123 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 163 15 57 +20 2 7 0 0 0 0 0 0 101 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 182 16 64 52 5 18 0 0 0 73 7 26 188 17 66 +188 17 66 188 17 66 189 17 66 109 10 38 5 0 2 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 95 9 33 189 17 66 +188 17 66 188 17 66 189 17 66 171 15 60 29 3 10 0 0 0 +16 1 6 156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 +17 2 6 0 0 0 0 0 0 85 8 30 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 81 7 29 0 0 0 85 8 30 190 17 67 +188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 25 2 9 162 15 57 190 17 67 +188 17 66 188 17 66 189 17 66 173 16 61 31 3 11 0 0 0 +30 3 10 171 15 60 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 141 13 49 +7 1 2 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 88 8 31 190 17 67 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 5 0 2 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 68 6 24 187 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 170 15 60 28 3 10 0 0 0 +34 3 12 174 16 61 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 101 9 35 +0 0 0 0 0 0 0 0 0 21 2 7 159 14 56 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 98 9 34 0 0 0 81 7 29 189 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 168 15 59 28 3 10 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 109 10 38 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 163 15 57 21 2 7 0 0 0 +26 2 9 168 15 59 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 47 4 16 +0 0 0 0 0 0 0 0 0 0 0 0 108 10 38 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 78 7 27 0 0 0 68 6 24 187 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 183 17 64 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 131 12 46 191 17 67 188 17 66 +188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 0 0 0 +11 1 4 146 13 51 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 126 14 44 7 1 2 +0 0 0 0 0 0 0 0 0 0 0 0 32 3 11 164 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 178 16 62 44 4 15 0 0 0 50 5 17 182 16 64 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 131 12 46 3 0 1 0 0 0 +0 0 0 101 9 35 190 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 170 15 60 44 4 15 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 7 27 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 134 12 47 9 1 3 0 0 0 31 3 11 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 124 11 43 191 17 67 188 17 66 +188 17 66 188 17 66 191 17 67 101 9 35 0 0 0 0 0 0 +0 0 0 35 3 12 168 15 59 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 182 16 64 77 7 27 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 1 2 +99 9 35 185 17 65 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +177 16 62 56 5 19 0 0 0 0 0 0 13 1 5 151 14 53 +190 17 67 188 17 66 188 17 66 188 17 66 185 17 65 56 5 19 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 99 9 35 191 17 67 188 17 66 +188 17 66 188 17 66 186 17 65 65 6 23 0 0 0 0 0 0 +0 0 0 0 0 0 79 7 28 182 16 64 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 177 16 62 83 8 29 4 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +8 1 3 89 8 31 175 16 62 191 17 67 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 181 16 63 +85 8 30 3 0 1 0 0 0 0 0 0 1 0 0 118 13 41 +191 17 67 188 17 66 188 17 66 189 17 66 173 16 61 34 3 12 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 +188 17 66 189 17 66 169 15 59 30 3 10 0 0 0 0 0 0 +0 0 0 0 0 0 5 0 2 83 8 29 173 16 61 191 17 67 +190 17 67 189 17 66 189 17 66 190 17 67 191 17 67 187 17 66 +151 14 53 56 5 19 3 0 1 0 0 0 16 1 6 50 5 17 +79 7 28 95 9 33 95 9 33 75 7 26 41 4 14 10 1 4 +0 0 0 2 0 1 50 5 17 132 12 46 178 16 62 190 17 67 +191 17 67 191 17 67 191 17 67 186 17 65 154 14 54 68 6 24 +4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +187 17 66 188 17 66 188 17 66 191 17 67 141 13 49 9 1 3 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 14 1 5 151 14 53 190 17 67 +188 17 66 191 17 67 131 12 46 5 0 2 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 2 0 1 44 4 15 113 10 40 +156 14 55 173 16 61 174 16 61 164 15 58 134 12 47 77 7 27 +18 2 6 0 0 0 16 1 6 85 8 30 151 14 53 182 16 64 +189 17 66 191 17 67 190 17 67 188 17 66 177 16 62 141 13 49 +68 6 24 8 1 3 0 0 0 8 1 3 44 4 15 88 8 31 +113 10 40 122 11 43 108 10 38 67 6 24 20 2 7 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 3 10 +166 15 58 190 17 67 188 17 66 187 17 66 79 7 28 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 73 7 26 185 17 65 +189 17 66 184 17 65 65 6 23 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 +17 2 6 32 3 11 34 3 12 22 2 8 6 1 2 0 0 0 +0 0 0 38 3 13 141 13 49 188 17 66 190 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 191 17 67 +184 17 65 122 11 43 21 2 7 0 0 0 0 0 0 0 0 0 +0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +108 10 38 191 17 67 191 17 67 141 13 49 16 1 6 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 8 1 3 112 10 39 +186 17 65 124 11 43 10 1 4 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +36 3 13 156 14 55 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +189 17 66 190 17 67 134 12 47 18 2 6 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 7 1 2 41 4 14 75 7 26 66 5 23 19 2 7 +26 2 9 144 13 50 154 14 54 40 4 14 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +56 5 19 19 2 7 0 0 0 7 1 2 29 3 10 35 3 12 +19 2 7 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 +134 12 47 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 108 10 38 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +40 4 14 124 11 43 177 16 62 188 17 66 187 17 66 144 13 50 +24 2 8 17 2 6 22 2 8 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 19 2 7 122 11 43 171 15 60 175 16 62 +159 14 56 112 10 39 40 4 14 2 0 1 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 +186 17 65 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 174 16 61 41 4 14 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 72 7 25 +168 15 59 191 17 67 189 17 66 188 17 66 188 17 66 190 17 67 +95 9 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 95 9 33 191 17 67 189 17 66 189 17 66 +190 17 67 191 17 67 171 15 60 90 8 32 12 1 4 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 132 12 46 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 98 9 34 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 88 8 31 180 16 63 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 +146 13 51 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 9 1 3 144 13 50 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 187 17 66 123 11 43 20 2 7 +0 0 0 0 0 0 0 0 0 0 0 0 21 2 7 163 15 57 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 134 12 47 5 0 2 +0 0 0 0 0 0 3 0 1 88 8 31 182 16 64 189 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +171 15 60 31 3 11 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 20 2 7 162 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 132 12 46 +20 2 7 0 0 0 0 0 0 0 0 0 32 3 11 173 16 61 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 +0 0 0 0 0 0 72 7 25 180 16 63 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +181 16 63 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 21 2 7 163 15 57 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +122 11 43 9 1 3 0 0 0 0 0 0 30 3 10 171 15 60 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 10 1 4 +0 0 0 38 3 13 166 15 58 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +183 17 64 52 5 18 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 13 1 5 154 14 54 190 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +186 17 65 79 7 28 0 0 0 0 0 0 14 1 5 156 14 54 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 2 0 1 +5 0 2 122 11 43 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +182 16 64 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 3 0 1 126 14 44 191 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 158 14 55 23 2 8 0 0 0 1 0 0 113 10 40 +191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 78 7 27 0 0 0 +47 4 16 177 16 62 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 +173 16 61 34 3 12 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 85 8 30 189 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 79 7 28 0 0 0 0 0 0 47 4 16 +175 16 62 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 190 17 67 156 14 55 22 2 8 0 0 0 +109 10 38 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +151 14 53 13 1 5 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 35 3 12 173 16 61 189 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 191 17 67 134 12 47 7 1 2 0 0 0 3 0 1 +99 9 35 188 17 66 189 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 181 16 63 68 6 24 0 0 0 18 2 6 +156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 +101 9 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 3 0 1 118 13 41 191 17 67 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 168 15 59 28 3 10 0 0 0 0 0 0 +12 1 4 113 10 40 187 17 66 189 17 67 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +190 17 67 180 16 63 88 8 31 4 0 1 0 0 0 47 4 16 +180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 168 15 59 +36 3 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 38 3 13 164 15 58 190 17 67 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 11 1 4 90 8 32 169 15 59 190 17 67 190 17 67 +189 17 66 189 17 66 189 17 66 189 17 66 191 17 67 189 17 66 +158 14 55 68 6 24 4 0 1 0 0 0 0 0 0 73 7 26 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 185 17 65 83 8 29 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 65 6 23 174 16 61 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 185 17 65 56 5 19 0 0 0 0 0 0 +0 0 0 0 0 0 2 0 1 35 3 12 99 9 35 146 13 51 +170 15 60 177 16 62 177 16 62 166 15 58 141 13 49 85 8 30 +24 2 8 0 0 0 0 0 0 0 0 0 0 0 0 85 8 30 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 189 17 66 112 10 39 8 1 3 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 68 6 24 +170 15 60 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 11 1 4 +28 3 10 40 4 14 38 3 13 25 2 9 8 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 7 27 +189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 187 17 66 113 10 40 14 1 5 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 +47 4 16 141 13 49 186 17 65 191 17 67 190 17 67 189 17 66 +189 17 66 191 17 67 156 14 55 20 2 7 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 4 15 +178 16 62 190 17 67 188 17 66 188 17 66 188 17 66 190 17 67 +191 17 67 173 16 61 90 8 32 10 1 4 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 14 1 5 68 6 24 131 12 46 162 15 57 174 16 61 +171 15 60 146 13 51 56 5 19 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 3 0 1 14 1 5 29 3 10 +41 4 14 47 4 16 50 5 17 45 4 16 34 3 12 18 2 6 +5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +90 8 32 169 15 59 185 17 65 187 17 66 182 16 64 163 15 57 +113 10 40 41 4 14 2 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 5 0 2 21 2 7 34 3 12 +29 3 10 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 +3 0 1 32 3 11 79 7 28 124 11 43 154 14 54 171 15 60 +180 16 63 182 16 64 182 16 64 180 16 63 174 16 61 159 14 56 +132 12 46 88 8 31 34 3 12 3 0 1 0 0 0 0 0 0 +3 0 1 29 3 10 56 5 19 65 6 23 50 5 17 23 2 8 +3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 2 9 +109 10 38 169 15 59 189 17 66 191 17 67 190 17 67 189 17 66 +189 17 66 188 17 66 188 17 66 188 17 66 189 17 66 190 17 67 +191 17 67 190 17 67 171 15 60 98 9 34 10 1 3 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 14 1 5 141 13 49 +191 17 67 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 67 186 17 65 65 6 23 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 23 2 8 166 15 58 +190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 189 17 66 176 16 62 45 4 16 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 83 8 29 +183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +188 17 66 189 17 66 185 17 65 95 9 33 3 0 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 +85 8 30 176 16 62 191 17 67 188 17 66 188 17 66 188 17 66 +188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 +191 17 67 180 16 63 95 9 33 7 1 3 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 0 1 52 5 18 141 13 49 185 17 65 191 17 67 189 17 67 +189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 187 17 66 +146 13 51 56 5 19 4 0 1 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 14 1 5 68 6 24 131 12 46 166 15 58 +180 16 63 183 17 64 180 16 63 168 15 59 134 12 47 75 7 26 +17 2 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 24 2 8 +44 4 15 52 5 18 45 4 16 26 2 9 6 1 2 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 diff --git a/bsp/raspberry-pi/dm/hwcrypto/Kconfig b/bsp/raspberry-pi/dm/hwcrypto/Kconfig new file mode 100755 index 0000000000..0a09e8d05d --- /dev/null +++ b/bsp/raspberry-pi/dm/hwcrypto/Kconfig @@ -0,0 +1,14 @@ +config RT_HWCRYPTO_RNG_BCM2835 + bool "Broadcom BCM2835/BCM63xx Random Number Generator support" + depends on RT_USING_DM + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_RNG + depends on RT_USING_RESET + default n + +config RT_HWCRYPTO_RNG_IPROC_RNG200 + bool "Broadcom iProc/STB RNG200 support" + depends on RT_USING_DM + depends on RT_USING_HWCRYPTO + depends on RT_HWCRYPTO_USING_RNG + default n diff --git a/bsp/raspberry-pi/dm/hwcrypto/SConscript b/bsp/raspberry-pi/dm/hwcrypto/SConscript new file mode 100755 index 0000000000..9cf5e7f8a7 --- /dev/null +++ b/bsp/raspberry-pi/dm/hwcrypto/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_HWCRYPTO_RNG_BCM2835']): + src += ['hw-rng-bcm2835.c'] + +if GetDepend(['RT_HWCRYPTO_RNG_IPROC_RNG200']): + src += ['hw-rng-iproc-rng200.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/hwcrypto/hw-rng-bcm2835.c b/bsp/raspberry-pi/dm/hwcrypto/hw-rng-bcm2835.c new file mode 100755 index 0000000000..93667c56ba --- /dev/null +++ b/bsp/raspberry-pi/dm/hwcrypto/hw-rng-bcm2835.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "rng.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#define RNG_CTRL 0x0 +#define RNG_STATUS 0x4 +#define RNG_DATA 0x8 +#define RNG_INT_MASK 0x10 + +/* enable rng */ +#define RNG_RBGEN 0x1 + +/* the initial numbers generated are "less random" so will be discarded */ +#define RNG_WARMUP_COUNT 0x40000 + +#define RNG_INT_OFF 0x1 + +struct bcm2835_rng_soc_data +{ + rt_bool_t mask_interrupts; +}; + +struct bcm2835_rng +{ + struct rt_hwcrypto_device parent; + + void *regs; + + rt_bool_t mask_interrupts; + struct rt_clk *clk; + struct rt_reset_control *rstc; +}; + +#define raw_to_bcm2835_rng(raw) rt_container_of(raw, struct bcm2835_rng, parent) + +rt_inline rt_uint32_t rng_readl(struct bcm2835_rng *brng, int offset) +{ + return HWREG32(brng->regs + offset); +} + +rt_inline void rng_writel(struct bcm2835_rng *brng, int offset, rt_uint32_t val) +{ + HWREG32(brng->regs + offset) = val; +} + +static rt_uint32_t bcm2835_rng_read(struct bcm2835_rng *brng, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_uint32_t max_words = max / sizeof(rt_uint32_t), num_words; + + while ((rng_readl(brng, RNG_STATUS) >> 24) == 0) + { + if (!wait) + { + return 0; + } + + rt_thread_mdelay(1000); + } + + num_words = rng_readl(brng, RNG_STATUS) >> 24; + + if (num_words > max_words) + { + num_words = max_words; + } + + for (int count = 0; count < num_words; ++count) + { + ((rt_uint32_t *)buf)[count] = rng_readl(brng, RNG_DATA); + } + + return num_words * sizeof(rt_uint32_t); +} + +static rt_err_t bcm2835_rng_init(struct bcm2835_rng *brng) +{ + rt_err_t err; + rt_uint32_t val; + + if ((err = rt_clk_prepare_enable(brng->clk))) + { + LOG_E("CLK enable error = %s", rt_strerror(err)); + return err; + } + + if ((err = rt_reset_control_reset(brng->rstc))) + { + LOG_E("Reset error = %s", rt_strerror(err)); + return err; + } + + if (brng->mask_interrupts) + { + /* mask the interrupt */ + val = rng_readl(brng, RNG_INT_MASK); + val |= RNG_INT_OFF; + rng_writel(brng, RNG_INT_MASK, val); + } + + /* set warm-up count & enable */ + rng_writel(brng, RNG_STATUS, RNG_WARMUP_COUNT); + rng_writel(brng, RNG_CTRL, RNG_RBGEN); + + return RT_EOK; +} + +static void bcm2835_rng_cleanup(struct bcm2835_rng *brng) +{ + /* Disable rng hardware */ + rng_writel(brng, RNG_CTRL, 0); + + rt_clk_disable_unprepare(brng->clk); +} + +static rt_uint32_t bcm2835_rng_rand(struct hwcrypto_rng *ctx) +{ + rt_size_t size; + rt_uint32_t rand; + struct bcm2835_rng *brng = raw_to_bcm2835_rng(ctx->parent.device); + + size = bcm2835_rng_read(brng, &rand, sizeof(rand), RT_TRUE); + + if (size != sizeof(rand)) + { + return 0; + } + + return rand; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = bcm2835_rng_rand, +}; + +static rt_err_t bcm2835_rng_create(struct rt_hwcrypto_ctx *ctx) +{ + rt_err_t res = RT_EOK; + struct hwcrypto_rng *rng; + + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_RNG: + ctx->contex = RT_NULL; + + rng = rt_container_of(ctx, struct hwcrypto_rng, parent); + rng->ops = &rng_ops; + break; + + default: + res = -RT_ENOSYS; + break; + } + + return res; +} + +static void bcm2835_rng_destroy(struct rt_hwcrypto_ctx *ctx) +{ + struct bcm2835_rng *brng = raw_to_bcm2835_rng(ctx->device); + + bcm2835_rng_cleanup(brng); + + rt_free(ctx->contex); +} + +static rt_err_t bcm2835_rng_copy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src) +{ + rt_err_t err = RT_EOK; + + switch (src->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_RNG: + break; + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static void bcm2835_rng_reset(struct rt_hwcrypto_ctx *ctx) +{ + struct bcm2835_rng *brng = raw_to_bcm2835_rng(ctx->device); + + bcm2835_rng_init(brng); +} + +static const struct rt_hwcrypto_ops bcm2835_rng_ops = +{ + .create = bcm2835_rng_create, + .destroy = bcm2835_rng_destroy, + .copy = bcm2835_rng_copy, + .reset = bcm2835_rng_reset, +}; + +static void bcm2835_rng_free(struct bcm2835_rng *brng) +{ + if (!brng->regs) + { + rt_iounmap(brng->regs); + } + + if (!rt_is_err_or_null(brng->rstc)) + { + rt_reset_control_assert(brng->rstc); + rt_reset_control_put(brng->rstc); + } + + if (!rt_is_err_or_null(brng->clk)) + { + rt_clk_disable_unprepare(brng->clk); + rt_clk_put(brng->clk); + } + + rt_free(brng); +} + +static rt_err_t bcm2835_rng_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct rt_device *dev = &pdev->parent; + const struct bcm2835_rng_soc_data *soc_data; + struct bcm2835_rng *brng = rt_calloc(1, sizeof(*brng)); + + if (!brng) + { + return -RT_ENOMEM; + } + + brng->regs = rt_dm_dev_iomap(dev, 0); + + if (!brng->regs) + { + err = -RT_EIO; + goto _fail; + } + + brng->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(brng->clk)) + { + err = rt_ptr_err(brng->clk); + goto _fail; + } + + brng->rstc = rt_reset_control_get_by_index(dev, 0); + + if (rt_is_err(brng->rstc)) + { + err = rt_ptr_err(brng->rstc); + goto _fail; + } + + if ((soc_data = pdev->id->data)) + { + brng->mask_interrupts = soc_data->mask_interrupts; + } + + dev->user_data = brng; + + brng->parent.ops = &bcm2835_rng_ops; + + if ((err = rt_hwcrypto_register(&brng->parent, "hwrng"))) + { + goto _fail; + } + + bcm2835_rng_init(brng); + + return RT_EOK; + +_fail: + bcm2835_rng_free(brng); + + return err; +} + +static rt_err_t bcm2835_rng_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_rng *brng = pdev->parent.user_data; + + bcm2835_rng_cleanup(brng); + + rt_device_unregister(&brng->parent.parent); + + bcm2835_rng_free(brng); + + return RT_EOK; +} + +static const struct bcm2835_rng_soc_data nsp_rng_data = +{ + .mask_interrupts = RT_TRUE, +}; + +static const struct rt_ofw_node_id bcm2835_rng_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-rng" }, + { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_data }, + { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_data }, + { .compatible = "brcm,bcm6368-rng" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_rng_driver = +{ + .name = "bcm2835-rng", + .ids = bcm2835_rng_ofw_ids, + + .probe = bcm2835_rng_probe, + .remove = bcm2835_rng_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_rng_driver); diff --git a/bsp/raspberry-pi/dm/hwcrypto/hw-rng-iproc-rng200.c b/bsp/raspberry-pi/dm/hwcrypto/hw-rng-iproc-rng200.c new file mode 100755 index 0000000000..a8feade65e --- /dev/null +++ b/bsp/raspberry-pi/dm/hwcrypto/hw-rng-iproc-rng200.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "rng.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#define RNG_CTRL_OFFSET 0x00 +#define RNG_CTRL_RNG_RBGEN_MASK 0x00001fff +#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 + +#define RNG_SOFT_RESET_OFFSET 0x04 +#define RNG_SOFT_RESET 0x00000001 + +#define RBG_SOFT_RESET_OFFSET 0x08 +#define RBG_SOFT_RESET 0x00000001 + +#define RNG_INT_STATUS_OFFSET 0x18 +#define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000 +#define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000 +#define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020 +#define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001 + +#define RNG_FIFO_DATA_OFFSET 0x20 + +#define RNG_FIFO_COUNT_OFFSET 0x24 +#define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000ff + +#define MAX_RESETS_PER_READ 1 +#define MAX_IDLE_TIME (1 * 100) + +struct iproc_rng200 +{ + struct rt_hwcrypto_device parent; + + void *regs; +}; + +#define raw_to_iproc_rng200(raw) rt_container_of(raw, struct iproc_rng200, parent) + +static void iproc_rng200_enable_set(struct iproc_rng200 *rng200, rt_bool_t enable) +{ + rt_uint32_t val; + + val = HWREG32(rng200->regs + RNG_CTRL_OFFSET); + val &= ~RNG_CTRL_RNG_RBGEN_MASK; + + if (enable) + { + val |= RNG_CTRL_RNG_RBGEN_ENABLE; + } + + HWREG32(rng200->regs + RNG_CTRL_OFFSET) = val; +} + +static void iproc_rng200_restart(struct iproc_rng200 *rng200) +{ + rt_uint32_t val; + void *regs = rng200->regs; + + iproc_rng200_enable_set(rng200, RT_FALSE); + + /* Clear all interrupt status */ + HWREG32(regs + RNG_INT_STATUS_OFFSET) = 0xffffffffUL; + + /* Reset RNG and RBG */ + val = HWREG32(regs + RBG_SOFT_RESET_OFFSET); + val |= RBG_SOFT_RESET; + HWREG32(regs + RBG_SOFT_RESET_OFFSET) = val; + + val = HWREG32(regs + RNG_SOFT_RESET_OFFSET); + val |= RNG_SOFT_RESET; + HWREG32(regs + RNG_SOFT_RESET_OFFSET) = val; + + val = HWREG32(regs + RNG_SOFT_RESET_OFFSET); + val &= ~RNG_SOFT_RESET; + HWREG32(regs + RNG_SOFT_RESET_OFFSET) = val; + + val = HWREG32(regs + RBG_SOFT_RESET_OFFSET); + val &= ~RBG_SOFT_RESET; + HWREG32(regs + RBG_SOFT_RESET_OFFSET) = val; + + iproc_rng200_enable_set(rng200, RT_TRUE); +} + +static rt_uint32_t iproc_rng200_read(struct iproc_rng200 *rng200, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_uint32_t num_remaining = max, status, num_resets = 0; + + while (num_remaining > 0) + { + rt_thread_mdelay(MAX_IDLE_TIME >> 1); + + /* Is RNG sane? If not, reset it. */ + status = HWREG32(rng200->regs + RNG_INT_STATUS_OFFSET); + if ((status & (RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK | + RNG_INT_STATUS_NIST_FAIL_IRQ_MASK)) != 0) + { + if (num_resets >= MAX_RESETS_PER_READ) + { + return max - num_remaining; + } + + iproc_rng200_restart(rng200); + ++num_resets; + } + + /* Are there any random numbers available? */ + if ((HWREG32(rng200->regs + RNG_FIFO_COUNT_OFFSET) & + RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK) > 0) + { + if (num_remaining >= sizeof(rt_uint32_t)) + { + /* Buffer has room to store entire word */ + *(rt_uint32_t *)buf = HWREG32(rng200->regs + RNG_FIFO_DATA_OFFSET); + buf += sizeof(rt_uint32_t); + num_remaining -= sizeof(rt_uint32_t); + } + else + { + /* Buffer can only store partial word */ + rt_uint32_t rnd_number = HWREG32(rng200->regs + RNG_FIFO_DATA_OFFSET); + + rt_memcpy(buf, &rnd_number, num_remaining); + buf += num_remaining; + num_remaining = 0; + } + } + else + { + if (!wait) + { + /* Cannot wait, return immediately */ + return max - num_remaining; + } + + /* Can wait, give others chance to run */ + rt_hw_us_delay((rt_min(num_remaining * 10, 500U)) >> 1); + } + } + + return max - num_remaining; +} + +static rt_err_t iproc_rng200_init(struct iproc_rng200 *rng200) +{ + iproc_rng200_enable_set(rng200, RT_TRUE); + + return RT_EOK; +} + +static void iproc_rng200_cleanup(struct iproc_rng200 *rng200) +{ + iproc_rng200_enable_set(rng200, RT_FALSE); +} + +static rt_uint32_t iproc_rng200_rand(struct hwcrypto_rng *ctx) +{ + rt_size_t size; + rt_uint32_t rand; + struct iproc_rng200 *rng200 = raw_to_iproc_rng200(ctx->parent.device); + + size = iproc_rng200_read(rng200, &rand, sizeof(rand), RT_TRUE); + + if (size != sizeof(rand)) + { + return 0; + } + + return rand; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = iproc_rng200_rand, +}; + +static rt_err_t iproc_rng200_create(struct rt_hwcrypto_ctx *ctx) +{ + rt_err_t res = RT_EOK; + struct hwcrypto_rng *rng; + + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_RNG: + ctx->contex = RT_NULL; + + rng = rt_container_of(ctx, struct hwcrypto_rng, parent); + rng->ops = &rng_ops; + break; + + default: + res = -RT_ENOSYS; + break; + } + + return res; +} + +static void iproc_rng200_destroy(struct rt_hwcrypto_ctx *ctx) +{ + struct iproc_rng200 *rng200 = raw_to_iproc_rng200(ctx->device); + + iproc_rng200_cleanup(rng200); + + rt_free(ctx->contex); +} + +static rt_err_t iproc_rng200_copy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src) +{ + rt_err_t err = RT_EOK; + + switch (src->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_RNG: + break; + default: + err = -RT_ENOSYS; + break; + } + + return err; +} + +static void iproc_rng200_reset(struct rt_hwcrypto_ctx *ctx) +{ + struct iproc_rng200 *rng200 = raw_to_iproc_rng200(ctx->device); + + iproc_rng200_init(rng200); +} + +static const struct rt_hwcrypto_ops iproc_rng200_ops = +{ + .create = iproc_rng200_create, + .destroy = iproc_rng200_destroy, + .copy = iproc_rng200_copy, + .reset = iproc_rng200_reset, +}; + +static rt_err_t iproc_rng200_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct iproc_rng200 *rng200 = rt_calloc(1, sizeof(*rng200)); + + if (!rng200) + { + return -RT_ENOMEM; + } + + rng200->regs = rt_dm_dev_iomap(dev, 0); + + if (!rng200->regs) + { + err = -RT_EIO; + goto _fail; + } + + dev->user_data = rng200; + + rng200->parent.ops = &iproc_rng200_ops; + + if ((err = rt_hwcrypto_register(&rng200->parent, "hwrng"))) + { + goto _fail; + } + + iproc_rng200_init(rng200); + + return RT_EOK; + +_fail: + if (rng200->regs) + { + rt_iounmap(rng200->regs); + } + + rt_free(rng200); + + return err; +} + +static rt_err_t iproc_rng200_remove(struct rt_platform_device *pdev) +{ + struct iproc_rng200 *rng200 = pdev->parent.user_data; + + iproc_rng200_cleanup(rng200); + + rt_device_unregister(&rng200->parent.parent); + + rt_iounmap(rng200->regs); + rt_free(rng200); + + return RT_EOK; +} + +static const struct rt_ofw_node_id iproc_rng200_ofw_ids[] = +{ + { .compatible = "brcm,bcm2711-rng200", }, + { .compatible = "brcm,bcm7211-rng200", }, + { .compatible = "brcm,bcm7278-rng200", }, + { .compatible = "brcm,iproc-rng200", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver iproc_rng200_driver = +{ + .name = "iproc-rng200", + .ids = iproc_rng200_ofw_ids, + + .probe = iproc_rng200_probe, + .remove = iproc_rng200_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(iproc_rng200_driver); diff --git a/bsp/raspberry-pi/dm/i2c/Kconfig b/bsp/raspberry-pi/dm/i2c/Kconfig new file mode 100755 index 0000000000..86fe1e7115 --- /dev/null +++ b/bsp/raspberry-pi/dm/i2c/Kconfig @@ -0,0 +1,9 @@ +config RT_I2C_BCM2835 + bool "Broadcom BCM2835 I2C controller" + depends on RT_USING_PINCTRL + default n + +config RT_I2C_BRCMSTB + bool "BRCM Settop/DSL I2C controller" + depends on RT_USING_PINCTRL + default n diff --git a/bsp/raspberry-pi/dm/i2c/SConscript b/bsp/raspberry-pi/dm/i2c/SConscript new file mode 100755 index 0000000000..ffcbb27d7d --- /dev/null +++ b/bsp/raspberry-pi/dm/i2c/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_I2C_BCM2835']): + src += ['i2c-bcm2835.c'] + +if GetDepend(['RT_I2C_BRCMSTB']): + src += ['i2c-brcmstb.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/i2c/i2c-bcm2835.c b/bsp/raspberry-pi/dm/i2c/i2c-bcm2835.c new file mode 100755 index 0000000000..fe44841272 --- /dev/null +++ b/bsp/raspberry-pi/dm/i2c/i2c-bcm2835.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "i2c.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define BCM2835_I2C_C 0x0 +#define BCM2835_I2C_S 0x4 +#define BCM2835_I2C_DLEN 0x8 +#define BCM2835_I2C_A 0xc +#define BCM2835_I2C_FIFO 0x10 +#define BCM2835_I2C_DIV 0x14 +#define BCM2835_I2C_DEL 0x18 +/* + * 16-bit field for the number of SCL cycles to wait after rising SCL + * before deciding the slave is not responding. 0 disables the + * timeout detection. + */ +#define BCM2835_I2C_CLKT 0x1c + +#define BCM2835_I2C_C_READ RT_BIT(0) +#define BCM2835_I2C_C_CLEAR RT_BIT(4) /* bits 4 and 5 both clear */ +#define BCM2835_I2C_C_ST RT_BIT(7) +#define BCM2835_I2C_C_INTD RT_BIT(8) +#define BCM2835_I2C_C_INTT RT_BIT(9) +#define BCM2835_I2C_C_INTR RT_BIT(10) +#define BCM2835_I2C_C_I2CEN RT_BIT(15) + +#define BCM2835_I2C_S_TA RT_BIT(0) +#define BCM2835_I2C_S_DONE RT_BIT(1) +#define BCM2835_I2C_S_TXW RT_BIT(2) +#define BCM2835_I2C_S_RXR RT_BIT(3) +#define BCM2835_I2C_S_TXD RT_BIT(4) +#define BCM2835_I2C_S_RXD RT_BIT(5) +#define BCM2835_I2C_S_TXE RT_BIT(6) +#define BCM2835_I2C_S_RXF RT_BIT(7) +#define BCM2835_I2C_S_ERR RT_BIT(8) +#define BCM2835_I2C_S_CLKT RT_BIT(9) +#define BCM2835_I2C_S_LEN RT_BIT(10) /* Fake bit for SW error reporting */ + +#define BCM2835_I2C_FEDL_SHIFT 16 +#define BCM2835_I2C_REDL_SHIFT 0 + +#define BCM2835_I2C_CDIV_MIN 0x0002 +#define BCM2835_I2C_CDIV_MAX 0xfffe + +#define CLK_TOUT_MS 35 + +struct bcm2835_i2c +{ + struct rt_i2c_bus_device parent; + + void *regs; + int irq; + struct rt_clk *clk; + + struct rt_completion done; + + struct rt_i2c_msg *curr_msg; + int num_msgs; + rt_err_t msg_err; + rt_uint8_t *msg_buf; + rt_size_t msg_buf_remaining; +}; + +#define raw_to_bcm2835_i2c(raw) rt_container_of(raw, struct bcm2835_i2c, parent) + +rt_inline void bcm2835_i2c_writel(struct bcm2835_i2c *i2c, int offset, rt_uint32_t val) +{ + HWREG32(i2c->regs + offset) = val; +} + +rt_inline rt_uint32_t bcm2835_i2c_readl(struct bcm2835_i2c *i2c, int offset) +{ + return HWREG32(i2c->regs + offset); +} + +static void bcm2835_fill_txfifo(struct bcm2835_i2c *i2c) +{ + while (i2c->msg_buf_remaining) + { + if (!(bcm2835_i2c_readl(i2c, BCM2835_I2C_S) & BCM2835_I2C_S_TXD)) + { + break; + } + + bcm2835_i2c_writel(i2c, BCM2835_I2C_FIFO, *i2c->msg_buf); + + ++i2c->msg_buf; + --i2c->msg_buf_remaining; + } +} + +static void bcm2835_drain_rxfifo(struct bcm2835_i2c *i2c) +{ + while (i2c->msg_buf_remaining) + { + if (!(bcm2835_i2c_readl(i2c, BCM2835_I2C_S) & BCM2835_I2C_S_RXD)) + { + break; + } + + *i2c->msg_buf = bcm2835_i2c_readl(i2c, BCM2835_I2C_FIFO); + + ++i2c->msg_buf; + --i2c->msg_buf_remaining; + } +} + +static void bcm2835_i2c_start_transfer(struct bcm2835_i2c *i2c) +{ + rt_uint32_t c; + rt_bool_t last_msg; + struct rt_i2c_msg *msg = i2c->curr_msg; + + if (!i2c->num_msgs) + { + return; + } + + last_msg = (i2c->num_msgs == 1); + c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN; + + --i2c->num_msgs; + i2c->msg_buf = msg->buf; + i2c->msg_buf_remaining = msg->len; + rt_hw_rmb(); + + if (msg->flags & RT_I2C_RD) + { + c |= BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR; + } + else + { + c |= BCM2835_I2C_C_INTT; + } + + if (last_msg) + { + c |= BCM2835_I2C_C_INTD; + } + + bcm2835_i2c_writel(i2c, BCM2835_I2C_A, msg->addr); + bcm2835_i2c_writel(i2c, BCM2835_I2C_DLEN, msg->len); + bcm2835_i2c_writel(i2c, BCM2835_I2C_C, c); +} + +static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c *i2c) +{ + i2c->curr_msg = RT_NULL; + i2c->num_msgs = 0; + + i2c->msg_buf = RT_NULL; + i2c->msg_buf_remaining = 0; +} + +static rt_ssize_t bcm2835_i2c_master_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + rt_err_t err; + rt_bool_t ignore_nak = RT_FALSE; + struct bcm2835_i2c *i2c = raw_to_bcm2835_i2c(bus); + + for (int i = 0; i < num - 1; ++i) + { + if (msgs[i].flags & RT_I2C_RD) + { + return -RT_ENOSYS; + } + + if (msgs[i].flags & RT_I2C_IGNORE_NACK) + { + ignore_nak = RT_TRUE; + } + } + + i2c->curr_msg = msgs; + i2c->num_msgs = num; + i2c->msg_err = 0; + + bcm2835_i2c_start_transfer(i2c); + + err = rt_completion_wait(&i2c->done, RT_TICK_PER_SECOND); + + bcm2835_i2c_finish_transfer(i2c); + + if (ignore_nak) + { + i2c->msg_err &= ~BCM2835_I2C_S_ERR; + } + + if (err) + { + bcm2835_i2c_writel(i2c, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + + return -RT_ETIMEOUT; + } + + if (!i2c->msg_err) + { + return num; + } + + if (i2c->msg_err & BCM2835_I2C_S_ERR) + { + LOG_E("Bus error"); + } + + return -RT_EIO; +} + +const static struct rt_i2c_bus_device_ops bcm2835_i2c_ops = +{ + .master_xfer = bcm2835_i2c_master_xfer, +}; + +static void bcm2835_i2c_isr(int irqno, void *param) +{ + rt_uint32_t val, err; + struct bcm2835_i2c *i2c = param; + + val = bcm2835_i2c_readl(i2c, BCM2835_I2C_S); + + err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); + if (err && !(val & BCM2835_I2C_S_TA)) + { + i2c->msg_err = err; + } + + if (val & BCM2835_I2C_S_DONE) + { + if (!i2c->curr_msg) + { + LOG_E("Got unexpected interrupt (from firmware?)"); + } + else if (i2c->curr_msg->flags & RT_I2C_RD) + { + bcm2835_drain_rxfifo(i2c); + val = bcm2835_i2c_readl(i2c, BCM2835_I2C_S); + } + + if ((val & BCM2835_I2C_S_RXD) || i2c->msg_buf_remaining) + { + i2c->msg_err = BCM2835_I2C_S_LEN; + } + + goto _complete; + } + + if (val & BCM2835_I2C_S_TXW) + { + if (!i2c->msg_buf_remaining) + { + i2c->msg_err = val | BCM2835_I2C_S_LEN; + goto _complete; + } + + bcm2835_fill_txfifo(i2c); + + if (i2c->num_msgs && !i2c->msg_buf_remaining) + { + i2c->curr_msg++; + bcm2835_i2c_start_transfer(i2c); + } + + return; + } + + if (val & BCM2835_I2C_S_RXR) + { + if (!i2c->msg_buf_remaining) + { + i2c->msg_err = val | BCM2835_I2C_S_LEN; + goto _complete; + } + + bcm2835_drain_rxfifo(i2c); + } + + return; + +_complete: + bcm2835_i2c_writel(i2c, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + bcm2835_i2c_writel(i2c, BCM2835_I2C_S, BCM2835_I2C_S_CLKT | + BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE); + rt_completion_done(&i2c->done); +} + +static int clk_bcm2835_i2c_calc_divider(rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_uint32_t divider = RT_DIV_ROUND_UP(parent_rate, rate); + + if (divider & 1) + { + ++divider; + } + + if (divider < BCM2835_I2C_CDIV_MIN || divider > BCM2835_I2C_CDIV_MAX) + { + return -RT_EINVAL; + } + + return divider; +} + +static rt_err_t bcm2835_i2c_clk_set_rate(struct bcm2835_i2c *i2c, rt_ubase_t rate) +{ + rt_uint32_t redl, fedl, clk_tout, divider; + + divider = clk_bcm2835_i2c_calc_divider(rate, rt_clk_get_rate(i2c->clk)); + + if ((rt_int32_t)divider < 0) + { + return (rt_err_t)divider; + } + + bcm2835_i2c_writel(i2c, BCM2835_I2C_DIV, divider); + + /* + * Number of core clocks to wait after falling edge before + * outputting the next data bit. Note that both FEDL and REDL + * can't be greater than CDIV/2. + */ + fedl = rt_max(divider / 16, 1U); + + /* + * Number of core clocks to wait after rising edge before + * sampling the next incoming data bit. + */ + redl = rt_max(divider / 4, 1U); + + bcm2835_i2c_writel(i2c, BCM2835_I2C_DEL, + (fedl << BCM2835_I2C_FEDL_SHIFT) | (redl << BCM2835_I2C_REDL_SHIFT)); + + /* Set the clock stretch timeout. */ + if (rate > 0xffff * 1000 / CLK_TOUT_MS) + { + clk_tout = 0xffff; + } + else + { + clk_tout = CLK_TOUT_MS * rate / 1000; + } + + bcm2835_i2c_writel(i2c, BCM2835_I2C_CLKT, clk_tout); + + return RT_EOK; +} + +static void bcm2835_i2c_free(struct bcm2835_i2c *i2c) +{ + if (i2c->regs) + { + rt_iounmap(i2c->regs); + } + + if (!rt_is_err_or_null(i2c->clk)) + { + rt_clk_disable_unprepare(i2c->clk); + rt_clk_put(i2c->clk); + } + + rt_free(i2c); +} + +static rt_err_t bcm2835_i2c_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + rt_uint32_t bus_clk_rate; + struct rt_device *dev = &pdev->parent; + struct bcm2835_i2c *i2c = rt_calloc(1, sizeof(*i2c)); + + if (!i2c) + { + return -RT_ENOMEM; + } + + i2c->regs = rt_dm_dev_iomap(dev, 0); + + if (!i2c->regs) + { + err = -RT_EIO; + goto _fail; + } + + i2c->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(i2c->clk)) + { + err = rt_ptr_err(i2c->clk); + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "clock-frequency", &bus_clk_rate)) + { + bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; + } + + if ((err = bcm2835_i2c_clk_set_rate(i2c, bus_clk_rate))) + { + goto _fail; + } + + if ((err = rt_clk_prepare_enable(i2c->clk))) + { + goto _fail; + } + + i2c->irq = rt_dm_dev_get_irq(dev, 0); + + if (i2c->irq < 0) + { + err = i2c->irq; + goto _fail; + } + + /* + * Disable the hardware clock stretching timeout. SMBUS + * specifies a limit for how long the device can stretch the + * clock, but core I2C doesn't. + */ + bcm2835_i2c_writel(i2c, BCM2835_I2C_CLKT, 0); + bcm2835_i2c_writel(i2c, BCM2835_I2C_C, 0); + + rt_completion_init(&i2c->done); + + rt_dm_dev_set_name_auto(&i2c->parent.parent, "i2c"); + dev_name = rt_dm_dev_get_name(&i2c->parent.parent); + + rt_hw_interrupt_install(i2c->irq, bcm2835_i2c_isr, i2c, dev_name); + rt_hw_interrupt_umask(i2c->irq); + + dev->user_data = i2c; + + i2c->parent.ops = &bcm2835_i2c_ops; + i2c->parent.parent.ofw_node = dev->ofw_node; + + if ((err = rt_i2c_bus_device_register(&i2c->parent, dev_name))) + { + goto _free_irq; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2c); + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + +_fail: + bcm2835_i2c_free(i2c); + + return err; +} + +static rt_err_t bcm2835_i2c_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_i2c *i2c = pdev->parent.user_data; + + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + + rt_device_unregister(&i2c->parent.parent); + + bcm2835_i2c_free(i2c); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_i2c_ofw_ids[] = +{ + { .compatible = "brcm,bcm2711-i2c" }, + { .compatible = "brcm,bcm2835-i2c" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_i2c_driver = +{ + .name = "bcm2835-i2c", + .ids = bcm2835_i2c_ofw_ids, + + .probe = bcm2835_i2c_probe, + .remove = bcm2835_i2c_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_i2c_driver); diff --git a/bsp/raspberry-pi/dm/i2c/i2c-brcmstb.c b/bsp/raspberry-pi/dm/i2c/i2c-brcmstb.c new file mode 100755 index 0000000000..709d97e2fc --- /dev/null +++ b/bsp/raspberry-pi/dm/i2c/i2c-brcmstb.c @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "i2c.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define N_DATA_REGS 8 + +/* + * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register + * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per + * data register whereas STB SoCs use 4 byte per data register transfer, + * account for this difference in total count per transaction and mask to use. + */ +#define BSC_CNT_REG1_MASK(nb) (nb == 1 ? RT_GENMASK(3, 0) : RT_GENMASK(5, 0)) +#define BSC_CNT_REG1_SHIFT 0 + +/* BSC CTL register field definitions */ +#define BSC_CTL_REG_DTF_MASK 0x00000003 +#define BSC_CTL_REG_SCL_SEL_MASK 0x00000030 +#define BSC_CTL_REG_SCL_SEL_SHIFT 4 +#define BSC_CTL_REG_INT_EN_MASK 0x00000040 +#define BSC_CTL_REG_INT_EN_SHIFT 6 +#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080 + +/* BSC_IIC_ENABLE r/w enable and interrupt field definitions */ +#define BSC_IIC_EN_RESTART_MASK 0x00000040 +#define BSC_IIC_EN_NOSTART_MASK 0x00000020 +#define BSC_IIC_EN_NOSTOP_MASK 0x00000010 +#define BSC_IIC_EN_NOACK_MASK 0x00000004 +#define BSC_IIC_EN_INTRP_MASK 0x00000002 +#define BSC_IIC_EN_ENABLE_MASK 0x00000001 + +/* BSC_CTLHI control register field definitions */ +#define BSC_CTLHI_REG_DATAREG_SIZE_MASK 0x00000040 +#define BSC_CTLHI_REG_IGNORE_ACK_MASK 0x00000002 +#define BSC_CTLHI_REG_WAIT_DIS_MASK 0x00000001 + +#define I2C_TIMEOUT 100 /* msecs */ + +/* Condition mask used for non combined transfer */ +#define COND_RESTART BSC_IIC_EN_RESTART_MASK +#define COND_NOSTART BSC_IIC_EN_NOSTART_MASK +#define COND_NOSTOP BSC_IIC_EN_NOSTOP_MASK +#define COND_START_STOP (COND_RESTART | COND_NOSTART | COND_NOSTOP) + +/* BSC data transfer direction */ +#define DTF_WR_MASK 0x00000000 +#define DTF_RD_MASK 0x00000001 +/* BSC data transfer direction combined format */ +#define DTF_RD_WR_MASK 0x00000002 +#define DTF_WR_RD_MASK 0x00000003 + +#define AUTOI2C_CTRL0 0x26c +#define AUTOI2C_CTRL0_RELEASE_BSC RT_BIT(1) + +/* BSC block register map structure to cache fields to be written */ +struct bsc_regs +{ + rt_uint32_t chip_address; /* slave address */ + rt_uint32_t data_in[N_DATA_REGS]; /* tx data buffer*/ + rt_uint32_t cnt_reg; /* rx/tx data length */ + rt_uint32_t ctl_reg; /* control register */ + rt_uint32_t iic_enable; /* xfer enable and status */ + rt_uint32_t data_out[N_DATA_REGS]; /* rx data buffer */ + rt_uint32_t ctlhi_reg; /* more control fields */ + rt_uint32_t scl_param; /* reserved */ +}; + +struct bsc_clk_param +{ + rt_uint32_t hz; + rt_uint32_t scl_mask; + rt_uint32_t div_mask; +}; + +enum bsc_xfer_cmd +{ + CMD_WR, + CMD_RD, + CMD_WR_NOACK, + CMD_RD_NOACK, +}; + +enum bus_speeds +{ + SPD_375K, + SPD_390K, + SPD_187K, + SPD_200K, + SPD_93K, + SPD_97K, + SPD_46K, + SPD_50K, +}; + +static const struct bsc_clk_param bsc_clk[] = +{ + [SPD_375K] = + { + .hz = 375000, + .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0, + }, + [SPD_390K] = + { + .hz = 390000, + .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0, + }, + [SPD_187K] = + { + .hz = 187500, + .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0, + }, + [SPD_200K] = + { + .hz = 200000, + .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0, + }, + [SPD_93K] = + { + .hz = 93750, + .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK, + }, + [SPD_97K] = + { + .hz = 97500, + .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK, + }, + [SPD_46K] = + { + .hz = 46875, + .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK, + }, + [SPD_50K] = + { + .hz = 50000, + .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK, + } +}; + +struct brcmstb_i2c +{ + struct rt_i2c_bus_device parent; + + int irq; + void *base; + struct bsc_regs bsc_regmap; + + int data_regsz; + rt_uint32_t clk_freq_hz; + struct rt_completion done; +}; + +#define raw_to_brcmstb_i2c(raw) rt_container_of(raw, struct brcmstb_i2c, parent) + +#define bsc_readl(i2c, reg) HWREG32((i2c)->base + rt_offsetof(struct bsc_regs, reg)) +#define bsc_writel(i2c, reg, val) HWREG32((i2c)->base + rt_offsetof(struct bsc_regs, reg)) = (val) + +rt_inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c *i2c) +{ + return (N_DATA_REGS * i2c->data_regsz); +} + +rt_inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c *i2c) +{ + return i2c->data_regsz; +} + +static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c *i2c, rt_bool_t int_en) +{ + if (int_en) + { + /* Enable BSC CTL interrupt line */ + i2c->bsc_regmap.ctl_reg |= BSC_CTL_REG_INT_EN_MASK; + } + else + { + /* Disable BSC CTL interrupt line */ + i2c->bsc_regmap.ctl_reg &= ~BSC_CTL_REG_INT_EN_MASK; + } + + rt_hw_barrier(); + bsc_writel(i2c, ctl_reg, i2c->bsc_regmap.ctl_reg); +} + +/* Wait for device to be ready */ +static rt_err_t brcmstb_i2c_wait_if_busy(struct brcmstb_i2c *i2c) +{ + rt_tick_t timeout; + + timeout = rt_tick_from_millisecond(I2C_TIMEOUT); + timeout += rt_tick_get(); + + while ((bsc_readl(i2c, iic_enable) & BSC_IIC_EN_INTRP_MASK)) + { + if (rt_tick_get() > timeout) + { + return -RT_ETIMEOUT; + } + + rt_hw_cpu_relax(); + } + + return RT_EOK; +} + +/* i2c xfer completion function, handles both irq and polling mode */ +static rt_err_t brcmstb_i2c_wait_for_completion(struct brcmstb_i2c *i2c) +{ + rt_tick_t timeout; + rt_err_t err = RT_EOK; + + timeout = rt_tick_from_millisecond(I2C_TIMEOUT); + timeout += rt_tick_get(); + + if (i2c->irq >= 0) + { + err = rt_completion_wait(&i2c->done, timeout); + } + else + { + /* Polling mode */ + rt_uint32_t bsc_intrp; + + do { + bsc_intrp = bsc_readl(i2c, iic_enable) & BSC_IIC_EN_INTRP_MASK; + + if (rt_tick_get() > timeout) + { + err = -RT_ETIMEOUT; + break; + } + + rt_hw_cpu_relax(); + } while (!bsc_intrp); + } + + if (i2c->irq < 0 || err == -RT_ETIMEOUT) + { + brcmstb_i2c_enable_disable_irq(i2c, RT_FALSE); + } + + return err; +} + +/* Set xfer START/STOP conditions for subsequent transfer */ +static void brcmstb_set_i2c_start_stop(struct brcmstb_i2c *i2c, rt_uint32_t cond_flag) +{ + rt_uint32_t regval = i2c->bsc_regmap.iic_enable; + + i2c->bsc_regmap.iic_enable = (regval & ~COND_START_STOP) | cond_flag; +} + +/* Send I2C request check completion */ +static rt_err_t brcmstb_send_i2c_cmd(struct brcmstb_i2c *i2c, enum bsc_xfer_cmd cmd) +{ + rt_err_t err; + struct bsc_regs *pi2creg = &i2c->bsc_regmap; + + /* Make sure the hardware is ready */ + if ((err = brcmstb_i2c_wait_if_busy(i2c))) + { + return err; + } + + /* Enable BSC CTL interrupt line */ + brcmstb_i2c_enable_disable_irq(i2c, RT_TRUE); + + /* Initiate transfer by setting iic_enable */ + pi2creg->iic_enable |= BSC_IIC_EN_ENABLE_MASK; + bsc_writel(i2c, iic_enable, pi2creg->iic_enable); + + /* Wait for transaction to finish or timeout */ + if ((err = brcmstb_i2c_wait_for_completion(i2c))) + { + goto _cmd_out; + } + + if ((cmd == CMD_RD || cmd == CMD_WR) && bsc_readl(i2c, iic_enable) & BSC_IIC_EN_NOACK_MASK) + { + err = -RT_EIO; + } + +_cmd_out: + bsc_writel(i2c, cnt_reg, 0); + bsc_writel(i2c, iic_enable, 0); + + return err; +} + +/* Actual data transfer through the BSC master */ +static rt_err_t brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c *i2c, + rt_uint8_t *buf, rt_size_t len, struct rt_i2c_msg *msg) +{ + rt_err_t err; + int data_regsz; + rt_uint32_t ctl_reg; + enum bsc_xfer_cmd cmd; + struct bsc_regs *pi2creg = &i2c->bsc_regmap; + + data_regsz = brcmstb_i2c_get_data_regsz(i2c); + + if (msg->flags & RT_I2C_IGNORE_NACK) + { + cmd = (msg->flags & RT_I2C_RD) ? CMD_RD_NOACK : CMD_WR_NOACK; + pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; + } + else + { + cmd = (msg->flags & RT_I2C_RD) ? CMD_RD : CMD_WR; + pi2creg->ctlhi_reg &= ~BSC_CTLHI_REG_IGNORE_ACK_MASK; + } + bsc_writel(i2c, ctlhi_reg, pi2creg->ctlhi_reg); + + /* Set data transfer direction */ + ctl_reg = pi2creg->ctl_reg & ~BSC_CTL_REG_DTF_MASK; + + if (cmd == CMD_WR || cmd == CMD_WR_NOACK) + { + pi2creg->ctl_reg = ctl_reg | DTF_WR_MASK; + } + else + { + pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK; + } + + /* Set the read/write length */ + bsc_writel(i2c, cnt_reg, BSC_CNT_REG1_MASK(data_regsz) & (len << BSC_CNT_REG1_SHIFT)); + + /* Write data into data_in register */ + if (cmd == CMD_WR || cmd == CMD_WR_NOACK) + { + for (int cnt = 0, i = 0; cnt < len; cnt += data_regsz, ++i) + { + rt_uint32_t word = 0; + + for (int byte = 0; byte < data_regsz; ++byte) + { + word >>= RT_BITS_PER_BYTE; + + if ((cnt + byte) < len) + { + word |= buf[cnt + byte] << (RT_BITS_PER_BYTE * (data_regsz - 1)); + } + } + + bsc_writel(i2c, data_in[i], word); + } + } + + /* Initiate xfer, the function will return on completion */ + if ((err = brcmstb_send_i2c_cmd(i2c, cmd))) + { + return err; + } + + /* Read data from data_out register */ + if (cmd == CMD_RD || cmd == CMD_RD_NOACK) + { + for (int cnt = 0, i = 0; cnt < len; cnt += data_regsz, ++i) + { + rt_uint32_t data = bsc_readl(i2c, data_out[i]); + + for (int byte = 0; byte < data_regsz && byte + cnt < len; ++byte) + { + buf[cnt + byte] = data & 0xff; + data >>= RT_BITS_PER_BYTE; + } + } + } + + return RT_EOK; +} + +/* Write a single byte of data to the i2c bus */ +static rt_err_t brcmstb_i2c_write_data_byte(struct brcmstb_i2c *i2c, + rt_uint32_t *buf, rt_uint32_t nak_expected) +{ + enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK; + + bsc_writel(i2c, cnt_reg, 1); + bsc_writel(i2c, data_in, *buf); + + return brcmstb_send_i2c_cmd(i2c, cmd); +} + +/* Send i2c address */ +static rt_err_t brcmstb_i2c_do_addr(struct brcmstb_i2c *i2c, struct rt_i2c_msg *msg) +{ + rt_err_t err; + rt_uint8_t addr; + + if (msg->flags & RT_I2C_ADDR_10BIT) + { + /* First byte is 11110XX0 where XX is upper 2 bits */ + addr = 0xf0 | ((msg->addr & 0x300) >> 7); + bsc_writel(i2c, chip_address, addr); + + /* Second byte is the remaining 8 bits */ + addr = msg->addr & 0xff; + if ((err = brcmstb_i2c_write_data_byte(i2c, (void *)&addr, 0))) + { + return err; + } + + if (msg->flags & RT_I2C_RD) + { + /* For read, send restart without stop condition */ + brcmstb_set_i2c_start_stop(i2c, COND_RESTART | COND_NOSTOP); + + /* Then re-send the first byte with the read bit set */ + addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01; + if ((err = brcmstb_i2c_write_data_byte(i2c, (void *)&addr, 0))) + { + return err; + } + } + } + else + { + /* 8bit addr from msg */ + addr = (msg->addr << 1) | (msg->flags & RT_I2C_RD ? 1 : 0);; + bsc_writel(i2c, chip_address, addr); + } + + return RT_EOK; +} + +static rt_ssize_t brcmstb_i2c_master_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + rt_err_t err; + rt_uint8_t *tmp_buf; + int bytes_to_xfer, xfersz, len; + rt_uint32_t cond, cond_per_msg; + struct rt_i2c_msg *pmsg; + struct brcmstb_i2c *i2c = raw_to_brcmstb_i2c(bus); + + xfersz = brcmstb_i2c_get_xfersz(i2c); + + /* Loop through all messages */ + for (int i = 0; i < num; ++i) + { + pmsg = &msgs[i]; + len = pmsg->len; + tmp_buf = pmsg->buf; + + if (i < num - 1 && (msgs[i + 1].flags & RT_I2C_NO_START)) + { + cond = ~COND_START_STOP; + } + else + { + cond = COND_RESTART | COND_NOSTOP; + } + + brcmstb_set_i2c_start_stop(i2c, cond); + + /* Send slave address */ + if (!(pmsg->flags & RT_I2C_NO_START)) + { + if ((err = brcmstb_i2c_do_addr(i2c, pmsg))) + { + return err; + } + } + + cond_per_msg = cond; + + /* Perform data transfer */ + while (len) + { + bytes_to_xfer = rt_min(len, xfersz); + + if (len <= xfersz) + { + if (i == num - 1) + { + cond_per_msg = cond_per_msg & ~(COND_RESTART | COND_NOSTOP); + } + else + { + cond_per_msg = cond; + } + } + else + { + cond_per_msg = (cond_per_msg & ~COND_RESTART) | COND_NOSTOP; + } + + brcmstb_set_i2c_start_stop(i2c, cond_per_msg); + + if ((err = brcmstb_i2c_xfer_bsc_data(i2c, tmp_buf, bytes_to_xfer, pmsg))) + { + return err; + } + + len -= bytes_to_xfer; + tmp_buf += bytes_to_xfer; + + cond_per_msg = COND_NOSTART | COND_NOSTOP; + } + } + + return num; +} + +const static struct rt_i2c_bus_device_ops brcmstb_i2c_ops = +{ + .master_xfer = brcmstb_i2c_master_xfer, +}; + +static void brcmstb_i2c_isr(int irq, void *param) +{ + rt_uint32_t status_bsc_ctl; + struct brcmstb_i2c *i2c = param; + + status_bsc_ctl = bsc_readl(i2c, ctl_reg); + + if (!(status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK)) + { + return; + } + + brcmstb_i2c_enable_disable_irq(i2c, RT_FALSE); + rt_completion_done(&i2c->done); +} + +static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c *i2c) +{ + int i, num_speeds = RT_ARRAY_SIZE(bsc_clk); + rt_uint32_t clk_freq_hz = i2c->clk_freq_hz; + + if (brcmstb_i2c_get_data_regsz(i2c) == sizeof(rt_uint32_t)) + { + i2c->bsc_regmap.ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK; + } + else + { + i2c->bsc_regmap.ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK; + } + + bsc_writel(i2c, ctlhi_reg, i2c->bsc_regmap.ctlhi_reg); + + /* Set bus speed */ + for (i = 0; i < num_speeds; ++i) + { + if (bsc_clk[i].hz == clk_freq_hz) + { + i2c->bsc_regmap.ctl_reg &= ~(BSC_CTL_REG_SCL_SEL_MASK | BSC_CTL_REG_DIV_CLK_MASK); + i2c->bsc_regmap.ctl_reg |= bsc_clk[i].scl_mask | bsc_clk[i].div_mask; + bsc_writel(i2c, ctl_reg, i2c->bsc_regmap.ctl_reg); + break; + } + } + + /* in case we did not get find a valid speed */ + if (i == num_speeds) + { + i = (bsc_readl(i2c, ctl_reg) & BSC_CTL_REG_SCL_SEL_MASK) >> BSC_CTL_REG_SCL_SEL_SHIFT; + } +} + +static void brcmstb_i2c_free(struct brcmstb_i2c *i2c) +{ + if (i2c->base) + { + rt_iounmap(i2c->base); + } + + rt_free(i2c); +} + +static rt_err_t brcmstb_i2c_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + void *autoi2c; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct brcmstb_i2c *i2c = rt_calloc(1, sizeof(*i2c)); + + if (!i2c) + { + return -RT_ENOMEM; + } + + i2c->base = rt_dm_dev_iomap(dev, 0); + + if (!i2c->base) + { + err = -RT_EIO; + goto _fail; + } + + if (rt_dm_dev_prop_read_bool(dev, "reg-names")) + { + if (!(autoi2c = rt_dm_dev_iomap_by_name(dev, "auto-i2c"))) + { + err = -RT_EIO; + goto _fail; + } + + HWREG32(autoi2c + AUTOI2C_CTRL0) = AUTOI2C_CTRL0_RELEASE_BSC; + rt_iounmap(autoi2c); + + i2c->bsc_regmap.iic_enable = 0; + bsc_writel(i2c, iic_enable, i2c->bsc_regmap.iic_enable); + } + + i2c->irq = rt_dm_dev_get_irq(dev, 0); + + brcmstb_i2c_enable_disable_irq(i2c, RT_FALSE); + + if (rt_dm_dev_prop_read_u32(dev, "clock-frequency", &i2c->clk_freq_hz)) + { + i2c->clk_freq_hz = bsc_clk[0].hz; + } + + if (rt_ofw_node_is_compatible(dev->ofw_node, "brcm,brcmper-i2c")) + { + i2c->data_regsz = sizeof(rt_uint8_t); + } + else + { + i2c->data_regsz = sizeof(rt_uint32_t); + } + + brcmstb_i2c_set_bsc_reg_defaults(i2c); + + rt_completion_init(&i2c->done); + + rt_dm_dev_set_name_auto(&i2c->parent.parent, "i2c"); + dev_name = rt_dm_dev_get_name(&i2c->parent.parent); + + if (i2c->irq >= 0) + { + rt_hw_interrupt_install(i2c->irq, brcmstb_i2c_isr, i2c, dev_name); + rt_hw_interrupt_umask(i2c->irq); + } + + dev->user_data = i2c; + + i2c->parent.ops = &brcmstb_i2c_ops; + i2c->parent.parent.ofw_node = dev->ofw_node; + + if ((err = rt_i2c_bus_device_register(&i2c->parent, dev_name))) + { + goto _free_irq; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, i2c); + + return RT_EOK; +_free_irq: + if (i2c->irq >= 0) + { + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + } + +_fail: + brcmstb_i2c_free(i2c); + + return err; +} + +static rt_err_t brcmstb_i2c_remove(struct rt_platform_device *pdev) +{ + struct brcmstb_i2c *i2c = pdev->parent.user_data; + + if (i2c->irq >= 0) + { + rt_hw_interrupt_mask(i2c->irq); + rt_pic_detach_irq(i2c->irq, i2c); + } + + rt_device_unregister(&i2c->parent.parent); + + brcmstb_i2c_free(i2c); + + return RT_EOK; +} + +static const struct rt_ofw_node_id brcmstb_i2c_ofw_ids[] = +{ + { .compatible = "brcm,brcmstb-i2c" }, + { .compatible = "brcm,brcmper-i2c" }, + { .compatible = "brcm,bcm2711-hdmi-i2c" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmstb_i2c_driver = +{ + .name = "brcmstb-i2c", + .ids = brcmstb_i2c_ofw_ids, + + .probe = brcmstb_i2c_probe, + .remove = brcmstb_i2c_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(brcmstb_i2c_driver); diff --git a/bsp/raspberry-pi/dm/include/bcm2835-pm.h b/bsp/raspberry-pi/dm/include/bcm2835-pm.h new file mode 100755 index 0000000000..1cf48f9be1 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/bcm2835-pm.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __BCM2835_PM_H__ +#define __BCM2835_PM_H__ + +struct bcm2835_pm +{ + void *base; + void *asb; + void *rpivid_asb; + + void *ofw_node; +}; + +#endif /* __BCM2835_PM_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835-aux.h b/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835-aux.h new file mode 100755 index 0000000000..189b2b48ad --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835-aux.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_BCM2835_AUX_H__ +#define __DT_BINDINGS_CLOCK_BCM2835_AUX_H__ + +#define BCM2835_AUX_CLOCK_UART 0 +#define BCM2835_AUX_CLOCK_SPI1 1 +#define BCM2835_AUX_CLOCK_SPI2 2 +#define BCM2835_AUX_CLOCK_COUNT 3 + +#endif /* __DT_BINDINGS_CLOCK_BCM2835_AUX_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835.h b/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835.h new file mode 100755 index 0000000000..0182e3aac7 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/clock/bcm2835.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_BCM2835_H__ +#define __DT_BINDINGS_CLOCK_BCM2835_H__ + +#define BCM2835_PLLA 0 +#define BCM2835_PLLB 1 +#define BCM2835_PLLC 2 +#define BCM2835_PLLD 3 +#define BCM2835_PLLH 4 + +#define BCM2835_PLLA_CORE 5 +#define BCM2835_PLLA_PER 6 +#define BCM2835_PLLB_ARM 7 +#define BCM2835_PLLC_CORE0 8 +#define BCM2835_PLLC_CORE1 9 +#define BCM2835_PLLC_CORE2 10 +#define BCM2835_PLLC_PER 11 +#define BCM2835_PLLD_CORE 12 +#define BCM2835_PLLD_PER 13 +#define BCM2835_PLLH_RCAL 14 +#define BCM2835_PLLH_AUX 15 +#define BCM2835_PLLH_PIX 16 + +#define BCM2835_CLOCK_TIMER 17 +#define BCM2835_CLOCK_OTP 18 +#define BCM2835_CLOCK_UART 19 +#define BCM2835_CLOCK_VPU 20 +#define BCM2835_CLOCK_V3D 21 +#define BCM2835_CLOCK_ISP 22 +#define BCM2835_CLOCK_H264 23 +#define BCM2835_CLOCK_VEC 24 +#define BCM2835_CLOCK_HSM 25 +#define BCM2835_CLOCK_SDRAM 26 +#define BCM2835_CLOCK_TSENS 27 +#define BCM2835_CLOCK_EMMC 28 +#define BCM2835_CLOCK_PERI_IMAGE 29 +#define BCM2835_CLOCK_PWM 30 +#define BCM2835_CLOCK_PCM 31 + +#define BCM2835_PLLA_DSI0 32 +#define BCM2835_PLLA_CCP2 33 +#define BCM2835_PLLD_DSI0 34 +#define BCM2835_PLLD_DSI1 35 + +#define BCM2835_CLOCK_AVEO 36 +#define BCM2835_CLOCK_DFT 37 +#define BCM2835_CLOCK_GP0 38 +#define BCM2835_CLOCK_GP1 39 +#define BCM2835_CLOCK_GP2 40 +#define BCM2835_CLOCK_SLIM 41 +#define BCM2835_CLOCK_SMI 42 +#define BCM2835_CLOCK_TEC 43 +#define BCM2835_CLOCK_DPI 44 +#define BCM2835_CLOCK_CAM0 45 +#define BCM2835_CLOCK_CAM1 46 +#define BCM2835_CLOCK_DSI0E 47 +#define BCM2835_CLOCK_DSI1E 48 +#define BCM2835_CLOCK_DSI0P 49 +#define BCM2835_CLOCK_DSI1P 50 + +#define BCM2711_CLOCK_EMMC2 51 + +#endif /* __DT_BINDINGS_CLOCK_BCM2835_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/clock/rp1.h b/bsp/raspberry-pi/dm/include/dt-bindings/clock/rp1.h new file mode 100755 index 0000000000..da56a95a90 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/clock/rp1.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_RP1_H__ +#define __DT_BINDINGS_CLOCK_RP1_H__ + +#define RP1_PLL_SYS_CORE 0 +#define RP1_PLL_AUDIO_CORE 1 +#define RP1_PLL_VIDEO_CORE 2 + +#define RP1_PLL_SYS 3 +#define RP1_PLL_AUDIO 4 +#define RP1_PLL_VIDEO 5 + +#define RP1_PLL_SYS_PRI_PH 6 +#define RP1_PLL_SYS_SEC_PH 7 +#define RP1_PLL_AUDIO_PRI_PH 8 + +#define RP1_PLL_SYS_SEC 9 +#define RP1_PLL_AUDIO_SEC 10 +#define RP1_PLL_VIDEO_SEC 11 + +#define RP1_CLK_SYS 12 +#define RP1_CLK_SLOW_SYS 13 +#define RP1_CLK_DMA 14 +#define RP1_CLK_UART 15 +#define RP1_CLK_ETH 16 +#define RP1_CLK_PWM0 17 +#define RP1_CLK_PWM1 18 +#define RP1_CLK_AUDIO_IN 19 +#define RP1_CLK_AUDIO_OUT 20 +#define RP1_CLK_I2S 21 +#define RP1_CLK_MIPI0_CFG 22 +#define RP1_CLK_MIPI1_CFG 23 +#define RP1_CLK_PCIE_AUX 24 +#define RP1_CLK_USBH0_MICROFRAME 25 +#define RP1_CLK_USBH1_MICROFRAME 26 +#define RP1_CLK_USBH0_SUSPEND 27 +#define RP1_CLK_USBH1_SUSPEND 28 +#define RP1_CLK_ETH_TSU 29 +#define RP1_CLK_ADC 30 +#define RP1_CLK_SDIO_TIMER 31 +#define RP1_CLK_SDIO_ALT_SRC 32 +#define RP1_CLK_GP0 33 +#define RP1_CLK_GP1 34 +#define RP1_CLK_GP2 35 +#define RP1_CLK_GP3 36 +#define RP1_CLK_GP4 37 +#define RP1_CLK_GP5 38 +#define RP1_CLK_VEC 39 +#define RP1_CLK_DPI 40 +#define RP1_CLK_MIPI0_DPI 41 +#define RP1_CLK_MIPI1_DPI 42 + +/* Extra PLL output channels - RP1B0 only */ +#define RP1_PLL_VIDEO_PRI_PH 43 +#define RP1_PLL_AUDIO_TERN 44 + +/* MIPI clocks managed by the DSI driver */ +#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45 +#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46 + +#endif /* __DT_BINDINGS_CLOCK_RP1_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/mfd/rp1.h b/bsp/raspberry-pi/dm/include/dt-bindings/mfd/rp1.h new file mode 100755 index 0000000000..c935229840 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/mfd/rp1.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_MFD_RP1_H__ +#define __DT_BINDINGS_MFD_RP1_H__ + +/* Address map */ +#define RP1_SYSINFO_BASE 0x000000 +#define RP1_TBMAN_BASE 0x004000 +#define RP1_SYSCFG_BASE 0x008000 +#define RP1_OTP_BASE 0x00c000 +#define RP1_POWER_BASE 0x010000 +#define RP1_RESETS_BASE 0x014000 +#define RP1_CLOCKS_BANK_DEFAULT_BASE 0x018000 +#define RP1_CLOCKS_BANK_VIDEO_BASE 0x01c000 +#define RP1_PLL_SYS_BASE 0x020000 +#define RP1_PLL_AUDIO_BASE 0x024000 +#define RP1_PLL_VIDEO_BASE 0x028000 +#define RP1_UART0_BASE 0x030000 +#define RP1_UART1_BASE 0x034000 +#define RP1_UART2_BASE 0x038000 +#define RP1_UART3_BASE 0x03c000 +#define RP1_UART4_BASE 0x040000 +#define RP1_UART5_BASE 0x044000 +#define RP1_SPI8_BASE 0x04c000 +#define RP1_SPI0_BASE 0x050000 +#define RP1_SPI1_BASE 0x054000 +#define RP1_SPI2_BASE 0x058000 +#define RP1_SPI3_BASE 0x05c000 +#define RP1_SPI4_BASE 0x060000 +#define RP1_SPI5_BASE 0x064000 +#define RP1_SPI6_BASE 0x068000 +#define RP1_SPI7_BASE 0x06c000 +#define RP1_I2C0_BASE 0x070000 +#define RP1_I2C1_BASE 0x074000 +#define RP1_I2C2_BASE 0x078000 +#define RP1_I2C3_BASE 0x07c000 +#define RP1_I2C4_BASE 0x080000 +#define RP1_I2C5_BASE 0x084000 +#define RP1_I2C6_BASE 0x088000 +#define RP1_AUDIO_IN_BASE 0x090000 +#define RP1_AUDIO_OUT_BASE 0x094000 +#define RP1_PWM0_BASE 0x098000 +#define RP1_PWM1_BASE 0x09c000 +#define RP1_I2S0_BASE 0x0a0000 +#define RP1_I2S1_BASE 0x0a4000 +#define RP1_I2S2_BASE 0x0a8000 +#define RP1_TIMER_BASE 0x0ac000 +#define RP1_SDIO0_APBS_BASE 0x0b0000 +#define RP1_SDIO1_APBS_BASE 0x0b4000 +#define RP1_BUSFABRIC_MONITOR_BASE 0x0c0000 +#define RP1_BUSFABRIC_AXISHIM_BASE 0x0c4000 +#define RP1_ADC_BASE 0x0c8000 +#define RP1_IO_BANK0_BASE 0x0d0000 +#define RP1_IO_BANK1_BASE 0x0d4000 +#define RP1_IO_BANK2_BASE 0x0d8000 +#define RP1_SYS_RIO0_BASE 0x0e0000 +#define RP1_SYS_RIO1_BASE 0x0e4000 +#define RP1_SYS_RIO2_BASE 0x0e8000 +#define RP1_PADS_BANK0_BASE 0x0f0000 +#define RP1_PADS_BANK1_BASE 0x0f4000 +#define RP1_PADS_BANK2_BASE 0x0f8000 +#define RP1_PADS_ETH_BASE 0x0fc000 +#define RP1_ETH_IP_BASE 0x100000 +#define RP1_ETH_CFG_BASE 0x104000 +#define RP1_PCIE_APBS_BASE 0x108000 +#define RP1_MIPI0_CSIDMA_BASE 0x110000 +#define RP1_MIPI0_CSIHOST_BASE 0x114000 +#define RP1_MIPI0_DSIDMA_BASE 0x118000 +#define RP1_MIPI0_DSIHOST_BASE 0x11c000 +#define RP1_MIPI0_MIPICFG_BASE 0x120000 +#define RP1_MIPI0_ISP_BASE 0x124000 +#define RP1_MIPI1_CSIDMA_BASE 0x128000 +#define RP1_MIPI1_CSIHOST_BASE 0x12c000 +#define RP1_MIPI1_DSIDMA_BASE 0x130000 +#define RP1_MIPI1_DSIHOST_BASE 0x134000 +#define RP1_MIPI1_MIPICFG_BASE 0x138000 +#define RP1_MIPI1_ISP_BASE 0x13c000 +#define RP1_VIDEO_OUT_CFG_BASE 0x140000 +#define RP1_VIDEO_OUT_VEC_BASE 0x144000 +#define RP1_VIDEO_OUT_DPI_BASE 0x148000 +#define RP1_XOSC_BASE 0x150000 +#define RP1_WATCHDOG_BASE 0x154000 +#define RP1_DMA_TICK_BASE 0x158000 +#define RP1_SDIO_CLOCKS_BASE 0x15c000 +#define RP1_USBHOST0_APBS_BASE 0x160000 +#define RP1_USBHOST1_APBS_BASE 0x164000 +#define RP1_ROSC0_BASE 0x168000 +#define RP1_ROSC1_BASE 0x16c000 +#define RP1_VBUSCTRL_BASE 0x170000 +#define RP1_TICKS_BASE 0x174000 +#define RP1_PIO_APBS_BASE 0x178000 +#define RP1_SDIO0_AHBLS_BASE 0x180000 +#define RP1_SDIO1_AHBLS_BASE 0x184000 +#define RP1_DMA_BASE 0x188000 +#define RP1_RAM_BASE 0x1c0000 +#define RP1_RAM_SIZE 0x020000 +#define RP1_USBHOST0_AXIS_BASE 0x200000 +#define RP1_USBHOST1_AXIS_BASE 0x300000 +#define RP1_EXAC_BASE 0x400000 + +/* Interrupts */ + +#define RP1_INT_IO_BANK0 0 +#define RP1_INT_IO_BANK1 1 +#define RP1_INT_IO_BANK2 2 +#define RP1_INT_AUDIO_IN 3 +#define RP1_INT_AUDIO_OUT 4 +#define RP1_INT_PWM0 5 +#define RP1_INT_ETH 6 +#define RP1_INT_I2C0 7 +#define RP1_INT_I2C1 8 +#define RP1_INT_I2C2 9 +#define RP1_INT_I2C3 10 +#define RP1_INT_I2C4 11 +#define RP1_INT_I2C5 12 +#define RP1_INT_I2C6 13 +#define RP1_INT_I2S0 14 +#define RP1_INT_I2S1 15 +#define RP1_INT_I2S2 16 +#define RP1_INT_SDIO0 17 +#define RP1_INT_SDIO1 18 +#define RP1_INT_SPI0 19 +#define RP1_INT_SPI1 20 +#define RP1_INT_SPI2 21 +#define RP1_INT_SPI3 22 +#define RP1_INT_SPI4 23 +#define RP1_INT_SPI5 24 +#define RP1_INT_UART0 25 +#define RP1_INT_TIMER_0 26 +#define RP1_INT_TIMER_1 27 +#define RP1_INT_TIMER_2 28 +#define RP1_INT_TIMER_3 29 +#define RP1_INT_USBHOST0 30 +#define RP1_INT_USBHOST0_0 31 +#define RP1_INT_USBHOST0_1 32 +#define RP1_INT_USBHOST0_2 33 +#define RP1_INT_USBHOST0_3 34 +#define RP1_INT_USBHOST1 35 +#define RP1_INT_USBHOST1_0 36 +#define RP1_INT_USBHOST1_1 37 +#define RP1_INT_USBHOST1_2 38 +#define RP1_INT_USBHOST1_3 39 +#define RP1_INT_DMA 40 +#define RP1_INT_PWM1 41 +#define RP1_INT_UART1 42 +#define RP1_INT_UART2 43 +#define RP1_INT_UART3 44 +#define RP1_INT_UART4 45 +#define RP1_INT_UART5 46 +#define RP1_INT_MIPI0 47 +#define RP1_INT_MIPI1 48 +#define RP1_INT_VIDEO_OUT 49 +#define RP1_INT_PIO_0 50 +#define RP1_INT_PIO_1 51 +#define RP1_INT_ADC_FIFO 52 +#define RP1_INT_PCIE_OUT 53 +#define RP1_INT_SPI6 54 +#define RP1_INT_SPI7 55 +#define RP1_INT_SPI8 56 +#define RP1_INT_SYSCFG 58 +#define RP1_INT_CLOCKS_DEFAULT 59 +#define RP1_INT_VBUSCTRL 60 +#define RP1_INT_PROC_MISC 57 +#define RP1_INT_END 61 + +/* DMA peripherals (for pacing) */ +#define RP1_DMA_I2C0_RX 0x0 +#define RP1_DMA_I2C0_TX 0x1 +#define RP1_DMA_I2C1_RX 0x2 +#define RP1_DMA_I2C1_TX 0x3 +#define RP1_DMA_I2C2_RX 0x4 +#define RP1_DMA_I2C2_TX 0x5 +#define RP1_DMA_I2C3_RX 0x6 +#define RP1_DMA_I2C3_TX 0x7 +#define RP1_DMA_I2C4_RX 0x8 +#define RP1_DMA_I2C4_TX 0x9 +#define RP1_DMA_I2C5_RX 0xa +#define RP1_DMA_I2C5_TX 0xb +#define RP1_DMA_SPI0_RX 0xc +#define RP1_DMA_SPI0_TX 0xd +#define RP1_DMA_SPI1_RX 0xe +#define RP1_DMA_SPI1_TX 0xf +#define RP1_DMA_SPI2_RX 0x10 +#define RP1_DMA_SPI2_TX 0x11 +#define RP1_DMA_SPI3_RX 0x12 +#define RP1_DMA_SPI3_TX 0x13 +#define RP1_DMA_SPI4_RX 0x14 +#define RP1_DMA_SPI4_TX 0x15 +#define RP1_DMA_SPI5_RX 0x16 +#define RP1_DMA_SPI5_TX 0x17 +#define RP1_DMA_PWM0 0x18 +#define RP1_DMA_UART0_RX 0x19 +#define RP1_DMA_UART0_TX 0x1a +#define RP1_DMA_AUDIO_IN_CH0 0x1b +#define RP1_DMA_AUDIO_IN_CH1 0x1c +#define RP1_DMA_AUDIO_OUT 0x1d +#define RP1_DMA_PWM1 0x1e +#define RP1_DMA_I2S0_RX 0x1f +#define RP1_DMA_I2S0_TX 0x20 +#define RP1_DMA_I2S1_RX 0x21 +#define RP1_DMA_I2S1_TX 0x22 +#define RP1_DMA_I2S2_RX 0x23 +#define RP1_DMA_I2S2_TX 0x24 +#define RP1_DMA_UART1_RX 0x25 +#define RP1_DMA_UART1_TX 0x26 +#define RP1_DMA_UART2_RX 0x27 +#define RP1_DMA_UART2_TX 0x28 +#define RP1_DMA_UART3_RX 0x29 +#define RP1_DMA_UART3_TX 0x2a +#define RP1_DMA_UART4_RX 0x2b +#define RP1_DMA_UART4_TX 0x2c +#define RP1_DMA_UART5_RX 0x2d +#define RP1_DMA_UART5_TX 0x2e +#define RP1_DMA_ADC 0x2f +#define RP1_DMA_DMA_TICK_TICK0 0x30 +#define RP1_DMA_DMA_TICK_TICK1 0x31 +#define RP1_DMA_SPI6_RX 0x32 +#define RP1_DMA_SPI6_TX 0x33 +#define RP1_DMA_SPI7_RX 0x34 +#define RP1_DMA_SPI7_TX 0x35 +#define RP1_DMA_SPI8_RX 0x36 +#define RP1_DMA_SPI8_TX 0x37 +#define RP1_DMA_PIO_CH0_TX 0x38 +#define RP1_DMA_PIO_CH0_RX 0x39 +#define RP1_DMA_PIO_CH1_TX 0x3a +#define RP1_DMA_PIO_CH1_RX 0x3b +#define RP1_DMA_PIO_CH2_TX 0x3c +#define RP1_DMA_PIO_CH2_RX 0x3d +#define RP1_DMA_PIO_CH3_TX 0x3e +#define RP1_DMA_PIO_CH3_RX 0x3f + +#endif /* __DT_BINDINGS_MFD_RP1_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/pinctrl/bcm2835.h b/bsp/raspberry-pi/dm/include/dt-bindings/pinctrl/bcm2835.h new file mode 100755 index 0000000000..c98752b200 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/pinctrl/bcm2835.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PINCTRL_BCM2835_H__ +#define __DT_BINDINGS_PINCTRL_BCM2835_H__ + +/* brcm,function property */ +#define BCM2835_FSEL_GPIO_IN 0 +#define BCM2835_FSEL_GPIO_OUT 1 +#define BCM2835_FSEL_ALT5 2 +#define BCM2835_FSEL_ALT4 3 +#define BCM2835_FSEL_ALT0 4 +#define BCM2835_FSEL_ALT1 5 +#define BCM2835_FSEL_ALT2 6 +#define BCM2835_FSEL_ALT3 7 + +/* brcm,pull property */ +#define BCM2835_PUD_OFF 0 +#define BCM2835_PUD_DOWN 1 +#define BCM2835_PUD_UP 2 + +#endif /* __DT_BINDINGS_PINCTRL_BCM2835_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/power/bcm2835-pm.h b/bsp/raspberry-pi/dm/include/dt-bindings/power/bcm2835-pm.h new file mode 100755 index 0000000000..5864167be0 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/power/bcm2835-pm.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_POWER_BCM2835_PM_H__ +#define __DT_BINDINGS_POWER_BCM2835_PM_H__ + +#define BCM2835_POWER_DOMAIN_GRAFX 0 +#define BCM2835_POWER_DOMAIN_GRAFX_V3D 1 +#define BCM2835_POWER_DOMAIN_IMAGE 2 +#define BCM2835_POWER_DOMAIN_IMAGE_PERI 3 +#define BCM2835_POWER_DOMAIN_IMAGE_ISP 4 +#define BCM2835_POWER_DOMAIN_IMAGE_H264 5 +#define BCM2835_POWER_DOMAIN_USB 6 +#define BCM2835_POWER_DOMAIN_DSI0 7 +#define BCM2835_POWER_DOMAIN_DSI1 8 +#define BCM2835_POWER_DOMAIN_CAM0 9 +#define BCM2835_POWER_DOMAIN_CAM1 10 +#define BCM2835_POWER_DOMAIN_CCP2TX 11 +#define BCM2835_POWER_DOMAIN_HDMI 12 + +#define BCM2835_POWER_DOMAIN_COUNT 13 + +#define BCM2835_RESET_V3D 0 +#define BCM2835_RESET_ISP 1 +#define BCM2835_RESET_H264 2 + +#define BCM2835_RESET_COUNT 3 + +#endif /* __DT_BINDINGS_POWER_BCM2835_PM_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/power/raspberrypi-power.h b/bsp/raspberry-pi/dm/include/dt-bindings/power/raspberrypi-power.h new file mode 100755 index 0000000000..573c39206b --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/power/raspberrypi-power.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_POWER_RASPBERRYPI_POWER_H__ +#define __DT_BINDINGS_POWER_RASPBERRYPI_POWER_H__ + +#define RPI_POWER_DOMAIN_I2C0 0 +#define RPI_POWER_DOMAIN_I2C1 1 +#define RPI_POWER_DOMAIN_I2C2 2 +#define RPI_POWER_DOMAIN_VIDEO_SCALER 3 +#define RPI_POWER_DOMAIN_VPU1 4 +#define RPI_POWER_DOMAIN_HDMI 5 +#define RPI_POWER_DOMAIN_USB 6 +#define RPI_POWER_DOMAIN_VEC 7 +#define RPI_POWER_DOMAIN_JPEG 8 +#define RPI_POWER_DOMAIN_H264 9 +#define RPI_POWER_DOMAIN_V3D 10 +#define RPI_POWER_DOMAIN_ISP 11 +#define RPI_POWER_DOMAIN_UNICAM0 12 +#define RPI_POWER_DOMAIN_UNICAM1 13 +#define RPI_POWER_DOMAIN_CCP2RX 14 +#define RPI_POWER_DOMAIN_CSI2 15 +#define RPI_POWER_DOMAIN_CPI 16 +#define RPI_POWER_DOMAIN_DSI0 17 +#define RPI_POWER_DOMAIN_DSI1 18 +#define RPI_POWER_DOMAIN_TRANSPOSER 19 +#define RPI_POWER_DOMAIN_CCP2TX 20 +#define RPI_POWER_DOMAIN_CDP 21 +#define RPI_POWER_DOMAIN_ARM 22 + +#define RPI_POWER_DOMAIN_COUNT 23 + +#endif /* __DT_BINDINGS_POWER_BCMRASPBERRYPI_POWERH__ */ diff --git a/bsp/raspberry-pi/dm/include/dt-bindings/reset/raspberrypi,firmware-reset.h b/bsp/raspberry-pi/dm/include/dt-bindings/reset/raspberrypi,firmware-reset.h new file mode 100755 index 0000000000..37c6135325 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dt-bindings/reset/raspberrypi,firmware-reset.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_POWER_RASPBERRYPI_FIRMWARE_RESET_H__ +#define __DT_BINDINGS_POWER_RASPBERRYPI_FIRMWARE_RESET_H__ + +#define RASPBERRYPI_FIRMWARE_RESET_ID_USB 0 +#define RASPBERRYPI_FIRMWARE_RESET_NUM_IDS 1 + +#endif /* __DT_BINDINGS_POWER_RASPBERRYPI_FIRMWARE_RESET_H__ */ diff --git a/bsp/raspberry-pi/dm/include/dvfs-raspberrypi-cpufreq.h b/bsp/raspberry-pi/dm/include/dvfs-raspberrypi-cpufreq.h new file mode 100644 index 0000000000..15092a7c92 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/dvfs-raspberrypi-cpufreq.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#ifndef __DVFS_RASPBERRYPI_CPUFREQ_H__ +#define __DVFS_RASPBERRYPI_CPUFREQ_H__ + +#include +#include + +struct rt_clk *raspberrypi_arm_clk_get(void); +rt_err_t raspberrypi_cpufreq_register(struct rt_clk *arm_clk, struct rt_ofw_node *cpu_np, + struct rpi_firmware *rpi_fw); + +#endif /* __DVFS_RASPBERRYPI_CPUFREQ_H__ */ diff --git a/bsp/raspberry-pi/dm/include/firmware-raspberrypi.h b/bsp/raspberry-pi/dm/include/firmware-raspberrypi.h new file mode 100755 index 0000000000..ab949ae1aa --- /dev/null +++ b/bsp/raspberry-pi/dm/include/firmware-raspberrypi.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#ifndef __RASPBERRYPI_FIRMWARE_H__ +#define __RASPBERRYPI_FIRMWARE_H__ + +#include + +struct rpi_firmware; + +enum rpi_firmware_property_status +{ + RPI_FIRMWARE_STATUS_REQUEST = 0, + RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000, + RPI_FIRMWARE_STATUS_ERROR = 0x80000001, +}; + +struct rpi_firmware_property_tag_header +{ + rt_uint32_t tag; + rt_uint32_t buf_size; + rt_uint32_t req_resp_size; /* always 4 byte aligned */ +}; + +enum rpi_firmware_property_tag +{ + RPI_FIRMWARE_PROPERTY_END = 0, + RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001, + RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002, + RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003, + + RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010, + RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011, + + RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001, + RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002, + RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003, + RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004, + RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005, + RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006, + RPI_FIRMWARE_GET_CLOCKS = 0x00010007, + RPI_FIRMWARE_GET_POWER_STATE = 0x00020001, + RPI_FIRMWARE_GET_TIMING = 0x00020002, + RPI_FIRMWARE_SET_POWER_STATE = 0x00028001, + RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001, + RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002, + RPI_FIRMWARE_GET_VOLTAGE = 0x00030003, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004, + RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005, + RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007, + RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008, + RPI_FIRMWARE_GET_TURBO = 0x00030009, + RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a, + RPI_FIRMWARE_GET_STC = 0x0003000b, + RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c, + RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d, + RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e, + RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f, + RPI_FIRMWARE_EXECUTE_CODE = 0x00030010, + RPI_FIRMWARE_EXECUTE_QPU = 0x00030011, + RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012, + RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, + RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, + RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, + RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023, + RPI_FIRMWARE_GET_USER_OTP = 0x00030024, + RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, + RPI_FIRMWARE_GET_THROTTLED = 0x00030046, + RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, + RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048, + RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001, + RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002, + RPI_FIRMWARE_SET_VOLTAGE = 0x00038003, + RPI_FIRMWARE_SET_TURBO = 0x00038009, + RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021, + RPI_FIRMWARE_SET_USER_OTP = 0x00038024, + RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030, + RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041, + RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041, + RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042, + RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043, + RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043, + RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045, + RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, + RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, + RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00038049, + RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 0x00030050, + RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, + RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064, + RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064, + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, + RPI_FIRMWARE_GET_BUTTONS_PRESSED = 0x00030088, + RPI_FIRMWARE_GET_RTC_REG = 0x00030087, + RPI_FIRMWARE_SET_RTC_REG = 0x00038087, + + /* Dispmanx TAGS */ + RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, + RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002, + RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003, + RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004, + RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005, + RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006, + RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007, + RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008, + RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009, + RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a, + RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b, + RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c, + RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d, + RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e, + RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f, + RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010, + RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013, + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004, + RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006, + RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009, + RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a, + RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b, + RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c, + RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d, + RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e, + RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003, + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004, + RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005, + RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006, + RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007, + RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008, + RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009, + RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a, + RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b, + + RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f, + RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020, + RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e, + RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c, + RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d, + RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, + + RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + + RPI_FIRMWARE_SET_PLANE = 0x00048015, + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, + RPI_FIRMWARE_SET_TIMING = 0x00048017, + RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, + RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019, + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, +}; + +enum rpi_firmware_clk_id +{ + RPI_FIRMWARE_EMMC_CLK_ID = 1, + RPI_FIRMWARE_UART_CLK_ID, + RPI_FIRMWARE_ARM_CLK_ID, + RPI_FIRMWARE_CORE_CLK_ID, + RPI_FIRMWARE_V3D_CLK_ID, + RPI_FIRMWARE_H264_CLK_ID, + RPI_FIRMWARE_ISP_CLK_ID, + RPI_FIRMWARE_SDRAM_CLK_ID, + RPI_FIRMWARE_PIXEL_CLK_ID, + RPI_FIRMWARE_PWM_CLK_ID, + RPI_FIRMWARE_HEVC_CLK_ID, + RPI_FIRMWARE_EMMC2_CLK_ID, + RPI_FIRMWARE_M2MC_CLK_ID, + RPI_FIRMWARE_PIXEL_BVB_CLK_ID, + RPI_FIRMWARE_VEC_CLK_ID, + RPI_FIRMWARE_DISP_CLK_ID, + RPI_FIRMWARE_NUM_CLK_ID, +}; + +#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64 + +rt_packed(struct rpi_firmware_clk_rate_request +{ + rt_le32_t id; /* ID of the clock being queried */ + rt_le32_t rate; /* Rate in Hertz. Set by the firmware */ +}); + +#define RPI_FIRMWARE_CLK_RATE_REQUEST(ID) \ +{ \ + .id = ID, \ +} + +void *rpi_firmware_property_raw_alloc(struct rpi_firmware *rpi_fw, + rt_size_t max_header_tag_size, rt_ubase_t *out_bus_addr); +void rpi_firmware_property_raw_free(struct rpi_firmware *rpi_fw, + rt_size_t max_header_tag_size, void *buf, rt_ubase_t bus_addr); + +rt_err_t rpi_firmware_property(struct rpi_firmware *rpi_fw, + rt_uint32_t tag, void *tag_data, rt_size_t buf_size); +rt_err_t rpi_firmware_property_raw(struct rpi_firmware *rpi_fw, rt_uint32_t tag, + rt_ubase_t bus_addr, struct rpi_firmware_property_tag_header *header, rt_size_t req_size); +rt_err_t rpi_firmware_property_list(struct rpi_firmware *rpi_fw, + void *data, rt_size_t tag_size); +rt_err_t rpi_firmware_property_list_raw(struct rpi_firmware *rpi_fw, + rt_ubase_t bus_addr, void *data, rt_size_t tag_size); + +rt_uint32_t rpi_firmware_clk_get_max_rate(struct rpi_firmware *rpi_fw, rt_uint32_t id); + +struct rt_ofw_node *rpi_firmware_find_node(void); +struct rpi_firmware *rpi_firmware_get(struct rt_ofw_node *fw_np); +void rpi_firmware_put(struct rpi_firmware *rpi_fw); + +#endif /* __RASPBERRYPI_FIRMWARE_H__ */ diff --git a/bsp/raspberry-pi/dm/include/rpi-sense.h b/bsp/raspberry-pi/dm/include/rpi-sense.h new file mode 100755 index 0000000000..1c5a9937d6 --- /dev/null +++ b/bsp/raspberry-pi/dm/include/rpi-sense.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __RPISENSE_H__ +#define __RPISENSE_H__ + +#include + +#define SENSEFB_FBIO_IOC_MAGIC 0xf1 + +#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0) +#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1) +#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2) + +/* + * Register values. + */ +#define RPISENSE_FB 0x00 +#define RPISENSE_WAI 0xf0 +#define RPISENSE_VER 0xf1 +#define RPISENSE_KEYS 0xf2 +#define RPISENSE_EE_WP 0xf3 + +#define RPISENSE_ID 's' + +struct rpisense +{ + struct rt_i2c_client *i2c_client; + + struct rt_platform_device joystick_dev; + struct rt_platform_device framebuffer_dev; +}; + +rt_int32_t rpisense_reg_read(struct rpisense *rpisense, int reg); +rt_ssize_t rpisense_block_write(struct rpisense *rpisense, const char *buf, int count); + +#endif /* __RPISENSE_H__ */ diff --git a/bsp/raspberry-pi/dm/input/SConscript b/bsp/raspberry-pi/dm/input/SConscript new file mode 100755 index 0000000000..3d15055d62 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/SConscript @@ -0,0 +1,13 @@ +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/raspberry-pi/dm/input/joystick/Kconfig b/bsp/raspberry-pi/dm/input/joystick/Kconfig new file mode 100755 index 0000000000..b5be7b9cc7 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/joystick/Kconfig @@ -0,0 +1,5 @@ +config RT_INPUT_JOYSTICK_RPISENSE + bool "Raspberry Pi Sense HAT joystick" + depends on RT_INPUT_JOYSTICK + depends on RT_MFD_RPI_SENSE + default n diff --git a/bsp/raspberry-pi/dm/input/joystick/SConscript b/bsp/raspberry-pi/dm/input/joystick/SConscript new file mode 100755 index 0000000000..4061a05e44 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/joystick/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_INPUT_JOYSTICK_RPISENSE']): + src += ['js-rpisense.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/input/joystick/js-rpisense.c b/bsp/raspberry-pi/dm/input/joystick/js-rpisense.c new file mode 100755 index 0000000000..9bfeaea847 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/joystick/js-rpisense.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#include + +struct rpisense_joystick +{ + struct rt_input_device parent; + struct rpisense *rpisense; + + rt_base_t pin; + rt_uint8_t active_val; + rt_int32_t prev_keys; + + struct rt_thread *keys_task; +}; + +static rt_uint8_t keymap[5] = +{ + KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT +}; + +static void rpisense_keys_task(void *param) +{ + rt_int32_t keys, changes; + struct rpisense_joystick *rpisense_js = param; + + while (RT_TRUE) + { + rt_thread_suspend(rpisense_js->keys_task); + rt_schedule(); + + keys = rpisense_reg_read(rpisense_js->rpisense, RPISENSE_KEYS); + changes = keys ^ rpisense_js->prev_keys; + rpisense_js->prev_keys = keys; + + for (int i = 0; i < RT_ARRAY_SIZE(keymap); ++i) + { + if (changes & 1) + { + rt_input_report_key(&rpisense_js->parent, keymap[i], keys & 1); + } + + changes >>= 1; + keys >>= 1; + } + + rt_input_sync(&rpisense_js->parent); + } +} + +static void rpisense_isr(void *args) +{ + struct rpisense_joystick *rpisense_js = args; + + rt_thread_resume(rpisense_js->keys_task); +} + +static rt_err_t rpisense_js_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rpisense *rpisense = pdev->priv; + struct rpisense_joystick *rpisense_js = rt_calloc(1, sizeof(*rpisense_js)); + + if (!rpisense_js) + { + return -RT_ENOMEM; + } + + rpisense_js->rpisense = rpisense; + rpisense_js->pin = rt_pin_get_named_pin(&rpisense->i2c_client->parent, + "keys-int", 0, RT_NULL, &rpisense_js->active_val); + + if (rpisense_js->pin < 0) + { + err = rpisense_js->pin; + goto _fail; + } + + rt_pin_write(rpisense_js->pin, rpisense_js->active_val); + rt_pin_mode(rpisense_js->pin, PIN_MODE_INPUT); + rt_pin_attach_irq(rpisense_js->pin, PIN_IRQ_MODE_RISING, rpisense_isr, rpisense_js); + rt_pin_irq_enable(rpisense_js->pin, RT_TRUE); + + for (int i = 0; i < RT_ARRAY_SIZE(keymap); ++i) + { + rt_input_set_capability(&rpisense_js->parent, EV_KEY, keymap[i]); + } + + if ((err = rt_input_device_register(&rpisense_js->parent))) + { + goto _fail; + } + + rpisense_js->keys_task = rt_thread_create("rpisense-js", &rpisense_keys_task, + rpisense_js, DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!rpisense_js->keys_task) + { + rt_input_device_unregister(&rpisense_js->parent); + goto _fail; + } + + pdev->parent.user_data = rpisense_js; + + rt_thread_startup(rpisense_js->keys_task); + + return RT_EOK; + +_fail: + if (rpisense_js->pin >= 0) + { + rt_pin_detach_irq(rpisense_js->pin); + } + + rt_free(rpisense_js); + + return err; +} + +static rt_err_t rpisense_js_remove(struct rt_platform_device *pdev) +{ + struct rpisense_joystick *rpisense_js = pdev->parent.user_data; + + rt_pin_irq_enable(rpisense_js->pin, RT_FALSE); + rt_pin_detach_irq(rpisense_js->pin); + + rt_thread_delete(rpisense_js->keys_task); + + rt_input_device_unregister(&rpisense_js->parent); + + rt_free(rpisense_js); + + return RT_EOK; +} + +static struct rt_platform_driver rpisense_js_driver = +{ + .name = "rpi-sense-js", + + .probe = rpisense_js_probe, + .remove = rpisense_js_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpisense_js_driver); diff --git a/bsp/raspberry-pi/dm/input/touchscreen/Kconfig b/bsp/raspberry-pi/dm/input/touchscreen/Kconfig new file mode 100755 index 0000000000..9766216f38 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/touchscreen/Kconfig @@ -0,0 +1,9 @@ +config RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW + bool "Raspberry Pi's firmware base touch screen support" + depends on RT_INPUT_TOUCHSCREEN + depends on RT_USING_OFW + depends on RT_USING_DMA + depends on RT_FIRMWARE_RASPBERRYPI + depends on RT_USING_ADT + depends on RT_USING_ADT_BITMAP + default n diff --git a/bsp/raspberry-pi/dm/input/touchscreen/SConscript b/bsp/raspberry-pi/dm/input/touchscreen/SConscript new file mode 100755 index 0000000000..0b95fd9d21 --- /dev/null +++ b/bsp/raspberry-pi/dm/input/touchscreen/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +if GetDepend(['RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW']): + src += ['ts-raspberrypi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/input/touchscreen/ts-raspberrypi.c b/bsp/raspberry-pi/dm/input/touchscreen/ts-raspberrypi.c new file mode 100755 index 0000000000..0e2da82d4c --- /dev/null +++ b/bsp/raspberry-pi/dm/input/touchscreen/ts-raspberrypi.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "input.touchscreen.rpi-ts" +#define DBG_LVL DBG_INFO +#include + +#include + +#define RPI_TS_DEFAULT_WIDTH 800 +#define RPI_TS_DEFAULT_HEIGHT 480 + +#define RPI_TS_MAX_SUPPORTED_POINTS 10 + +#define RPI_TS_FTS_TOUCH_DOWN 0 +#define RPI_TS_FTS_TOUCH_CONTACT 2 + +#define RPI_TS_POLL_INTERVAL 17 /* 60fps */ + +#define RPI_TS_NPOINTS_REG_INVALIDATE 99 + +struct rpi_ts_regs +{ + rt_uint8_t device_mode; + rt_uint8_t gesture_id; + rt_uint8_t num_points; + + struct rpi_ts_touch + { + rt_uint8_t xh; + rt_uint8_t xl; + rt_uint8_t yh; + rt_uint8_t yl; + rt_uint8_t pressure; /* Not supported */ + rt_uint8_t area; /* Not supported */ + } point[RPI_TS_MAX_SUPPORTED_POINTS]; +}; + +struct rpi_ts +{ + struct rt_input_device parent; + + void *fw_regs; + rt_ubase_t fw_regs_phys; + + int known_ids; + struct rpi_ts_regs ts_regs; +}; + +#define raw_to_rpi_ts(raw) rt_container_of(raw, struct rpi_ts, parent) + +static void rpi_ts_poll(struct rt_input_device *idev) +{ + int touchid; + int event_type; + int modified_ids = 0; + int x, y, bit = 0; + rt_bitmap_t released_ids; + struct rpi_ts *rts = raw_to_rpi_ts(idev); + struct rpi_ts_regs *regs = &rts->ts_regs; + + rt_memcpy(regs, rts->fw_regs, sizeof(*regs)); + + /* + * We poll the memory based register copy of the touchscreen chip using + * the number of points register to know whether the copy has been + * updated (we write 99 to the memory copy, the GPU will write between + * 0 - 10 points) + */ + HWREG8(rts->fw_regs + (rt_size_t)&((struct rpi_ts_regs *)0)->num_points) = + RPI_TS_NPOINTS_REG_INVALIDATE; + + if (regs->num_points == RPI_TS_NPOINTS_REG_INVALIDATE || + (regs->num_points == 0 && rts->known_ids == 0)) + { + return; + } + + for (int i = 0; i < regs->num_points; ++i) + { + x = (((int)regs->point[i].xh & 0xf) << 8) + regs->point[i].xl; + y = (((int)regs->point[i].yh & 0xf) << 8) + regs->point[i].yl; + touchid = (regs->point[i].yh >> 4) & 0xf; + event_type = (regs->point[i].xh >> 6) & 0x03; + + modified_ids |= RT_BIT(touchid); + + if (event_type == RPI_TS_FTS_TOUCH_DOWN || + event_type == RPI_TS_FTS_TOUCH_CONTACT) + { + rt_input_report_touch_slot(idev, touchid); + rt_input_report_touch_inactive(idev, RT_TRUE); + rt_input_report_touch_position(idev, x, y, RT_TRUE); + } + } + + released_ids = rts->known_ids & ~modified_ids; + rt_bitmap_for_each_set_bit(&released_ids, bit, RPI_TS_MAX_SUPPORTED_POINTS) + { + rt_input_report_touch_slot(idev, bit); + rt_input_report_touch_inactive(idev, RT_FALSE); + modified_ids &= ~RT_BIT(bit); + } + + rts->known_ids = modified_ids; + rt_input_sync(idev); +} + +static rt_err_t rpi_ts_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_uint32_t touchbuf; + struct rt_touch_info touch_info = {}; + struct rpi_firmware *rpi_fw = RT_NULL; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_ts *rts = rt_calloc(1, sizeof(*rts)); + + if (!rts) + { + return -RT_ENOMEM; + } + rts->parent.parent.ofw_node = np; + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + rts->fw_regs = rt_dma_alloc_coherent(dev, ARCH_PAGE_SIZE, &rts->fw_regs_phys); + + if (!rts->fw_regs) + { + LOG_E("Failed to dma buffer"); + + goto _fail; + } + + if (rts->fw_regs_phys > RT_UINT32_MAX) + { + LOG_E("64 bits dma buffer is not support"); + + goto _fail; + } + + touchbuf = (rt_uint32_t)rts->fw_regs_phys; + + if ((err = rpi_firmware_property(rpi_fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, + &touchbuf, sizeof(touchbuf)))) + { + LOG_E("Set touchbuf from firmware error = %s", rt_strerror(err)); + + goto _fail; + } + + if ((err = rt_input_set_capability(&rts->parent, EV_ABS, ABS_MT_POSITION_X)) || + (err = rt_input_set_capability(&rts->parent, EV_ABS, ABS_MT_POSITION_Y))) + { + goto _fail; + } + + rt_input_set_absinfo(&rts->parent, + ABS_MT_POSITION_X, 0, RPI_TS_DEFAULT_WIDTH, 0, 0); + + rt_input_set_absinfo(&rts->parent, + ABS_MT_POSITION_Y, 0, RPI_TS_DEFAULT_HEIGHT, 0, 0); + + if ((err = rt_input_setup_polling(&rts->parent, rpi_ts_poll))) + { + goto _fail; + } + + rt_input_set_poll_interval(&rts->parent, RPI_TS_POLL_INTERVAL); + + touch_info.type = RT_TOUCH_TYPE_RESISTANCE; + touch_info.vendor = RT_TOUCH_VENDOR_UNKNOWN; + + if ((err = rt_input_setup_touch(&rts->parent, + RPI_TS_MAX_SUPPORTED_POINTS, &touch_info))) + { + goto _fail; + } + + if ((err = rt_input_device_register(&rts->parent))) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, &rts->parent); + dev->user_data = rts; + + return RT_EOK; + +_fail: + rt_input_remove_config(&rts->parent); + + if (rts->fw_regs) + { + rt_dma_free_coherent(dev, ARCH_PAGE_SIZE, rts->fw_regs, rts->fw_regs_phys); + } + + if (rpi_fw) + { + rpi_firmware_put(rpi_fw); + } + + rt_free(rts); + + return err; +} + +static rt_err_t rpi_ts_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rpi_ts *rts = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + rt_input_device_unregister(&rts->parent); + + rt_dma_free_coherent(dev, ARCH_PAGE_SIZE, rts->fw_regs, rts->fw_regs_phys); + + rt_free(rts); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rpi_ts_ofw_ids[] = +{ + { .compatible = "raspberrypi,firmware-ts" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_ts_driver = +{ + .name = "touchscreen-rpi", + .ids = rpi_ts_ofw_ids, + + .probe = rpi_ts_probe, + .remove = rpi_ts_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpi_ts_driver); diff --git a/bsp/raspberry-pi/dm/mailbox/Kconfig b/bsp/raspberry-pi/dm/mailbox/Kconfig new file mode 100755 index 0000000000..64c55a6618 --- /dev/null +++ b/bsp/raspberry-pi/dm/mailbox/Kconfig @@ -0,0 +1,3 @@ +config RT_MBOX_BCM2835 + bool "BCM2835 Mailbox" + default n diff --git a/bsp/raspberry-pi/dm/mailbox/SConscript b/bsp/raspberry-pi/dm/mailbox/SConscript new file mode 100755 index 0000000000..14d2237d2a --- /dev/null +++ b/bsp/raspberry-pi/dm/mailbox/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MBOX_BCM2835']): + src += ['mailbox-bcm2835.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/mailbox/mailbox-bcm2835.c b/bsp/raspberry-pi/dm/mailbox/mailbox-bcm2835.c new file mode 100755 index 0000000000..59f28e3684 --- /dev/null +++ b/bsp/raspberry-pi/dm/mailbox/mailbox-bcm2835.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include +#include + +/* Mailboxes */ +#define ARM_0_MAIL0 0x00 +#define ARM_0_MAIL1 0x20 + +/* + * Mailbox registers. We basically only support mailbox 0 & 1. We + * deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See + * BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about + * the placement of memory barriers. + */ +#define MAIL0_RD (ARM_0_MAIL0 + 0x00) +#define MAIL0_POL (ARM_0_MAIL0 + 0x10) +#define MAIL0_STA (ARM_0_MAIL0 + 0x18) +#define MAIL0_CNF (ARM_0_MAIL0 + 0x1C) +#define MAIL1_WRT (ARM_0_MAIL1 + 0x00) +#define MAIL1_STA (ARM_0_MAIL1 + 0x18) + +/* Status register: FIFO state. */ +#define ARM_MS_FULL RT_BIT(31) +#define ARM_MS_EMPTY RT_BIT(30) + +/* Configuration register: Enable interrupts. */ +#define ARM_MC_IHAVEDATAIRQEN RT_BIT(0) + +struct bcm2835_mbox +{ + struct rt_mbox_controller parent; + + int irq; + void *regs; + struct rt_spinlock lock; +}; + +#define raw_to_bcm2835_mbox(raw) rt_container_of(raw, struct bcm2835_mbox, parent) + +rt_inline rt_uint32_t bcm2835_mbox_readl(struct bcm2835_mbox *bcm_mbox, int offset) +{ + return HWREG32(bcm_mbox->regs + offset); +} + +rt_inline void bcm2835_mbox_writel(struct bcm2835_mbox *bcm_mbox, int offset, + rt_uint32_t value) +{ + HWREG32(bcm_mbox->regs + offset) = value; +} + +static rt_err_t bcm2835_mbox_request(struct rt_mbox_chan *chan) +{ + struct bcm2835_mbox *bcm_mbox = raw_to_bcm2835_mbox(chan->ctrl); + + /* Enable the interrupt on data reception */ + bcm2835_mbox_writel(bcm_mbox, MAIL0_CNF, ARM_MC_IHAVEDATAIRQEN); + + return RT_EOK; +} + +static void bcm2835_mbox_release(struct rt_mbox_chan *chan) +{ + struct bcm2835_mbox *bcm_mbox = raw_to_bcm2835_mbox(chan->ctrl); + + bcm2835_mbox_writel(bcm_mbox, MAIL0_CNF, 0); +} + +static rt_err_t bcm2835_mbox_send(struct rt_mbox_chan *chan, const void *data) +{ + rt_err_t err = -RT_ETIMEOUT; + rt_int32_t timeout_us = 1000000; + rt_uint32_t msg = *(rt_uint32_t *)data; + struct bcm2835_mbox *bcm_mbox = raw_to_bcm2835_mbox(chan->ctrl); + + rt_spin_lock(&bcm_mbox->lock); + + /* + * Property channel replies are polled synchronously. Mask the mailbox + * interrupt while waiting so the ISR cannot consume the reply first and + * leave the poll loop timing out spuriously. + */ + rt_hw_interrupt_mask(bcm_mbox->irq); + + while (bcm2835_mbox_readl(bcm_mbox, MAIL1_STA) & ARM_MS_FULL) + { + rt_spin_unlock(&bcm_mbox->lock); + rt_hw_us_delay(10); + rt_spin_lock(&bcm_mbox->lock); + } + + bcm2835_mbox_writel(bcm_mbox, MAIL1_WRT, msg); + rt_hw_wmb(); + + while (timeout_us > 0) + { + rt_uint32_t sta = bcm2835_mbox_readl(bcm_mbox, MAIL0_STA); + + if (!(sta & ARM_MS_EMPTY)) + { + rt_uint32_t reply = bcm2835_mbox_readl(bcm_mbox, MAIL0_RD); + + rt_mbox_recv(chan, &reply); + err = RT_EOK; + break; + } + + rt_hw_us_delay(10); + timeout_us -= 10; + } + + rt_hw_interrupt_umask(bcm_mbox->irq); + rt_spin_unlock(&bcm_mbox->lock); + + return err; +} + +static int bcm2835_mbox_ofw_parse(struct rt_mbox_controller *ctrl, + struct rt_ofw_cell_args *args) +{ + if (args->args_count != 0) + { + return -RT_EINVAL; + } + + return 0; +} + +static const struct rt_mbox_controller_ops bcm2835_mbox_ops = +{ + .request = bcm2835_mbox_request, + .release = bcm2835_mbox_release, + .send = bcm2835_mbox_send, + .ofw_parse = bcm2835_mbox_ofw_parse, +}; + +static void bcm2835_mbox_isr(int irqno, void *param) +{ + struct bcm2835_mbox *bcm_mbox = param; + + while (!(bcm2835_mbox_readl(bcm_mbox, MAIL0_STA) & ARM_MS_EMPTY)) + { + rt_uint32_t msg = bcm2835_mbox_readl(bcm_mbox, MAIL0_RD); + + rt_mbox_recv(&bcm_mbox->parent.chans[0], &msg); + } +} + +static rt_err_t bcm2835_mbox_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct bcm2835_mbox *bcm_mbox = rt_calloc(1, sizeof(*bcm_mbox)); + + if (!bcm_mbox) + { + return -RT_ENOMEM; + } + + bcm_mbox->regs = rt_dm_dev_iomap(dev, 0); + + if (!bcm_mbox->regs) + { + err = -RT_EIO; + + goto _fail; + } + + bcm_mbox->irq = rt_dm_dev_get_irq(dev, 0); + + if (bcm_mbox->irq < 0) + { + err = bcm_mbox->irq; + + goto _fail; + } + + dev->user_data = bcm_mbox; + + rt_hw_interrupt_install(bcm_mbox->irq, bcm2835_mbox_isr, bcm_mbox, "bcm2835-mbox"); + rt_hw_interrupt_umask(bcm_mbox->irq); + + bcm_mbox->parent.dev = dev; + bcm_mbox->parent.num_chans = 1; + bcm_mbox->parent.ops = &bcm2835_mbox_ops; + + if ((err = rt_mbox_controller_register(&bcm_mbox->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (bcm_mbox->regs) + { + rt_iounmap(bcm_mbox->regs); + } + + rt_free(bcm_mbox); + + return err; +} + +static rt_err_t bcm2835_mbox_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_mbox *bcm_mbox = pdev->parent.user_data; + + rt_hw_interrupt_mask(bcm_mbox->irq); + rt_pic_detach_irq(bcm_mbox->irq, bcm_mbox); + + rt_mbox_controller_unregister(&bcm_mbox->parent); + + rt_iounmap(bcm_mbox->regs); + + rt_free(bcm_mbox); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_mbox_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-mbox" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_mbox_driver = +{ + .name = "mailbox-bcm2835", + .ids = bcm2835_mbox_ofw_ids, + + .probe = bcm2835_mbox_probe, + .remove = bcm2835_mbox_remove, +}; + +static int bcm2835_mbox_drv_register(void) +{ + rt_platform_driver_register(&bcm2835_mbox_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_mbox_drv_register); diff --git a/bsp/raspberry-pi/dm/mfd/Kconfig b/bsp/raspberry-pi/dm/mfd/Kconfig new file mode 100755 index 0000000000..3321277989 --- /dev/null +++ b/bsp/raspberry-pi/dm/mfd/Kconfig @@ -0,0 +1,18 @@ +config RT_MFD_BCM2835_PM + bool "BCM2835 PM driver" + depends on RT_USING_MFD + default n + +config RT_MFD_RP1 + bool "Raspberry Pi RP1 MFD driver" + depends on RT_USING_MFD + depends on RT_USING_PCI + default n + +config RT_MFD_RPI_SENSE + bool "Raspberry Pi Sense HAT core functions" + depends on RT_USING_MFD + depends on RT_USING_I2C + depends on RT_USING_OFW + depends on RT_USING_PIN + default n diff --git a/bsp/raspberry-pi/dm/mfd/SConscript b/bsp/raspberry-pi/dm/mfd/SConscript new file mode 100755 index 0000000000..a60f069e95 --- /dev/null +++ b/bsp/raspberry-pi/dm/mfd/SConscript @@ -0,0 +1,19 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_MFD_BCM2835_PM']): + src += ['bcm2835-pm.c'] + +if GetDepend(['RT_MFD_RP1']): + src += ['rp1.c'] + +if GetDepend(['RT_MFD_RPI_SENSE']): + src += ['rpi-sense.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/mfd/bcm2835-pm.c b/bsp/raspberry-pi/dm/mfd/bcm2835-pm.c new file mode 100755 index 0000000000..9bc9f35771 --- /dev/null +++ b/bsp/raspberry-pi/dm/mfd/bcm2835-pm.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#define DBG_TAG "mfd.bcm2835-pm" +#define DBG_LVL DBG_INFO +#include + +#include + +static rt_err_t bcm2835_pm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_bool_t is_2712 = RT_FALSE; + struct rt_device *dev = &pdev->parent; + struct rt_bus *bus = dev->bus; + struct bcm2835_pm *pm = rt_malloc(sizeof(*pm)); + + if (!pm) + { + return -RT_ENOMEM; + } + +#ifdef RT_USING_OFW + is_2712 = rt_ofw_node_is_compatible(dev->ofw_node, "brcm,bcm2712-pm"); + + if (rt_ofw_prop_read_bool(dev->ofw_node, "reg-names")) + { + if (!(pm->base = rt_dm_dev_iomap_by_name(dev, "pm"))) + { + err = -RT_EIO; + + goto _fail; + } + + pm->asb = rt_dm_dev_iomap_by_name(dev, "asb"); + pm->rpivid_asb = rt_dm_dev_iomap_by_name(dev, "rpivid_asb"); + } + else +#endif /* RT_USING_OFW */ + { + if (!(pm->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + + goto _fail; + } + + pm->asb = rt_dm_dev_iomap(dev, 1); + pm->rpivid_asb = rt_dm_dev_iomap(dev, 2); + } + + pm->ofw_node = dev->ofw_node; + + pdev->name = "bcm2835-wdt"; + pdev->priv = pm; + /* Ask bus to check drivers' name */ + pdev->parent.ofw_node = RT_NULL; + rt_bus_remove_device(dev); + rt_bus_add_device(bus, dev); + + if (pm->asb || is_2712) + { + pdev = rt_calloc(1, sizeof(*pdev)); + + if (pdev) + { + pdev->name = "bcm2835-power"; + pdev->priv = pm; + rt_bus_add_device(bus, &pdev->parent); + } + else + { + LOG_W("Power will not register"); + } + } + + /* No Error, No success */ + return 1; + +_fail: + rt_free(pm); + + return err; +} + +static const struct rt_ofw_node_id bcm2835_pm_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-pm-wdt", }, + { .compatible = "brcm,bcm2835-pm", }, + { .compatible = "brcm,bcm2711-pm", }, + { .compatible = "brcm,bcm2712-pm", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_pm_driver = +{ + .name = "pm-bcm2835", + .ids = bcm2835_pm_ofw_ids, + + .probe = bcm2835_pm_probe, +}; + +static int bcm2835_pm_register(void) +{ + rt_platform_driver_register(&bcm2835_pm_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_pm_register); diff --git a/bsp/raspberry-pi/dm/mfd/rp1.c b/bsp/raspberry-pi/dm/mfd/rp1.c new file mode 100755 index 0000000000..e38bf258b3 --- /dev/null +++ b/bsp/raspberry-pi/dm/mfd/rp1.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "mfd.rp1" +#define DBG_LVL DBG_INFO +#include + +#include + +#define PCI_DEVICE_ID_RP1_C0 0x0001 + +#define RP1_PCI_BAR0_OFFSET 0x410000ULL +#define RP1_PCI_BAR1_OFFSET 0x0ULL +#define RP1_PCI_BAR2_OFFSET 0x400000ULL + + + +#define RP1_ACTUAL_IRQS RP1_INT_END +#define RP1_IRQS RP1_ACTUAL_IRQS + +#define RP1_SYSCLK_RATE 200000000 +#define RP1_SYSCLK_FPGA_RATE 60000000 + +#define REG_RW 0x000 +#define REG_SET 0x800 +#define REG_CLR 0xc00 + +#define MSIX_CFG(x) (0x8 + (4 * (x))) + +#define MSIX_CFG_IACK_EN RT_BIT(3) +#define MSIX_CFG_IACK RT_BIT(2) +#define MSIX_CFG_TEST RT_BIT(1) +#define MSIX_CFG_ENABLE RT_BIT(0) + +#define INTSTATL 0x108 +#define INTSTATH 0x10c + +struct rp1_device +{ + struct rt_pic parent; + struct rt_pci_device *pdev; + + rt_ubase_t bar_start; + rt_ubase_t bar_end; + + struct rt_clk *sys_clk; + struct rt_pci_msix_entry msix_entries[RP1_IRQS]; + rt_bool_t rp1_level_triggered_irq[RP1_ACTUAL_IRQS]; + + void *msix_cfg_regs; + struct rt_pic *msi_pic; +}; + +#define raw_to_rp1(raw) rt_container_of(raw, struct rp1_device, parent) + +extern void brcm_pcie_reapply_maps(struct rt_pci_device *pdev); + +rt_inline rt_ubase_t rp1_io_to_phys(struct rp1_device *rp1, int offset) +{ + return rp1->bar_start + offset; +} + +static void msix_cfg_set(struct rp1_device *rp1, int hwirq, rt_uint32_t value) +{ + HWREG32(rp1->msix_cfg_regs + REG_SET + MSIX_CFG(hwirq)) = value; +} + +static void msix_cfg_clr(struct rp1_device *rp1, int hwirq, rt_uint32_t value) +{ + HWREG32(rp1->msix_cfg_regs + REG_CLR + MSIX_CFG(hwirq)) = value; +} + +static void rp1_sync_pci_bar_config(struct rt_pci_device *pdev) +{ + rt_uint16_t cmd; + rt_uint32_t bar0, bar1, bar2; + static const rt_uint32_t want[] = { + (rt_uint32_t)RP1_PCI_BAR0_OFFSET, + (rt_uint32_t)RP1_PCI_BAR1_OFFSET, + (rt_uint32_t)RP1_PCI_BAR2_OFFSET, + }; + + rt_pci_read_config_u32(pdev, PCIR_BAR(0), &bar0); + rt_pci_read_config_u32(pdev, PCIR_BAR(1), &bar1); + rt_pci_read_config_u32(pdev, PCIR_BAR(2), &bar2); + + if ((bar0 & ~0xfU) == want[0] && (bar1 & ~0xfU) == want[1] && + (bar2 & ~0xfU) == want[2]) + { + return; + } + + rt_pci_read_config_u16(pdev, PCIR_COMMAND, &cmd); + rt_pci_write_config_u16(pdev, PCIR_COMMAND, cmd & ~PCIM_CMD_MEMEN); + + rt_pci_write_config_u32(pdev, PCIR_BAR(1), want[1]); + rt_pci_write_config_u32(pdev, PCIR_BAR(1) + 4, 0); + rt_pci_write_config_u32(pdev, PCIR_BAR(2), want[2]); + rt_pci_write_config_u32(pdev, PCIR_BAR(2) + 4, 0); + rt_pci_write_config_u32(pdev, PCIR_BAR(0), want[0]); + + rt_pci_write_config_u16(pdev, PCIR_COMMAND, cmd); +} + +/* + * RP1 BAR CPU bases come from the host bridge MEM window + fixed PCI decode + * offsets (BAR1=0). Generic BAR assign may leave resource[1].base at the + * wrong anchor (e.g. win+0x400000); never use that as the window base. + */ +static rt_ubase_t rp1_host_mem_cpu(struct rt_pci_device *pdev) +{ + struct rt_pci_host_bridge *hb = rt_pci_find_host_bridge(pdev->bus); + + if (!hb) + { + return 0; + } + + for (int j = 0; j < hb->bus_regions_nr; ++j) + { + struct rt_pci_bus_region *mem = &hb->bus_regions[j]; + + if (mem->flags == PCI_BUS_REGION_F_MEM && mem->size > 0) + { + rt_uint64_t pci = RP1_PCI_BAR1_OFFSET; + + if (pci >= mem->phy_addr && + pci < mem->phy_addr + mem->size) + { + return mem->cpu_addr + (pci - mem->phy_addr); + } + } + } + + return 0; +} + +static void rp1_sync_bar_resources(struct rt_pci_device *pdev) +{ + rt_ubase_t win = rp1_host_mem_cpu(pdev); + + if (!win) + { + LOG_W("RP1: no MEM window anchor for BAR sync"); + return; + } + + if (pdev->resource[0].size == 0 || (pdev->resource[0].flags & PCI_BUS_REGION_F_NONE)) + { + pdev->resource[0].size = 0x4000; + pdev->resource[0].flags = PCI_BUS_REGION_F_MEM; + } + pdev->resource[0].base = win + RP1_PCI_BAR0_OFFSET; + + if (pdev->resource[1].size == 0 || (pdev->resource[1].flags & PCI_BUS_REGION_F_NONE)) + { + pdev->resource[1].size = 0x400000; + pdev->resource[1].flags = PCI_BUS_REGION_F_MEM; + } + pdev->resource[1].base = win; + + if (pdev->resource[2].size == 0 || (pdev->resource[2].flags & PCI_BUS_REGION_F_NONE)) + { + pdev->resource[2].size = 0x10000; + pdev->resource[2].flags = PCI_BUS_REGION_F_MEM; + } + pdev->resource[2].base = win + RP1_PCI_BAR2_OFFSET; +} + +/* + * Reset RP1 BAR config + resource[] before MSI-X enable so generic + * msix_table_remap() can use resource[bir].base (BIR 0 on Pi5). + */ +static void rp1_prepare_msix_bars(struct rt_pci_device *pdev) +{ + rp1_sync_pci_bar_config(pdev); + rp1_sync_bar_resources(pdev); +} + +static void rp1_msix_reprogram(struct rp1_device *rp1) +{ + struct rt_pci_device *pdev = rp1->pdev; + struct rt_pic *msi_pic = rp1->msi_pic; + struct rt_pci_msi_desc *desc; + + if (!pdev || !pdev->msix_enabled || !msi_pic || !msi_pic->ops->irq_compose_msi_msg) + { + return; + } + + rt_pci_msi_for_each_desc(pdev, desc) + { + struct rt_pic_irq *pirq = rt_pic_find_pirq(msi_pic, desc->irq); + + if (!pirq) + { + continue; + } + + msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg); + rt_pci_msi_write_msg(desc, &desc->msg); + } +} + +static void rp1_irq_eoi(struct rt_pic_irq *pirq) +{ + int hwirq = pirq->hwirq; + struct rp1_device *rp1 = raw_to_rp1(pirq->pic); + + /* Pulse IACK after the device ISR has cleared the level source, not before. */ + if (rp1->rp1_level_triggered_irq[hwirq]) + { + msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK); + } +} + +static void rp1_irq_mask(struct rt_pic_irq *pirq) +{ + struct rt_pic_irq *parent = pirq->parent; + + if (parent && parent->msi_desc) + { + rt_pci_msi_mask_irq(parent); + } + + rt_pic_irq_parent_mask(pirq); +} + +static void rp1_irq_unmask(struct rt_pic_irq *pirq) +{ + struct rt_pic_irq *parent = pirq->parent; + + /* Unmask the underlying PCI MSIX vector. */ + if (parent && parent->msi_desc) + { + rt_pci_msi_unmask_irq(parent); + } + + rt_pic_irq_parent_unmask(pirq); +} + +static rt_err_t rp1_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode) +{ + int hwirq = pirq->hwirq; + struct rp1_device *rp1 = raw_to_rp1(pirq->pic); + + switch (mode) + { + case RT_IRQ_MODE_LEVEL_HIGH: + msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK_EN); + rp1->rp1_level_triggered_irq[hwirq] = RT_TRUE; + break; + + case RT_IRQ_MODE_EDGE_RISING: + msix_cfg_clr(rp1, hwirq, MSIX_CFG_IACK_EN); + rp1->rp1_level_triggered_irq[hwirq] = RT_FALSE; + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static int rp1_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq; + struct rp1_device *rp1 = raw_to_rp1(pic); + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + + pirq->mode = mode; + rp1_irq_set_triger_mode(pirq, mode); + + /* Enable RP1-side MSIX routing. */ + msix_cfg_set(rp1, hwirq, MSIX_CFG_ENABLE); + + rt_pic_cascade(pirq, rp1->msix_entries[hwirq].irq); + + return irq; +} + +static rt_err_t rp1_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + out_pirq->hwirq = args->args[0]; + out_pirq->mode = args->args[1] & RT_IRQ_MODE_MASK; + + return RT_EOK; +} + +const static struct rt_pic_ops rp1_ops = +{ + .name = "RP1", + .irq_eoi = rp1_irq_eoi, + .irq_mask = rp1_irq_mask, + .irq_unmask = rp1_irq_unmask, + .irq_set_triger_mode = rp1_irq_set_triger_mode, + .irq_map = rp1_irq_map, + .irq_parse = rp1_irq_parse, + .flags = RT_PIC_F_IRQ_ROUTING, +}; + +static rt_err_t rp1_probe(struct rt_pci_device *pdev) +{ + rt_err_t err; + struct rp1_device *rp1; + struct rt_ofw_node *rp1_np, *pcie_np; + + pcie_np = rt_pci_find_host_bridge(pdev->bus)->parent.ofw_node; + + if (!pcie_np) + { + return -RT_EINVAL; + } + + rp1 = rt_calloc(1, sizeof(*rp1)); + + if (!rp1) + { + return -RT_ENOMEM; + } + + rp1->pdev = pdev; + + rt_pci_pme_active(pdev, RT_TRUE); + + rt_pci_set_master(pdev); + + /* + * Ensure PCIe inbound/outbound windows are active before MSIX table + * programming and RP1 MMIO. + */ + brcm_pcie_reapply_maps(pdev); + + rp1_prepare_msix_bars(pdev); + + rt_pci_msix_entry_index_linear(rp1->msix_entries, RP1_IRQS); + + if (rt_pci_msix_enable(pdev, rp1->msix_entries, RP1_IRQS) != RP1_IRQS) + { + err = -RT_ERROR; + goto _fail; + } + + rp1->msi_pic = pdev->msi_pic; + rp1_msix_reprogram(rp1); + rp1->bar_start = pdev->resource[1].base; + rp1->bar_end = rp1->bar_start + pdev->resource[1].size; + + rp1->msix_cfg_regs = rt_ioremap((void *)rp1_io_to_phys(rp1, RP1_PCIE_APBS_BASE), 0x1000); + + if (!rp1->msix_cfg_regs) + { + err = -RT_EIO; + goto _free_pci; + } + + if (!(rp1_np = rt_ofw_get_child_by_tag(pcie_np, "rp1"))) + { + LOG_E("Could not find RP1 node under %s", rt_ofw_node_full_name(pcie_np)); + err = -RT_EINVAL; + goto _free_msix; + } + + rp1->parent.priv_data = rp1; + rp1->parent.ops = &rp1_ops; + rt_pic_linear_irq(&rp1->parent, RP1_IRQS); + rt_pic_user_extends(&rp1->parent); + + rt_ofw_data(rp1_np) = &rp1->parent; + rt_platform_ofw_request(rp1_np); + + rt_ofw_node_put(rp1_np); + + return RT_EOK; + +_free_msix: + rt_iounmap(rp1->msix_cfg_regs); + +_free_pci: + rt_pci_free_vector(pdev); + +_fail: + rt_free(rp1); + + return err; +} + +static const struct rt_pci_device_id rp1_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RP1_C0) }, + { /* sentinel */ } +}; + +static struct rt_pci_driver rp1_driver = +{ + .name = "rp1", + + .ids = rp1_ids, + .probe = rp1_probe, +}; +RT_PCI_DRIVER_EXPORT(rp1_driver); diff --git a/bsp/raspberry-pi/dm/mfd/rpi-sense.c b/bsp/raspberry-pi/dm/mfd/rpi-sense.c new file mode 100755 index 0000000000..236f0cd2e1 --- /dev/null +++ b/bsp/raspberry-pi/dm/mfd/rpi-sense.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#define DBG_TAG "mfd.rpi-sense" +#define DBG_LVL DBG_INFO +#include + +#include "rpi-sense.h" + +static rt_int32_t i2c_smbus_read_byte_data(struct rt_i2c_client *client, + rt_uint8_t command) +{ + rt_int32_t res; + rt_uint8_t ret = 0; + struct rt_i2c_msg msg[2]; + + msg[0].buf = &command; + msg[0].addr = client->client_addr; + msg[0].len = 1; + msg[0].flags = RT_I2C_WR; + + msg[1].buf = &ret; + msg[1].addr = client->client_addr; + msg[1].len = 1; + msg[1].flags = RT_I2C_RD; + + res = rt_i2c_transfer(client->bus, msg, 2); + + return res == 2 ? ret : res; +} + +rt_int32_t rpisense_reg_read(struct rpisense *rpisense, int reg) +{ + rt_int32_t ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg); + + if (ret < 0) + { + LOG_E("Read from reg(%d) error = %s", reg, rt_strerror(ret)); + } + + /* + * As the BCM270x I2C clock stretching bug, some values may have MSB set. + * Clear it to avoid incorrect values. + */ + return ret & 0x7f; +} + +rt_ssize_t rpisense_block_write(struct rpisense *rpisense, const char *buf, int count) +{ + rt_ssize_t ret; + struct rt_i2c_client *client = rpisense->i2c_client; + + ret = rt_i2c_master_send(client->bus, client->client_addr, 0, (void *)buf, count); + + if (ret < 0) + { + LOG_E("Write block(%d) error = %s", count, rt_strerror(ret)); + } + + return ret; +} + +static void rpisense_client_dev_register(struct rpisense *rpisense, + const char *name, struct rt_platform_device *pdev) +{ + pdev->name = name; + pdev->priv = rpisense; + + rt_platform_device_register(pdev); +} + +static rt_err_t rpisense_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_int32_t value; + struct rt_device *dev = &client->parent; + struct rpisense *rpisense = rt_calloc(1, sizeof(*rpisense)); + + if (!rpisense) + { + return -RT_ENOMEM; + } + + rpisense->i2c_client = client; + + value = rpisense_reg_read(rpisense, RPISENSE_WAI); + if (value > 0) + { + if (value != RPISENSE_ID) + { + err = -RT_EINVAL; + goto _fail; + } + } + else + { + err = value; + goto _fail; + } + + value = rpisense_reg_read(rpisense, RPISENSE_VER); + if (value < 0) + { + err = value; + goto _fail; + } + + LOG_I("Raspberry Pi Sense HAT firmware version %i", value); + + dev->user_data = rpisense; + + rpisense_client_dev_register(rpisense, "rpi-sense-js", &rpisense->joystick_dev); + rpisense_client_dev_register(rpisense, "rpi-sense-fb", &rpisense->framebuffer_dev); + + return RT_EOK; + +_fail: + rt_free(rpisense); + + return err; +} + +static rt_err_t rpisense_remove(struct rt_i2c_client *client) +{ + struct rpisense *rpisense = client->parent.user_data; + + rt_bus_remove_device(&rpisense->joystick_dev.parent); + rt_bus_remove_device(&rpisense->framebuffer_dev.parent); + + rt_free(rpisense); + + return RT_EOK; +} + +static const struct rt_i2c_device_id rpisense_ids[] = +{ + { .name = "rpi-sense" }, + { /* sentinel */ }, +}; + +static const struct rt_ofw_node_id rpisense_ofw_ids[] = +{ + { .compatible = "rpi,rpi-sense" }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver rpisense_driver = +{ + .ids = rpisense_ids, + .ofw_ids = rpisense_ofw_ids, + + .probe = rpisense_probe, + .remove = rpisense_remove, +}; +RT_I2C_DRIVER_EXPORT(rpisense_driver); diff --git a/bsp/raspberry-pi/dm/nvmem/Kconfig b/bsp/raspberry-pi/dm/nvmem/Kconfig new file mode 100755 index 0000000000..6c5b3b8dd1 --- /dev/null +++ b/bsp/raspberry-pi/dm/nvmem/Kconfig @@ -0,0 +1,4 @@ +config RT_NVMEM_RASPBERRYPI_OTP + bool "Raspberry Pi OTP support" + depends on RT_USING_NVMEM + default n diff --git a/bsp/raspberry-pi/dm/nvmem/SConscript b/bsp/raspberry-pi/dm/nvmem/SConscript new file mode 100755 index 0000000000..f5635e6088 --- /dev/null +++ b/bsp/raspberry-pi/dm/nvmem/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_NVMEM_RASPBERRYPI_OTP']): + src += ['raspberrypi-otp.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/nvmem/raspberrypi-otp.c b/bsp/raspberry-pi/dm/nvmem/raspberrypi-otp.c new file mode 100755 index 0000000000..2294e736bc --- /dev/null +++ b/bsp/raspberry-pi/dm/nvmem/raspberrypi-otp.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#define DBG_TAG "nvmem.raspberrypi" +#define DBG_LVL DBG_INFO +#include + +#include + +#define MAX_ROWS 192 + +struct rpi_otp +{ + struct rt_nvmem_device parent; + + struct rpi_firmware *fw; + rt_uint32_t block; +}; + +#define raw_to_rpi_otp(raw) rt_container_of(raw, struct rpi_otp, parent) + +static rt_ssize_t rpi_otp_read(struct rt_nvmem_device *ndev, int offset, + void *val, rt_size_t bytes) +{ + rt_err_t err; + int words, index; + rt_uint32_t data[3 + MAX_ROWS]; + struct rpi_otp *otp = raw_to_rpi_otp(ndev); + + words = bytes / sizeof(rt_uint32_t); + index = offset / sizeof(rt_uint32_t); + data[0] = otp->block; + data[1] = index; + data[2] = words; + + if (words > MAX_ROWS) + { + return -RT_EINVAL; + } + + err = rpi_firmware_property(otp->fw, RPI_FIRMWARE_GET_USER_OTP, &data, sizeof(data)); + + if (!err) + { + rt_memcpy(val, data + 3, bytes); + } + else + { + rt_memset(val, 0xee, bytes); + } + + return err ? : bytes; +} + +static rt_ssize_t rpi_otp_write(struct rt_nvmem_device *ndev, int offset, + void *val, rt_size_t bytes) +{ + int words, index; + rt_uint32_t data[3 + MAX_ROWS]; + struct rpi_otp *otp = raw_to_rpi_otp(ndev); + + words = bytes / sizeof(rt_uint32_t); + index = offset / sizeof(rt_uint32_t); + data[0] = otp->block; + data[1] = index; + data[2] = words; + + if (bytes > MAX_ROWS * sizeof(rt_uint32_t)) + { + return -RT_EINVAL; + } + + rt_memcpy(data + 3, val, bytes); + + return rpi_firmware_property(otp->fw, RPI_FIRMWARE_SET_USER_OTP, &data, sizeof(data)) ? : bytes; +} + +static rt_err_t rpi_otp_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t reg[2]; + struct rt_nvmem_device *nvmem; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_otp *otp = rt_calloc(1, sizeof(*otp)); + + if (!otp) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + otp->fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!otp->fw) + { + err = -RT_EINVAL; + goto _fail; + } + + if (rt_dm_dev_prop_read_u32_array_index(dev, "reg", 0, RT_ARRAY_SIZE(reg), reg) <= 0) + { + err = -RT_EINVAL; + goto _fail; + } + + nvmem = &otp->parent; + nvmem->parent.ofw_node = np; + nvmem->reg_read = rpi_otp_read, + nvmem->reg_write = rpi_otp_write, + nvmem->size = reg[1] * sizeof(rt_uint32_t); + nvmem->read_only = !rt_dm_dev_prop_read_bool(dev, "rw"); + nvmem->stride = sizeof(rt_uint32_t); + nvmem->word_size = sizeof(rt_uint32_t); + + if ((err = rt_nvmem_device_register(nvmem))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (otp->fw) + { + rpi_firmware_put(otp->fw); + } + + rt_free(otp); + + return err; +} + +static rt_err_t rpi_otp_remove(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rpi_otp *otp = pdev->parent.user_data; + + err = rt_nvmem_device_unregister(&otp->parent); + + rpi_firmware_put(otp->fw); + + rt_free(otp); + + return err; +} + +static const struct rt_ofw_node_id rpi_top_ofw_ids[] = +{ + { .compatible = "raspberrypi,rpi-otp", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_top_driver = +{ + .name = "nvmem-raspberrypi-otp", + .ids = rpi_top_ofw_ids, + + .probe = rpi_otp_probe, + .remove = rpi_otp_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpi_top_driver); diff --git a/bsp/raspberry-pi/dm/pci/Kconfig b/bsp/raspberry-pi/dm/pci/Kconfig new file mode 100755 index 0000000000..20e93a8622 --- /dev/null +++ b/bsp/raspberry-pi/dm/pci/Kconfig @@ -0,0 +1,5 @@ +config RT_PCIE_BRCMSTB + bool "Broadcom Brcmstb PCIe controller" + depends on RT_PCI_MSI + depends on RT_USING_OFW + default n diff --git a/bsp/raspberry-pi/dm/pci/SConscript b/bsp/raspberry-pi/dm/pci/SConscript new file mode 100755 index 0000000000..f8b4e28c2b --- /dev/null +++ b/bsp/raspberry-pi/dm/pci/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pci'] + +if GetDepend(['RT_PCIE_BRCMSTB']): + src += ['pcie-brcmstb.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pci/pcie-brcmstb.c b/bsp/raspberry-pi/dm/pci/pcie-brcmstb.c new file mode 100755 index 0000000000..97aa97483c --- /dev/null +++ b/bsp/raspberry-pi/dm/pci/pcie-brcmstb.c @@ -0,0 +1,2669 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pcie.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include +#include + +/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ +#define BRCM_PCIE_CAP_REGS 0x00ac + +/* Broadcom STB PCIe Register Offsets */ +#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188 +#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc +#define PCIE_RC_CFG_VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN 0x0 + +#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c +#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff + +#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc +#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK 0x1f0 + +#define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8 +#define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8 + +#define PCIE_RC_TL_VDM_CTL0 0x0a20 +#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000 +#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000 +#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000 + +#define PCIE_RC_TL_VDM_CTL1 0x0a0c +#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff +#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000 + +#define PCIE_RC_DL_MDIO_ADDR 0x1100 +#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 +#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 + +#define PCIE_RC_PL_REG_PHY_CTL_1 0x1804 +#define PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK 0x8 + +#define PCIE_RC_PL_PHY_CTL_15 0x184c +#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000 +#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff + +#define PCIE_RC_PL_STATS_CTRL 0x1940 +#define PCIE_RC_PL_STATS_CTRL_EN_MASK 0x1 +#define PCIE_RC_PL_STATS_CTRL_LEN_MASK 0xfffffff0 + +#define PCIE_RC_PL_STATS_TXTLP_LO 0x1944 +#define PCIE_RC_PL_STATS_TXTLP_HI 0x1948 +#define PCIE_RC_PL_STATS_TXDLLP_LO 0x194c +#define PCIE_RC_PL_STATS_TXDLLP_HI 0x1950 +#define PCIE_RC_PL_STATS_RXTLP_LO 0x195c +#define PCIE_RC_PL_STATS_RXTLP_HI 0x1960 +#define PCIE_RC_PL_STATS_RXDLLP_LO 0x1964 +#define PCIE_RC_PL_STATS_RXDLLP_HI 0x1968 +#define PCIE_RC_PL_STATS_RXPL_ERR 0x1974 +#define PCIE_RC_PL_STATS_RXDL_ERR 0x1978 +#define PCIE_RC_PL_STATS_RXTL_ERR 0x197c + +#define PCIE_RC_PL_LTSSM_STATS_3 0x19b0 +#define PCIE_RC_PL_LTSSM_STATS_3_TIME_L0S_MASK 0xffff0000 +#define PCIE_RC_PL_LTSSM_STATS_3_TIME_RECOV_MASK 0x0000ffff + +#define PCIE_RC_PL_LTSSM_STATS_CNT 0x19b4 +#define PCIE_RC_PL_LTSSM_STATS_CNT_L0S_FAIL_MASK 0xffff0000 +#define PCIE_RC_PL_LTSSM_STATS_CNT_RECOV_MASK 0x0000ffff + +#define PCIE_RC_PL_LTSSM_HIST_0 0x1cec +#define PCIE_RC_PL_LTSSM_HIST(n) (PCIE_RC_PL_LTSSM_HIST_0 + ((n) * 4)) + +#define PCIE_MISC_MISC_CTRL 0x4008 +#define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80 +#define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 +#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 +#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 +#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 + +#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 +#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x07c00000 +#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x0000001f +#define SCB_SIZE_MASK(x) PCIE_MISC_MISC_CTRL_SCB ## x ## _SIZE_MASK + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c +#define PCIE_MEM_WIN0_LO(win) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 8) + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 +#define PCIE_MEM_WIN0_HI(win) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 8) + +#define PCIE_BRCM_MAX_INBOUND_WINS 16 +#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c +#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f + +#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 + +#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 +#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 + +#define PCIE_MISC_MSI_DATA_CONFIG 0x404c +#define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540 +#define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540 + +#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c + +#define PCIE_MISC_PCIE_CTRL 0x4064 +#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 +#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4 + +#define PCIE_MISC_PCIE_STATUS 0x4068 +#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 +#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 +#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 +#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 + +#define PCIE_MISC_REVISION 0x406c +#define BRCM_PCIE_HW_REV_33 0x0303 +#define BRCM_PCIE_HW_REV_3_20 0x0320 + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 +#define PCIE_MEM_WIN0_BASE_LIMIT(win) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff +#define PCIE_MEM_WIN0_BASE_HI(win) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff +#define PCIE_MEM_WIN0_LIMIT_HI(win) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) + +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->soc_data->reg_offsets[PCIE_HARD_DEBUG] +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK 0x8 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_ENABLE_MASK 0x10000 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_OUT_MASK 0x100000 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK 0x200000 +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 +#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000 +#define PCIE_CLKREQ_MASK \ + (PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK | \ + PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK) + +/* PCIe Link Capabilities: L0s Entry Supported (PCI Express Base Spec) */ +#ifndef PCI_EXP_LNKCAP_ASPM_L0S +#define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 +#endif + +#define PCIE_MISC_CTRL_1 0x40A0 +#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf +#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK RT_BIT(3) +#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK RT_BIT(4) +#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK RT_BIT(5) + +#define PCIE_MISC_UBUS_CTRL 0x40a4 +#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK RT_BIT(13) +#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK RT_BIT(19) + +#define PCIE_MISC_UBUS_TIMEOUT 0x40a8 + +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK RT_BIT(0) +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0 +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP 0x410c + +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4 +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK RT_BIT(0) +#define PCIE_MISC_UBUS_BAR3_CONFIG_REMAP 0x40bc + +/* Additional RC BARs */ +#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 +#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8 + +#define PCIE_MISC_RC_BAR10_CONFIG_LO 0x4104 +#define PCIE_MISC_RC_BAR10_CONFIG_HI 0x4108 + +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110 + +#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_LO 0x413c +#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_HI 0x4140 + +/* AXI priority forwarding - automatic level-based */ +#define PCIE_MISC_TC_QUEUE_TO_QOS_MAP(x) (0x4160 - (x) * 4) +/* Defined in quarter-fullness */ +#define QUEUE_THRESHOLD_34_TO_QOS_MAP_SHIFT 12 +#define QUEUE_THRESHOLD_23_TO_QOS_MAP_SHIFT 8 +#define QUEUE_THRESHOLD_12_TO_QOS_MAP_SHIFT 4 +#define QUEUE_THRESHOLD_01_TO_QOS_MAP_SHIFT 0 +#define QUEUE_THRESHOLD_MASK 0xf + +/* VDM messages indexing TCs to AXI priorities */ +/* Indexes 8-15 */ +#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164 +/* Indexes 0-7 */ +#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168 +#define VDM_PRIORITY_TO_QOS_MAP_SHIFT(x) (4 * (x)) +#define VDM_PRIORITY_TO_QOS_MAP_MASK 0xf + +#define PCIE_MISC_AXI_INTF_CTRL 0x416c +#define AXI_EN_RCLK_QOS_ARRAY_FIX RT_BIT(13) +#define AXI_EN_QOS_UPDATE_TIMING_FIX RT_BIT(12) +#define AXI_DIS_QOS_GATING_IN_MASTER RT_BIT(11) +#define AXI_REQFIFO_EN_QOS_PROPAGATION RT_BIT(7) +#define AXI_BRIDGE_LOW_LATENCY_MODE RT_BIT(6) +#define AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK 0x3f + +#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170 + +#define PCIE_MSI_INTR2_BASE 0x4500 +/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ +#define MSI_INT_STATUS 0x0 +#define MSI_INT_CLR 0x8 +#define MSI_INT_MASK_SET 0x10 +#define MSI_INT_MASK_CLR 0x14 + +#define PCIE_EXT_CFG_DATA 0x8000 +#define PCIE_EXT_CFG_INDEX 0x9000 + +#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 +#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0 + +#define RGR1_SW_INIT_1_INIT_GENERIC_MASK 0x2 +#define RGR1_SW_INIT_1_INIT_GENERIC_SHIFT 0x1 +#define RGR1_SW_INIT_1_INIT_7278_MASK 0x1 +#define RGR1_SW_INIT_1_INIT_7278_SHIFT 0x0 + +/* PCIe parameters */ +#define BRCM_NUM_PCIE_OUT_WINS 0x4 +#define BRCM_INT_PCI_MSI_NR 32 +#define BRCM_INT_PCI_MSI_LEGACY_NR 8 +#define BRCM_INT_PCI_MSI_SHIFT 0 +#define BRCM_INT_PCI_MSI_MASK RT_GENMASK(BRCM_INT_PCI_MSI_NR - 1, 0) +#define BRCM_INT_PCI_MSI_LEGACY_MASK RT_GENMASK(31, 32 - BRCM_INT_PCI_MSI_LEGACY_NR) + +/* MSI target addresses */ +#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL +#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL + +/* PCIe CEM 2.2 / PCIe r5.0 6.6.1: wait after PERST# deassertion */ +#define PCIE_RESET_CONFIG_WAIT_MS 100 + +/* MDIO registers */ +#define MDIO_PORT0 0x0 +#define MDIO_DATA_MASK 0x7fffffff +#define MDIO_PORT_MASK 0xf0000 +#define MDIO_PORT_EXT_MASK 0x200000 +#define MDIO_REGAD_MASK 0xffff +#define MDIO_CMD_MASK 0x00100000 +#define MDIO_CMD_READ 0x1 +#define MDIO_CMD_WRITE 0x0 +#define MDIO_DATA_DONE_MASK 0x80000000 +#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0) +#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1) +#define SSC_REGS_ADDR 0x1100 +#define SET_ADDR_OFFSET 0x1f +#define SSC_CNTL_OFFSET 0x2 +#define SSC_CNTL_OVRD_EN_MASK 0x8000 +#define SSC_CNTL_OVRD_VAL_MASK 0x4000 +#define SSC_STATUS_OFFSET 0x1 +#define SSC_STATUS_SSC_MASK 0x400 +#define SSC_STATUS_PLL_LOCK_MASK 0x800 +#define PCIE_BRCM_MAX_MEMC 3 + +#define IDX_ADDR(pcie) (pcie->soc_data->reg_offsets[EXT_CFG_INDEX]) +#define DATA_ADDR(pcie) (pcie->soc_data->reg_offsets[EXT_CFG_DATA]) +#define HARD_DEBUG(pcie) (pcie->soc_data->reg_offsets[PCIE_HARD_DEBUG]) +#define INTR2_CPU_BASE(pcie) (pcie->soc_data->reg_offsets[PCIE_INTR2_CPU_BASE]) +#define PCIE_RGR1_SW_INIT_1(pcie) (pcie->soc_data->reg_offsets[RGR1_SW_INIT_1]) + +/* Rescal registers */ +#define PCIE_DVT_PMU_PHY_CTRL 0xc700 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_NFLDS 0x3 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_DIG_RESET_MASK 0x4 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_DIG_RESET_SHIFT 0x2 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_RESET_MASK 0x2 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_RESET_SHIFT 0x1 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_PWRDN_MASK 0x1 +#define PCIE_DVT_PMU_PHY_CTRL_DAST_PWRDN_SHIFT 0x0 + +enum +{ + RGR1_SW_INIT_1, + EXT_CFG_INDEX, + EXT_CFG_DATA, + PCIE_HARD_DEBUG, + PCIE_INTR2_CPU_BASE, +}; + +enum +{ + RGR1_SW_INIT_1_INIT_MASK, + RGR1_SW_INIT_1_INIT_SHIFT, +}; + +enum brcm_pcie_type +{ + GENERIC, + BCM2711, + BCM4908, + BCM7278, + BCM7425, + BCM7435, + BCM7712, +}; + +static const char * const supplies_prefix[] = +{ + "vpcie3v3", + "vpcie3v3aux", + "vpcie12v", +}; + +struct brcm_pcie; + +struct inbound_win +{ + rt_uint64_t size; + rt_uint64_t pci_offset; + rt_uint64_t cpu_addr; +}; + +struct pcie_cfg_soc_data +{ + const int *reg_offsets; + const enum brcm_pcie_type type; + const rt_bool_t has_phy; + +#define CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN RT_BIT(0) +#define CFG_QUIRK_NO_SSC RT_BIT(1) + const rt_uint32_t quirks; + rt_uint8_t num_inbound_wins; + + rt_err_t (*perst_set)(struct brcm_pcie *pcie, rt_uint32_t val); + rt_err_t (*bridge_sw_init_set)(struct brcm_pcie *pcie, rt_uint32_t val); + rt_err_t (*post_setup)(struct brcm_pcie *pcie); +}; + +struct brcm_msi +{ + int irq; + void *pcie_base; + void *intr_base; + + struct rt_pic inner_pic; + rt_uint64_t data_address; + + rt_bool_t legacy; + /* Some chips have MSIs in bits [31..24] of a shared register. */ + int legacy_shift; + + int msi_max_nr; + RT_BITMAP_DECLARE(msi_map, 64); + struct rt_spinlock lock; +}; + +/* Internal PCIe Host Controller Information. */ +struct brcm_pcie +{ + const struct pcie_cfg_soc_data *soc_data; + struct rt_device *dev; + + void *base; + + rt_bool_t ssc; /* Spread Spectrum Clocking */ + rt_bool_t l1ss; /* L1 PM Substates */ + rt_bool_t ep_wakeup_capable; + rt_uint32_t qos_map; + rt_uint32_t generation; + rt_uint32_t misc_revision; + rt_uint32_t tperst_clk_ms; + + rt_size_t memc_nr; + rt_uint64_t memc_size[PCIE_BRCM_MAX_MEMC]; + + struct rt_clk *clk; + struct rt_reset_control *rescal_rstc; + struct rt_reset_control *perst_rstc; + struct rt_reset_control *bridge_rstc; + struct rt_reset_control *swinit_rstc; + struct rt_regulator *supplies[RT_ARRAY_SIZE(supplies_prefix)]; + + struct brcm_msi *msi; + rt_uint64_t msi_data_address; + + struct rt_pci_host_bridge *bridge; + + struct inbound_win inbound_wins[PCIE_BRCM_MAX_INBOUND_WINS]; + rt_uint8_t num_inbound_wins; +}; + +static void brcm_pcie_reapply_7712_maps(struct brcm_pcie *pcie); + +rt_inline void replace_u32_bitfield(rt_uint32_t *p, rt_uint32_t val, rt_uint32_t field) +{ + *p = (*p & ~field) | ((val & (field / (field & -field))) * (field & -field)); +} + +rt_inline void replace_u16_bitfield(rt_uint16_t *p, rt_uint16_t val, rt_uint16_t field) +{ + *p = (*p & ~field) | ((val & (field / (field & -field))) * (field & -field)); +} + +rt_inline int __fls64(rt_uint64_t x) +{ + const rt_uint64_t bits_per_u64 = (sizeof(x) * 8); + int num = bits_per_u64 - 1; + + if (x == 0) + { + return 0; + } + + if (!(x & (~0ULL << (bits_per_u64 - 32)))) + { + num -= 32; + x <<= 32; + } + + if (!(x & (~0ULL << (bits_per_u64 - 16)))) + { + num -= 16; + x <<= 16; + } + + if (!(x & (~0ULL << (bits_per_u64 - 8)))) + { + num -= 8; + x <<= 8; + } + + if (!(x & (~0ULL << (bits_per_u64 - 4)))) + { + num -= 4; + x <<= 4; + } + + if (!(x & (~0ULL << (bits_per_u64 - 2)))) + { + num -= 2; + x <<= 2; + } + + if (!(x & (~0ULL << (bits_per_u64 - 1)))) + { + num -= 1; + } + + return num + 1; +} + +rt_uint32_t __hweight32(rt_uint32_t w) +{ + rt_uint32_t res = w - ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res + (res >> 4)) & 0x0f0f0f0f; + res = res + (res >> 8); + return (res + (res >> 16)) & 0x000000ff; +} + +rt_inline rt_bool_t is_bmips(const struct brcm_pcie *pcie) +{ + const struct pcie_cfg_soc_data *soc_data = pcie->soc_data; + + return soc_data->type == BCM7435 || soc_data->type == BCM7425; +} + +/* + * This is to convert the size of the inbound "BAR" region to the + * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE + */ +static int brcm_pcie_encode_ibar_size(rt_uint64_t size) +{ + int log2_in = rt_ilog2(size); + + if (log2_in >= 12 && log2_in <= 15) + { + /* Covers 4KB to 32KB (inclusive) */ + return (log2_in - 12) + 0x1c; + } + else if (log2_in >= 16 && log2_in <= 36) + { + /* Covers 64KB to 64GB, (inclusive) */ + return log2_in - 15; + } + + /* Something is awry so disable */ + return 0; +} + +static rt_uint32_t brcm_pcie_mdio_form_pkt(int port, int regad, int cmd) +{ + rt_uint32_t pkt = 0; + + pkt |= RT_FIELD_PREP(MDIO_PORT_EXT_MASK, port >> 4); + pkt |= RT_FIELD_PREP(MDIO_PORT_MASK, port); + pkt |= RT_FIELD_PREP(MDIO_REGAD_MASK, regad); + pkt |= RT_FIELD_PREP(MDIO_CMD_MASK, cmd); + + return pkt; +} + +/* Negative return value indicates error */ +static rt_err_t brcm_pcie_mdio_read(void *base, + rt_uint8_t port, rt_uint8_t regad, rt_uint32_t *val) +{ + rt_uint32_t data; + + HWREG32(base + PCIE_RC_DL_MDIO_ADDR) = + brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ); + data = HWREG32(base + PCIE_RC_DL_MDIO_ADDR); + + data = HWREG32(base + PCIE_RC_DL_MDIO_RD_DATA); + + for (int tries = 0; !MDIO_RD_DONE(data) && tries < 10; ++tries) + { + rt_hw_us_delay(10); + data = HWREG32(base + PCIE_RC_DL_MDIO_RD_DATA); + } + + *val = RT_FIELD_GET(MDIO_DATA_MASK, data); + + return MDIO_RD_DONE(data) ? 0 : -RT_EIO; +} + +/* Negative return value indicates error */ +static rt_err_t brcm_pcie_mdio_write(void *base, + rt_uint8_t port, rt_uint8_t regad, rt_uint16_t wrdata) +{ + rt_uint32_t data; + + HWREG32(base + PCIE_RC_DL_MDIO_ADDR) = + brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE); + data = HWREG32(base + PCIE_RC_DL_MDIO_ADDR); + HWREG32(base + PCIE_RC_DL_MDIO_WR_DATA) = MDIO_DATA_DONE_MASK | wrdata; + + data = HWREG32(base + PCIE_RC_DL_MDIO_WR_DATA); + + for (int tries = 0; !MDIO_WT_DONE(data) && tries < 10; ++tries) + { + rt_hw_us_delay(10); + data = HWREG32(base + PCIE_RC_DL_MDIO_WR_DATA); + } + + return MDIO_WT_DONE(data) ? 0 : -RT_EIO; +} + +/* + * Configures device for Spread Spectrum Clocking (SSC) mode; + * a negative return value indicates error. + */ +static rt_err_t brcm_pcie_set_ssc(struct brcm_pcie *pcie) +{ + int pll, ssc; + rt_err_t err; + rt_uint32_t tmp; + + if ((err = brcm_pcie_mdio_write(pcie->base, + MDIO_PORT0, SET_ADDR_OFFSET, SSC_REGS_ADDR)) < 0) + { + return err; + } + + if ((err = brcm_pcie_mdio_read(pcie->base, + MDIO_PORT0, SSC_CNTL_OFFSET, &tmp)) < 0) + { + return err; + } + + replace_u32_bitfield(&tmp, 1, SSC_CNTL_OVRD_EN_MASK); + replace_u32_bitfield(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK); + + if ((err = brcm_pcie_mdio_write(pcie->base, + MDIO_PORT0, SSC_CNTL_OFFSET, tmp)) < 0) + { + return err; + } + + rt_hw_us_delay(1500); + + if ((err = brcm_pcie_mdio_read(pcie->base, + MDIO_PORT0, SSC_STATUS_OFFSET, &tmp)) < 0) + { + return err; + } + + ssc = RT_FIELD_GET(SSC_STATUS_SSC_MASK, tmp); + pll = RT_FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp); + + return ssc && pll ? 0 : -RT_EIO; +} + +/* + * SerDes MDIO refclk programming for BCM7712/2712 (54MHz xosc). + * Must run after SERDES_IDDQ is cleared. + */ +static void brcm_pcie_delay_ms(rt_uint32_t ms); + +static rt_err_t brcm_pcie_serdes_munge_pll(struct brcm_pcie *pcie) +{ + void *base = pcie->base; + const rt_uint16_t data[] = + { + 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 + }; + const rt_uint8_t regs[] = + { + 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e + }; + rt_err_t err; + + if ((err = brcm_pcie_mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET, 0x1600))) + { + return err; + } + + for (int i = 0; i < RT_ARRAY_SIZE(regs); ++i) + { + if ((err = brcm_pcie_mdio_write(base, MDIO_PORT0, regs[i], data[i]))) + { + return err; + } + } + + rt_hw_us_delay(200); + + return RT_EOK; +} + +static void brcm_pcie_serdes_pm_clk_period(struct brcm_pcie *pcie) +{ + rt_uint32_t tmp; + void *base = pcie->base; + + /* + * L1SS sub-state timers: PM clock period 18.52ns (1/54MHz, round down). + */ + tmp = HWREG32(base + PCIE_RC_PL_PHY_CTL_15); + tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; + tmp |= 0x12; + HWREG32(base + PCIE_RC_PL_PHY_CTL_15) = tmp; +} + +/* Limits operation to a specific generation (1, 2, or 3) */ +static void brcm_pcie_set_generation(struct brcm_pcie *pcie, int generation) +{ + rt_uint16_t lnkctl2; + rt_uint32_t lnkcap; + + lnkctl2 = HWREG16(pcie->base + BRCM_PCIE_CAP_REGS + PCIER_LINK_CTL2); + lnkcap = HWREG32(pcie->base + BRCM_PCIE_CAP_REGS + PCIER_LINK_CAP); + + replace_u32_bitfield(&lnkcap, generation, PCIEM_LINK_CAP_MAX_SPEED); + HWREG32(pcie->base + BRCM_PCIE_CAP_REGS + PCIER_LINK_CAP) = lnkcap; + + replace_u16_bitfield(&lnkctl2, generation, PCIEM_LNKCTL2_TLS); + HWREG16(pcie->base + BRCM_PCIE_CAP_REGS + PCIER_LINK_CTL2) = lnkctl2; +} + +static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, rt_uint32_t win, + rt_uint64_t cpu_addr, rt_uint64_t pcie_addr, rt_uint64_t size) +{ + int high_addr_shift; + rt_ubase_t cpu_addr_mb, limit_addr_mb; + rt_uint32_t cpu_addr_mb_high, limit_addr_mb_high, tmp; + + /* Set the base of the pcie_addr window */ + HWREG32(pcie->base + PCIE_MEM_WIN0_LO(win)) = rt_lower_32_bits(pcie_addr); + HWREG32(pcie->base + PCIE_MEM_WIN0_HI(win)) = rt_upper_32_bits(pcie_addr); + + /* Write the addr base & limit lower bits (in MBs) */ + cpu_addr_mb = cpu_addr / SIZE_MB; + limit_addr_mb = (cpu_addr + size - 1) / SIZE_MB; + + tmp = HWREG32(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); + replace_u32_bitfield(&tmp, cpu_addr_mb, + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); + replace_u32_bitfield(&tmp, limit_addr_mb, + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK); + HWREG32(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)) = tmp; + + if (is_bmips(pcie)) + { + return; + } + + /* Write the cpu & limit addr upper bits */ + high_addr_shift = __hweight32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); + + cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift; + tmp = HWREG32(pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); + replace_u32_bitfield(&tmp, cpu_addr_mb_high, + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK); + HWREG32(pcie->base + PCIE_MEM_WIN0_BASE_HI(win)) = tmp; + + limit_addr_mb_high = limit_addr_mb >> high_addr_shift; + tmp = HWREG32(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); + replace_u32_bitfield(&tmp, limit_addr_mb_high, + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK); + HWREG32(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)) = tmp; +} + +static void brcm_pcie_misc_ctrl_enable_access(struct brcm_pcie *pcie) +{ + void *base = pcie->base; + rt_uint32_t tmp = HWREG32(base + PCIE_MISC_MISC_CTRL); + rt_uint32_t burst; + + if (is_bmips(pcie)) + { + burst = 0x1; + } + else if (pcie->soc_data->type == BCM2711) + { + burst = 0x0; + } + else if (pcie->soc_data->type == BCM7278) + { + burst = 0x3; + } + else + { + burst = 0x2; + } + + replace_u32_bitfield(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); + replace_u32_bitfield(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK); + HWREG32(base + PCIE_MISC_MISC_CTRL) = tmp; +} + +static void brcm_pcie_apply_outbound_wins(struct brcm_pcie *pcie) +{ + struct rt_pci_host_bridge *bridge = pcie->bridge; + int num_out_wins = 0; + + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + struct rt_pci_bus_region *region = &bridge->bus_regions[i]; + + if (region->flags != PCI_BUS_REGION_F_MEM && + region->flags != PCI_BUS_REGION_F_PREFETCH) + { + continue; + } + + if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) + { + LOG_E("Too many outbound wins"); + return; + } + + if (is_bmips(pcie)) + { + rt_uint64_t start = region->cpu_addr; + rt_off_t offset = region->cpu_addr - region->phy_addr; + rt_uint32_t nwins = region->size / 128 * SIZE_MB; + + if (nwins > BRCM_NUM_PCIE_OUT_WINS) + { + nwins = BRCM_NUM_PCIE_OUT_WINS; + } + + for (int j = 0; j < nwins; ++j, start += 128 * SIZE_MB) + { + brcm_pcie_set_outbound_win(pcie, j, start, start - offset, 128 * SIZE_MB); + } + return; + } + + brcm_pcie_set_outbound_win(pcie, num_out_wins, + region->cpu_addr, region->phy_addr, region->size); + ++num_out_wins; + } +} + +/* The controller is capable of serving in both RC and EP roles */ +static rt_bool_t brcm_pcie_rc_mode(struct brcm_pcie *pcie) +{ + void *base = pcie->base; + rt_uint32_t val = HWREG32(base + PCIE_MISC_PCIE_STATUS); + + return !!RT_FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); +} + +static rt_bool_t brcm_pcie_link_up(struct brcm_pcie *pcie) +{ + rt_uint32_t val = HWREG32(pcie->base + PCIE_MISC_PCIE_STATUS); + rt_uint32_t dla = RT_FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val); + rt_uint32_t plu = RT_FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val); + + return dla && plu; +} + +static void brcm_pcie_prep_train_clk(struct brcm_pcie *pcie) +{ + rt_uint32_t tmp; + void *base = pcie->base; + + tmp = HWREG32(base + HARD_DEBUG(pcie)); + tmp &= ~PCIE_CLKREQ_MASK; + HWREG32(base + HARD_DEBUG(pcie)) = tmp; +} + +static void brcm_pcie_delay_ms(rt_uint32_t ms) +{ + if (ms == 0) + { + return; + } + + /* + * Always busy-wait: link training runs during init (often before the + * scheduler is fully ready). mdelay can yield or mis-time here. + */ + rt_hw_us_delay(ms * 1000UL); +} + +static void *brcm_pcie_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg) +{ + void *base; + struct brcm_pcie *pcie = bus->sysdata; + + base = pcie->base; + + /* Accesses to the RC go right to the RC registers if !devfn */ + if (rt_pci_is_root_bus(bus)) + { + return devfn ? RT_NULL : base + PCIE_ECAM_REG(reg); + } + + /* An access to our HW w/o link-up will cause a CPU Abort */ + if (!brcm_pcie_link_up(pcie)) + { + return RT_NULL; + } + + /* For devices, write to the config space index register */ + HWREG32(pcie->base + IDX_ADDR(pcie)) = PCIE_ECAM_OFFSET(bus->number, devfn, 0); + return base + DATA_ADDR(pcie) + PCIE_ECAM_REG(reg); +} + +static void *brcm7425_pcie_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg) +{ + void *base; + struct brcm_pcie *pcie = bus->sysdata; + + base = pcie->base; + + /* Accesses to the RC go right to the RC registers if !devfn */ + if (rt_pci_is_root_bus(bus)) + { + return devfn ? RT_NULL : base + PCIE_ECAM_REG(reg); + } + + /* An access to our HW w/o link-up will cause a CPU Abort */ + if (!brcm_pcie_link_up(pcie)) + { + return RT_NULL; + } + + /* For devices, write to the config space index register */ + HWREG32(base + IDX_ADDR(pcie)) = PCIE_ECAM_OFFSET(bus->number, devfn, reg); + return base + DATA_ADDR(pcie); +} + +static rt_err_t brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, rt_uint32_t val) +{ + rt_err_t err; + rt_uint32_t tmp, mask = RGR1_SW_INIT_1_INIT_GENERIC_MASK; + rt_uint32_t shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT; + + if (pcie->bridge_rstc) + { + if (val) + { + err = rt_reset_control_assert(pcie->bridge_rstc); + } + else + { + err = rt_reset_control_deassert(pcie->bridge_rstc); + } + + return err; + } + + tmp = HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + tmp = (tmp & ~mask) | ((val << shift) & mask); + HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)) = tmp; + + return RT_EOK; +} + +static rt_err_t brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, rt_uint32_t val) +{ + rt_uint32_t tmp, mask = RGR1_SW_INIT_1_INIT_7278_MASK; + rt_uint32_t shift = RGR1_SW_INIT_1_INIT_7278_SHIFT; + + tmp = HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + tmp = (tmp & ~mask) | ((val << shift) & mask); + HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)) = tmp; + + return RT_EOK; +} + +static rt_err_t brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, rt_uint32_t val) +{ + rt_err_t err; + + if (!pcie->perst_rstc) + { + return -RT_EINVAL; + } + + if (val) + { + err = rt_reset_control_assert(pcie->perst_rstc); + } + else + { + err = rt_reset_control_deassert(pcie->perst_rstc); + } + + return err; +} + +static rt_err_t brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, rt_uint32_t val) +{ + rt_uint32_t tmp; + + /* Perst bit has moved and assert value is 0 */ + tmp = HWREG32(pcie->base + PCIE_MISC_PCIE_CTRL); + replace_u32_bitfield(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); + HWREG32(pcie->base + PCIE_MISC_PCIE_CTRL) = tmp; + + return RT_EOK; +} + +static rt_err_t brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, rt_uint32_t val) +{ + rt_uint32_t tmp; + + tmp = HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + replace_u32_bitfield(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); + HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)) = tmp; + + return RT_EOK; +} + +/* + * access timeout may occur during L1SS sleep periods, even without the + * presence of a PCIe access. + */ +static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie) +{ + /* 4 seconds, our setting for L1SS */ + const rt_uint32_t timeout_us = 4000000; + + /* 7712 does not have this (RGR1) timer */ + if (pcie->soc_data->type == BCM7712) + { + return; + } + + /* Each unit in timeout register is 1/216,000,000 seconds */ + HWREG32(pcie->base + PCIE_RGR1_SW_INIT_1(pcie) - 8) = 216 * timeout_us; +} + +static void brcm_config_clkreq(struct brcm_pcie *pcie) +{ + rt_err_t err; + void *base = pcie->base; + rt_uint32_t clkreq_cntl, tmp; + const char *mode = "default"; + + err = rt_dm_dev_prop_read_string(pcie->dev, "brcm,clkreq-mode", &mode); + + if (err && err != -RT_EINVAL) + { + mode = "safe"; + } + + /* + * brcm,enable-l1ss in DT documents capability; until ASPM is fully + * handled in RT-Thread, force refclk on to avoid EP stuck in L1.x. + */ + if (pcie->soc_data->type == BCM7712 && + rt_dm_dev_prop_read_bool(pcie->dev, "brcm,enable-l1ss")) + { + mode = "safe"; + } + + /* Start out assuming safe mode (both mode bits cleared) */ + clkreq_cntl = HWREG32(base + HARD_DEBUG(pcie)); + clkreq_cntl &= ~PCIE_CLKREQ_MASK; + + if (!rt_strcmp(mode, "no-l1ss")) + { + /* + * "no-l1ss" -- Provides Clock Power Management, L0s, and + * L1, but cannot provide L1 substate (L1SS) power + * savings. If the downstream device connected to the RC is + * L1SS capable AND the OS enables L1SS, all PCIe traffic + * may abruptly halt, potentially hanging the system. + */ + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; + /* + * We want to un-advertise L1 substates because if the OS + * tries to configure the controller into using L1 substate + * power savings it may fail or hang when the RC HW is in + * "no-l1ss" mode. + */ + tmp = HWREG32(base + PCIE_RC_CFG_PRIV1_ROOT_CAP); + replace_u32_bitfield(&tmp, 2, PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK); + HWREG32(base + PCIE_RC_CFG_PRIV1_ROOT_CAP) = tmp; + } + else if (!rt_strcmp(mode, "default")) + { + /* + * "default" -- Provides L0s, L1, and L1SS, but not + * compliant to provide Clock Power Management; + * specifically, may not be able to meet the Tclron max + * timing of 400ns as specified in "Dynamic Clock Control", + * section 3.2.5.2.2 of the PCIe spec. This situation is + * atypical and should happen only with older devices. + */ + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK; + brcm_extend_rbus_timeout(pcie); + } + else + { + /* + * "safe" -- No power savings; refclk is driven by RC + * unconditionally. + */ + if (rt_strcmp(mode, "safe") != 0) + { + LOG_W("invalid 'brcm,clkreq-mode' DT string"); + } + mode = "safe"; + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_OUT_MASK; + clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_REFCLK_OVRD_ENABLE_MASK; + tmp = HWREG32(base + PCIE_RC_CFG_PRIV1_ROOT_CAP); + replace_u32_bitfield(&tmp, 2, PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK); + HWREG32(base + PCIE_RC_CFG_PRIV1_ROOT_CAP) = tmp; + } + + HWREG32(base + HARD_DEBUG(pcie)) = clkreq_cntl; +} + + +static rt_err_t brcm_pcie_start_link(struct brcm_pcie *pcie) +{ + rt_err_t err; + rt_uint32_t tmp; + rt_uint16_t tmp16; + void *base = pcie->base; + + if (pcie->generation) + { + brcm_pcie_set_generation(pcie, pcie->generation); + } + + brcm_pcie_prep_train_clk(pcie); + + if (pcie->tperst_clk_ms) + { + tmp = HWREG32(base + HARD_DEBUG(pcie)); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); + HWREG32(base + HARD_DEBUG(pcie)) = tmp; + + if ((err = pcie->soc_data->perst_set(pcie, 0))) + { + return err; + } + brcm_pcie_delay_ms(pcie->tperst_clk_ms); + + tmp = HWREG32(base + HARD_DEBUG(pcie)); + replace_u32_bitfield(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_PERST_ASSERT_MASK); + HWREG32(base + HARD_DEBUG(pcie)) = tmp; + } + else + { + if ((err = pcie->soc_data->perst_set(pcie, 0))) + { + return err; + } + } + + brcm_pcie_delay_ms(PCIE_RESET_CONFIG_WAIT_MS); + + for (int i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5) + { + brcm_pcie_delay_ms(5); + } + + if (!brcm_pcie_link_up(pcie)) + { + LOG_E("%s: link down", rt_dm_dev_get_name(pcie->dev)); + return -RT_EINVAL; + } + + brcm_config_clkreq(pcie); + + if (pcie->soc_data->post_setup) + { + /* + * post_setup may run before the link is up; re-apply SerDes PLL + * settings after training so downstream refclk is stable. + */ + if ((err = brcm_pcie_serdes_munge_pll(pcie))) + { + LOG_W("post-train serdes munge failed: %s", rt_strerror(err)); + } + else + { + brcm_pcie_serdes_pm_clk_period(pcie); + } + } + + if (pcie->ssc) + { + if (brcm_pcie_set_ssc(pcie)) + { + LOG_E("Failed attempt to enter ssc mode"); + } + } + + brcm_pcie_reapply_7712_maps(pcie); + + tmp16 = HWREG16(base + BRCM_PCIE_CAP_REGS + PCIER_ROOT_CAP); + if (tmp16 & PCIEM_ROOT_CAP_CRS_VIS) + { + tmp16 = HWREG16(base + BRCM_PCIE_CAP_REGS + PCIER_ROOT_CTL); + replace_u16_bitfield(&tmp16, 1, PCIEM_ROOT_CTL_CRS_VIS); + HWREG16(base + BRCM_PCIE_CAP_REGS + PCIER_ROOT_CTL) = tmp16; + } + + return RT_EOK; +} + +static rt_err_t brcm_pcie_add_bus(struct rt_pci_bus *bus) +{ + rt_err_t err = RT_EOK; + struct brcm_pcie *pcie = bus->sysdata; + struct rt_device *dev = &bus->host_bridge->parent; + + if (!bus->parent) + { + return RT_EOK; + } + + if (!rt_pci_is_root_bus(bus->parent)) + { + return RT_EOK; + } + + if (dev->ofw_node) + { + rt_size_t supplies = 0; + + for (int i = 0; i < RT_ARRAY_SIZE(pcie->supplies); ++i) + { + pcie->supplies[i] = rt_regulator_get(dev, supplies_prefix[i]); + + if (rt_is_err(pcie->supplies[i])) + { + err = rt_ptr_err(pcie->supplies[i]); + + while (i --> 0) + { + rt_regulator_put(pcie->supplies[i]); + pcie->supplies[i] = RT_NULL; + } + + return err; + } + else if (pcie->supplies[i]) + { + ++supplies; + } + } + + if (!supplies) + { + goto _no_regulators; + } + + for (int i = 0; i < RT_ARRAY_SIZE(pcie->supplies); ++i) + { + if (pcie->supplies[i]) + { + if ((err = rt_regulator_enable(pcie->supplies[i]))) + { + LOG_E("Can't enable regulators for downstream device"); + + for (int i = 0; i < RT_ARRAY_SIZE(pcie->supplies); ++i) + { + rt_regulator_put(pcie->supplies[i]); + pcie->supplies[i] = RT_NULL; + } + + return err; + } + } + } + } + +_no_regulators: + err = brcm_pcie_start_link(pcie); + + return err; +} + +static rt_err_t brcm_pcie_remove_bus(struct rt_pci_bus *bus) +{ + struct brcm_pcie *pcie = bus->sysdata; + + for (int i = 0; i < RT_ARRAY_SIZE(pcie->supplies); ++i) + { + if (!rt_is_err_or_null(pcie->supplies[i])) + { + rt_regulator_disable(pcie->supplies[i]); + rt_regulator_put(pcie->supplies[i]); + } + } + + return RT_EOK; +} + +/* L23 is a low-power PCIe link state */ +static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) +{ + int l23; + rt_uint32_t tmp; + void *base = pcie->base; + + /* Assert request for L23 */ + tmp = HWREG32(base + PCIE_MISC_PCIE_CTRL); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); + HWREG32(base + PCIE_MISC_PCIE_CTRL) = tmp; + + /* Wait up to 36 msec for L23 */ + tmp = HWREG32(base + PCIE_MISC_PCIE_STATUS); + l23 = RT_FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp); + + for (int i = 0; i < 15 && !l23; ++i) + { + rt_hw_us_delay(2200); + + tmp = HWREG32(base + PCIE_MISC_PCIE_STATUS); + l23 = RT_FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp); + } + + if (!l23) + { + LOG_E("%s: failed to enter low-power link state", rt_dm_dev_get_name(pcie->dev)); + } +} + +static rt_err_t brcm_phy_cntl(struct brcm_pcie *pcie, const int start) +{ + rt_err_t err = RT_EOK; + void *base = pcie->base; + rt_uint32_t val, tmp, combined_mask = 0; + const int beg = start ? 0 : PCIE_DVT_PMU_PHY_CTRL_DAST_NFLDS - 1; + const int end = start ? PCIE_DVT_PMU_PHY_CTRL_DAST_NFLDS : -1; + static const rt_uint32_t shifts[PCIE_DVT_PMU_PHY_CTRL_DAST_NFLDS] = + { + PCIE_DVT_PMU_PHY_CTRL_DAST_PWRDN_SHIFT, + PCIE_DVT_PMU_PHY_CTRL_DAST_RESET_SHIFT, + PCIE_DVT_PMU_PHY_CTRL_DAST_DIG_RESET_SHIFT, + }; + static const rt_uint32_t masks[PCIE_DVT_PMU_PHY_CTRL_DAST_NFLDS] = + { + PCIE_DVT_PMU_PHY_CTRL_DAST_PWRDN_MASK, + PCIE_DVT_PMU_PHY_CTRL_DAST_RESET_MASK, + PCIE_DVT_PMU_PHY_CTRL_DAST_DIG_RESET_MASK, + }; + + for (int i = beg; i != end; start ? ++i : --i) + { + val = start ? RT_BIT_MASK(shifts[i]) : 0; + + tmp = HWREG32(base + PCIE_DVT_PMU_PHY_CTRL); + tmp = (tmp & ~masks[i]) | (val & masks[i]); + HWREG32(base + PCIE_DVT_PMU_PHY_CTRL) = tmp; + + rt_hw_us_delay(125); + combined_mask |= masks[i]; + } + + tmp = HWREG32(base + PCIE_DVT_PMU_PHY_CTRL); + val = start ? combined_mask : 0; + + if ((tmp & combined_mask) != val) + { + err = -RT_EIO; + LOG_E("%s: failed to %s phy", rt_dm_dev_get_name(pcie->dev), start ? "start" : "stop"); + } + + return err; +} + + +static rt_err_t brcm_pcie_post_setup_bcm2712(struct brcm_pcie *pcie) +{ + rt_err_t err; + rt_uint32_t tmp; + rt_uint8_t qos_map[8]; + void *base = pcie->base; + + if ((err = brcm_pcie_serdes_munge_pll(pcie))) + { + return err; + } + + rt_hw_us_delay(200); + brcm_pcie_serdes_pm_clk_period(pcie); + + /* + * BCM7712/2712 uses a UBUS-AXI bridge. + * Suppress AXI error responses and return 1s for read failures. + */ + tmp = HWREG32(base + PCIE_MISC_UBUS_CTRL); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK); + HWREG32(base + PCIE_MISC_UBUS_CTRL) = tmp; + HWREG32(base + PCIE_MISC_AXI_READ_ERROR_DATA) = 0xffffffff; + + /* + * Adjust timeouts. The UBUS timeout also affects Configuration Request + * Retry responses, as the request will get terminated if + * either timeout expires, so both have to be a large value + * (in clocks of 750MHz). + * Set UBUS timeout to 250ms, then set RC config retry timeout + * to be ~240ms. + * + * If CRSSVE=1 this will stop the core from blocking on a Retry + * response, but does require the device to be well-behaved... + */ + HWREG32(base + PCIE_MISC_UBUS_TIMEOUT) = 0xb2d0000; + HWREG32(base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT) = 0xaba0000; + + /* + * BCM2712 has a configurable QoS mechanism that assigns TLP Traffic Classes + * to separate AXI IDs with a configurable priority scheme. + * Dynamic priority elevation is supported through reception of Type 1 + * Vendor Defined Messages, but several bugs make this largely ineffective. + */ + + /* Disable broken forwarding search. Set chicken bits for 2712D0 */ + tmp = HWREG32(base + PCIE_MISC_AXI_INTF_CTRL); + tmp &= ~AXI_REQFIFO_EN_QOS_PROPAGATION; + tmp |= AXI_EN_RCLK_QOS_ARRAY_FIX | AXI_EN_QOS_UPDATE_TIMING_FIX | AXI_DIS_QOS_GATING_IN_MASTER; + HWREG32(base + PCIE_MISC_AXI_INTF_CTRL) = tmp; + + /* + * Work around spurious QoS=0 assignments to inbound traffic. + * If the QOS_UPDATE_TIMING_FIX bit is Reserved-0, then this is a + * 2712C1 chip, or a single-lane RC. Use the best-effort alternative + * which is to partially throttle AXI requests in-flight to SDRAM. + */ + tmp = HWREG32(base + PCIE_MISC_AXI_INTF_CTRL); + if (!(tmp & AXI_EN_QOS_UPDATE_TIMING_FIX)) + { + tmp &= ~AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK; + tmp |= 15; + HWREG32(base + PCIE_MISC_AXI_INTF_CTRL) = tmp; + } + + /* Disable VDM reception by default */ + tmp = HWREG32(base + PCIE_MISC_CTRL_1); + tmp &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; + HWREG32(base + PCIE_MISC_CTRL_1) = tmp; + + /* + * U-Boot enables BAR2 UBUS remap access for inbound EP MemWr (DMA). + * MIP MSIX doorbell (PCI 0xff_ffff_f000) uses inbound BAR3 on 2712. + */ + tmp = HWREG32(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); + HWREG32(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP) = tmp; + + tmp = HWREG32(base + PCIE_MISC_UBUS_BAR3_CONFIG_REMAP); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); + HWREG32(base + PCIE_MISC_UBUS_BAR3_CONFIG_REMAP) = tmp; + + if (!rt_dm_dev_prop_read_u8_array_index(pcie->dev, "brcm,fifo-qos-map", 0, 4, qos_map)) + { + /* + * Backpressure mode - each element is QoS for each + * quartile of FIFO level. Each TC gets the same map, because + * this mode is intended for nonrealtime EPs. + */ + tmp = 0; + for (int i = 0; i < 4; i++) + { + /* Priorities range from 0-15 */ + qos_map[i] &= 0x0f; + tmp |= qos_map[i] << (i * 4); + } + + for (int i = 0; i < 8; i++) + { + HWREG32(base + PCIE_MISC_TC_QUEUE_TO_QOS_MAP(i)) = tmp; + } + } + else if (!rt_dm_dev_prop_read_u8_array_index(pcie->dev, "brcm,vdm-qos-map", 0, 8, qos_map)) + { + /* Enable VDM reception */ + tmp = HWREG32(base + PCIE_MISC_CTRL_1); + tmp |= PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK; + HWREG32(base + PCIE_MISC_CTRL_1) = tmp; + + tmp = 0; + for (int i = 0; i < 8; i++) + { + /* Priorities range from 0-15 */ + qos_map[i] &= 0x0f; + tmp |= qos_map[i] << (i * 4); + } + /* Broken forwarding means no point separating panic priorities from normal */ + HWREG32(base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO) = tmp; + HWREG32(base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI) = tmp; + + /* Match Vendor ID of 0 */ + HWREG32(base + PCIE_RC_TL_VDM_CTL1) = 0; + + /* + * Forward VDMs to priority interface anyway - + * useful for debugging starvation through the received VDM count fields. + */ + tmp = HWREG32(base + PCIE_RC_TL_VDM_CTL0); + tmp |= PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK | + PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK | + PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK; + HWREG32(base + PCIE_RC_TL_VDM_CTL0) = tmp; + } + + return RT_EOK; +} + +static const int pcie_offsets[] = +{ + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x8000, + [PCIE_HARD_DEBUG] = 0x4204, + [PCIE_INTR2_CPU_BASE] = 0x4300, +}; + +static const int pcie_offsets_bcm7278[] = +{ + [RGR1_SW_INIT_1] = 0xc010, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x8000, + [PCIE_HARD_DEBUG] = 0x4204, + [PCIE_INTR2_CPU_BASE] = 0x4300, +}; + +static const int pcie_offsets_bcm7425[] = +{ + [RGR1_SW_INIT_1] = 0x8010, + [EXT_CFG_INDEX] = 0x8300, + [EXT_CFG_DATA] = 0x8304, + [PCIE_HARD_DEBUG] = 0x4204, + [PCIE_INTR2_CPU_BASE] = 0x4300, +}; + +static const int pcie_offsets_bcm7712[] = +{ + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x8000, + [PCIE_HARD_DEBUG] = 0x4304, + [PCIE_INTR2_CPU_BASE] = 0x4400, +}; + +static const struct pcie_cfg_soc_data generic_cfg = +{ + .reg_offsets = pcie_offsets, + .type = GENERIC, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm7425_cfg = +{ + .reg_offsets = pcie_offsets_bcm7425, + .type = BCM7425, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm7435_cfg = +{ + .reg_offsets = pcie_offsets, + .type = BCM7435, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm4908_cfg = +{ + .reg_offsets = pcie_offsets, + .type = BCM4908, + .perst_set = brcm_pcie_perst_set_4908, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm7278_cfg = +{ + .reg_offsets = pcie_offsets_bcm7278, + .type = BCM7278, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm2711_cfg = +{ + .reg_offsets = pcie_offsets, + .type = BCM2711, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm7216_cfg = +{ + .reg_offsets = pcie_offsets_bcm7278, + .type = BCM7278, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, + .has_phy = RT_TRUE, + .num_inbound_wins = 3, +}; + +static const struct pcie_cfg_soc_data bcm7712_cfg = +{ + .reg_offsets = pcie_offsets_bcm7712, + .type = BCM7712, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .num_inbound_wins = 10, +}; + +static const struct pcie_cfg_soc_data bcm2712_cfg = +{ + .reg_offsets = pcie_offsets_bcm7712, + .type = BCM7712, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, + .post_setup = brcm_pcie_post_setup_bcm2712, + .quirks = CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN | CFG_QUIRK_NO_SSC, + .num_inbound_wins = 10, +}; + +static const struct rt_pci_ops brcm_pcie_ops = +{ + .add = brcm_pcie_add_bus, + .remove = brcm_pcie_remove_bus, + .map = brcm_pcie_map, + .read = rt_pci_bus_read_config_uxx, + .write = rt_pci_bus_write_config_uxx, +}; + +static const struct rt_pci_ops brcm7425_pcie_ops = +{ + .add = brcm_pcie_add_bus, + .remove = brcm_pcie_remove_bus, + .map = brcm7425_pcie_map, + .read = rt_pci_bus_read_config_generic_u32, + .write = rt_pci_bus_write_config_generic_u32, +}; + +static void brcm_msi_ack_irq(struct rt_pic_irq *pirq) +{ + struct brcm_msi *msi = pirq->pic->priv_data; + + HWREG32(msi->intr_base + MSI_INT_CLR) = 1 << (pirq->hwirq + msi->legacy_shift); +} + +static void brcm_msi_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) +{ + struct brcm_msi *msi = pirq->pic->priv_data; + + msg->address_lo = rt_lower_32_bits(msi->data_address); + msg->address_hi = rt_upper_32_bits(msi->data_address); + msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | pirq->hwirq; +} + +static int brcm_msi_irq_alloc(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) +{ + int irq, hwirq; + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct brcm_msi *msi = pic->priv_data; + + level = rt_spin_lock_irqsave(&msi->lock); + hwirq = rt_bitmap_next_clear_bit(msi->msi_map, 0, msi->msi_max_nr); + + if (hwirq >= msi->msi_max_nr) + { + irq = -RT_EEMPTY; + goto _out_lock; + } + + rt_bitmap_set_bit(msi->msi_map, hwirq); + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + pirq = rt_pic_find_irq(pic, hwirq); + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + +_out_lock: + rt_spin_unlock_irqrestore(&msi->lock, level); + + return irq; +} + +static void brcm_msi_irq_free(struct rt_pic *pic, int irq) +{ + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct brcm_msi *msi = pic->priv_data; + + pirq = rt_pic_find_pirq(pic, irq); + + if (!pirq) + { + return; + } + + level = rt_spin_lock_irqsave(&msi->lock); + rt_bitmap_clear_bit(msi->msi_map, pirq->hwirq); + rt_spin_unlock_irqrestore(&msi->lock, level); +} + +const static struct rt_pic_ops brcm_msi_ops = +{ + .name = "BRCMSTB-MSI", + .irq_ack = brcm_msi_ack_irq, + .irq_mask = rt_pci_msi_mask_irq, + .irq_unmask = rt_pci_msi_unmask_irq, + .irq_compose_msi_msg = brcm_msi_compose_msi_msg, + .irq_alloc_msi = brcm_msi_irq_alloc, + .irq_free_msi = brcm_msi_irq_free, +}; + +static void brcm_pcie_msi_isr(int irqno, void *param) +{ + rt_uint32_t status; + rt_uint32_t raw_status; + struct rt_pic_irq *pirq; + struct brcm_msi *msi = param; + + RT_UNUSED(irqno); + + raw_status = HWREG32(msi->intr_base + MSI_INT_STATUS); + status = raw_status >> msi->legacy_shift; + + for (int bit = 0; bit < BRCM_INT_PCI_MSI_NR && status; ++bit) + { + if (!(RT_BIT(bit) & status)) + { + continue; + } + + pirq = rt_pic_find_irq(&msi->inner_pic, bit); + brcm_msi_ack_irq(pirq); + rt_pic_handle_isr(pirq); + + pirq = rt_pic_find_irq(&msi->inner_pic, bit + 32); + brcm_msi_ack_irq(pirq); + rt_pic_handle_isr(pirq); + + status &= ~RT_BIT(bit); + } + + rt_hw_interrupt_umask(msi->irq); +} + +static rt_err_t brcm_pcie_enable_msi(struct brcm_pcie *pcie) +{ + int irq; + rt_uint32_t val; + struct brcm_msi *msi; + struct rt_device *dev = pcie->dev; + + if ((irq = rt_dm_dev_get_irq(dev, 1)) < 0) + { + LOG_E("Read map MSI interrupt error = %s", rt_strerror(irq)); + return irq; + } + + if (!(msi = rt_calloc(1, sizeof(*msi)))) + { + return -RT_ENOMEM; + } + + msi->pcie_base = pcie->base; + msi->data_address = pcie->msi_data_address; + msi->irq = irq; + msi->legacy = pcie->misc_revision < BRCM_PCIE_HW_REV_33; + rt_spin_lock_init(&msi->lock); + + if (msi->legacy) + { + msi->intr_base = msi->pcie_base + PCIE_INTR2_CPU_BASE; + msi->msi_max_nr = BRCM_INT_PCI_MSI_LEGACY_NR; + msi->legacy_shift = 24; + } + else + { + msi->intr_base = msi->pcie_base + PCIE_MSI_INTR2_BASE; + msi->msi_max_nr = 64; + msi->legacy_shift = 0; + } + + msi->inner_pic.priv_data = msi; + msi->inner_pic.ops = &brcm_msi_ops; + rt_pic_linear_irq(&msi->inner_pic, msi->msi_max_nr); + rt_pic_user_extends(&msi->inner_pic); + + rt_hw_interrupt_install(msi->irq, brcm_pcie_msi_isr, msi, "brcm-pcie-msi"); + rt_hw_interrupt_umask(msi->irq); + + val = msi->legacy ? BRCM_INT_PCI_MSI_LEGACY_MASK : BRCM_INT_PCI_MSI_MASK; + + HWREG32(msi->intr_base + MSI_INT_MASK_CLR) = val; + HWREG32(msi->intr_base + MSI_INT_CLR) = val; + + /* + * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI enable, + * which we set to 1. + */ + HWREG32(msi->pcie_base + PCIE_MISC_MSI_BAR_CONFIG_LO) = rt_lower_32_bits(msi->data_address) | 0x1; + HWREG32(msi->pcie_base + PCIE_MISC_MSI_BAR_CONFIG_HI) = rt_upper_32_bits(msi->data_address); + + val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32; + HWREG32(msi->pcie_base + PCIE_MISC_MSI_DATA_CONFIG) = val; + + pcie->msi = msi; + + rt_ofw_data(dev->ofw_node) = &msi->inner_pic; + rt_ofw_node_set_flag(dev->ofw_node, RT_OFW_F_READLY); + + return RT_EOK; +} + +rt_inline rt_err_t brcm_phy_start(struct brcm_pcie *pcie) +{ + return pcie->soc_data->has_phy ? brcm_phy_cntl(pcie, 1) : RT_EOK; +} + +rt_inline rt_err_t brcm_phy_stop(struct brcm_pcie *pcie) +{ + return pcie->soc_data->has_phy ? brcm_phy_cntl(pcie, 0) : RT_EOK; +} + +static void brcm_pcie_turn_off(struct brcm_pcie *pcie) +{ + rt_uint32_t tmp; + void *base = pcie->base; + + if (brcm_pcie_link_up(pcie)) + { + brcm_pcie_enter_l23(pcie); + } + /* Assert fundamental reset */ + pcie->soc_data->perst_set(pcie, 1); + + /* Deassert request for L23 in case it was asserted */ + tmp = HWREG32(base + PCIE_MISC_PCIE_CTRL); + replace_u32_bitfield(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); + HWREG32(base + PCIE_MISC_PCIE_CTRL) = tmp; + + if (pcie->soc_data->type != BCM2711) + { + /* Turn off SerDes */ + tmp = HWREG32(base + HARD_DEBUG(pcie)); + replace_u32_bitfield(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); + HWREG32(base + HARD_DEBUG(pcie)) = tmp; + } + + if (!(pcie->soc_data->quirks & CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN)) + { + /* Shutdown PCIe bridge */ + pcie->soc_data->bridge_sw_init_set(pcie, 1); + } +} + +static void add_inbound_win(struct inbound_win *b, rt_uint8_t *count, + rt_uint64_t size, rt_uint64_t cpu_addr, rt_uint64_t pci_offset) +{ + b->size = size; + b->cpu_addr = cpu_addr; + b->pci_offset = pci_offset; + (*count)++; +} + +/* + * Debian DT omits the MIP doorbell dma-ranges entry present in bcm2712.dtsi. + * EP MSIX MemWr to brcm,msi-pci-addr must inbound-map to the MIP MMIO block. + */ +static void brcm_pcie_add_mip_doorbell_win(struct brcm_pcie *pcie, + struct inbound_win *b, rt_uint8_t *n, const struct inbound_win *begin) +{ + struct rt_ofw_node *np, *msi_np; + rt_uint32_t addr_cells[2]; + rt_uint64_t pci_door, cpu_door, reg_size; + int i; + + if (pcie->soc_data->type != BCM7712 || !pcie->dev) + { + return; + } + + np = pcie->dev->ofw_node; + msi_np = rt_ofw_parse_phandle(np, "msi-parent", 0); + if (!msi_np || msi_np == np) + { + rt_ofw_node_put(msi_np); + return; + } + + if (!rt_ofw_node_is_compatible(msi_np, "brcm,bcm2712-mip-intc")) + { + rt_ofw_node_put(msi_np); + return; + } + + if (rt_ofw_prop_read_u32_array_index(msi_np, "brcm,msi-pci-addr", 0, 2, addr_cells) < 2 || + rt_ofw_get_address(msi_np, 0, &cpu_door, ®_size)) + { + rt_ofw_node_put(msi_np); + return; + } + + pci_door = ((rt_uint64_t)addr_cells[0] << 32) | addr_cells[1]; + + for (i = 1; i <= *n; ++i) + { + if (begin[i].pci_offset == pci_door) + { + rt_ofw_node_put(msi_np); + return; + } + } + + if (*n >= pcie->soc_data->num_inbound_wins) + { + LOG_W("No inbound slot for MIP doorbell pci=%#llx", (unsigned long long)pci_door); + rt_ofw_node_put(msi_np); + return; + } + + add_inbound_win(b, n, 0x1000, cpu_door, pci_door); + + rt_ofw_node_put(msi_np); +} + +static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie, struct inbound_win inbound_wins[]) +{ + rt_uint8_t n = 0; + rt_uint64_t lowest_pcie_addr = ~(rt_uint64_t)0; + rt_uint64_t pci_offset, cpu_addr, size = 0, tot_size = 0; + struct rt_pci_host_bridge *bridge = pcie->bridge; + /* + * The HW registers (and PCIe) use order-1 numbering for BARs. As such, + * we have inbound_wins[0] unused and BAR1 starts at inbound_wins[1]. + */ + struct inbound_win *b_begin = &inbound_wins[1], *b = b_begin; + + /* + * STB chips beside 7712 disable the first inbound window default. + * Rather being mapped to system memory it is mapped to the + * internal registers of the SoC. This feature is deprecated, has + * security considerations, and is not implemented in our modern + * SoCs. + */ + if (pcie->soc_data->type != BCM7712) + { + add_inbound_win(b++, &n, 0, 0, 0); + } + + for (int i = 0; i < bridge->dma_regions_nr; ++i) + { + rt_uint64_t pcie_start, cpu_start; + struct rt_pci_bus_region *region = &bridge->dma_regions[i]; + + pcie_start = region->phy_addr; + cpu_start = region->cpu_addr; + + size = region->size; + tot_size += size; + + if (pcie_start < lowest_pcie_addr) + { + lowest_pcie_addr = pcie_start; + } + + /* + * 7712 and newer chips may have many BARs, with each + * offering a non-overlapping viewport to system memory. + * That being said, each BARs size must still be a power of two. + */ + if (pcie->soc_data->type == BCM7712) + { + add_inbound_win(b++, &n, size, cpu_start, pcie_start); + } + + if (n > pcie->soc_data->num_inbound_wins) + { + break; + } + } + + if (lowest_pcie_addr == ~(rt_uint64_t)0) + { + return -RT_EINVAL; + } + + /* + * 7712 and newer chips do not have an internal memory mapping system + * that enables multiple memory controllers. As such, it can return + * now w/o doing special configuration. + */ + if (pcie->soc_data->type == BCM7712) + { + brcm_pcie_add_mip_doorbell_win(pcie, b, &n, inbound_wins); + + if (n > pcie->soc_data->num_inbound_wins) + { + LOG_E("Too many inbound windows (%u)", n); + return -RT_EINVAL; + } + + return n; + } + + pcie->memc_nr = rt_dm_dev_prop_read_u64_array_index(pcie->dev, + "brcm,scb-sizes", 0, PCIE_BRCM_MAX_MEMC, pcie->memc_size); + + if ((rt_ssize_t)pcie->memc_nr <= 0) + { + /* Make an educated guess */ + pcie->memc_nr = 1; + pcie->memc_size[0] = 1ULL << __fls64(tot_size - 1); + } + + /* Each memc is viewed through a "port" that is a power of 2 */ + for (int i = 0, size = 0; i < pcie->memc_nr; ++i) + { + size += pcie->memc_size[i]; + } + + /* Our HW mandates that the window size must be a power of 2 */ + size = 1ULL << __fls64(size - 1); + + /* + * Pi4 firmware rewrites dma-ranges before boot. + * Ignore bogus brcm,scb-sizes and derive the inbound aperture from the + * parsed dma-ranges total instead. + */ + if (pcie->soc_data->type == BCM2711) + { + if (tot_size >= SIZE_MB) + { + rt_uint64_t want = 1ULL << __fls64(tot_size - 1); + + if (size < want) + { + size = want; + } + } + else if (lowest_pcie_addr == 0x400000000ULL) + { + size = 2ULL * SIZE_GB; + } + + } + + /* + * For STB chips, the BAR2 cpu_addr is hardwired to the start + * of system memory, so we set it to 0. + */ + cpu_addr = 0; + pci_offset = lowest_pcie_addr; + + /* + * We validate the inbound memory view even though we should trust + * whatever the device-tree provides. This is because of an HW issue on + * early Raspberry Pi 4's revisions (bcm2711). It turns out its + * firmware has to dynamically edit dma-ranges due to a bug on the + * PCIe controller integration, which prohibits any access above the + * lower 3GB of memory. Given this, we decided to keep the dma-ranges + * in check, avoiding hard to debug device-tree related issues in the + * future: + * + * The PCIe host controller by design must set the inbound viewport to + * be a contiguous arrangement of all of the system's memory. In + * addition, its size mut be a power of two. To further complicate + * matters, the viewport must start on a pcie-address that is aligned + * on a multiple of its size. If a portion of the viewport does not + * represent system memory -- e.g. 3GB of memory requires a 4GB + * viewport -- we can map the outbound memory in or after 3GB and even + * though the viewport will overlap the outbound memory the controller + * will know to send outbound memory downstream and everything else + * upstream. + * + * For example: + * + * - The best-case scenario, memory up to 3GB, is to place the inbound + * region in the first 4GB of pcie-space, as some legacy devices can + * only address 32bits. We would also like to put the MSI under 4GB + * as well, since some devices require a 32bit MSI target address. + * + * - If the system memory is 4GB or larger we cannot start the inbound + * region at location 0 (since we have to allow some space for + * outbound memory @ 3GB). So instead it will start at the 1x + * multiple of its size + */ + if (!size || (pci_offset & (size - 1)) || + (pci_offset < 4UL * SIZE_GB && pci_offset > 2UL * SIZE_GB)) + { + return -RT_EINVAL; + } + + /* Enable inbound window 2, the main inbound window for STB chips */ + add_inbound_win(b++, &n, size, cpu_addr, pci_offset); + + /* + * Disable inbound window 3. On some chips presents the same + * window as #2 but the data appears in a settable endianness. + */ + add_inbound_win(b++, &n, 0, 0, 0); + + return n; +} + +static rt_uint32_t brcm_bar_reg_offset(int bar) +{ + if (bar <= 3) + { + return PCIE_MISC_RC_BAR1_CONFIG_LO + 8 * (bar - 1); + } + else + { + return PCIE_MISC_RC_BAR4_CONFIG_LO + 8 * (bar - 4); + } +} + +static rt_uint32_t brcm_ubus_reg_offset(int bar) +{ + if (bar <= 3) + { + return PCIE_MISC_UBUS_BAR1_CONFIG_REMAP + 8 * (bar - 1); + } + else + { + return PCIE_MISC_UBUS_BAR4_CONFIG_REMAP + 8 * (bar - 4); + } +} + +static void set_inbound_win_registers(struct brcm_pcie *pcie, + const struct inbound_win *inbound_wins, rt_uint8_t num_inbound_wins) +{ + void *base = pcie->base; + + for (int i = 1; i <= num_inbound_wins; ++i) + { + rt_uint64_t pci_offset = inbound_wins[i].pci_offset; + rt_uint64_t cpu_addr = inbound_wins[i].cpu_addr; + rt_uint64_t size = inbound_wins[i].size; + rt_uint32_t reg_offset = brcm_bar_reg_offset(i); + rt_uint32_t tmp = rt_lower_32_bits(pci_offset); + + replace_u32_bitfield(&tmp, brcm_pcie_encode_ibar_size(size), + PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK); + + /* Write low */ + HWREG32(base + reg_offset) = tmp; + /* Write high */ + HWREG32(base + reg_offset + 4) = rt_upper_32_bits(pci_offset); + + /* + * Most STB chips: + * Do nothing. + * 7712: + * All of their BARs need to be set. + */ + if (pcie->soc_data->type == BCM7712) + { + /* BUS remap register settings */ + reg_offset = brcm_ubus_reg_offset(i); + tmp = rt_lower_32_bits(cpu_addr) & ~0xfffU; + tmp |= PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK; + HWREG32(base + reg_offset) = tmp; + HWREG32(base + reg_offset + 4) = rt_upper_32_bits(cpu_addr); + } + } +} + +static void brcm_pcie_reapply_inbound_access(struct brcm_pcie *pcie) +{ + void *base = pcie->base; + + if (!base || pcie->soc_data->type != BCM7712) + { + return; + } + + brcm_pcie_misc_ctrl_enable_access(pcie); + + /* + * MIP MSIX doorbell lands on inbound BAR3 (PCI ff_ffff_f000), not BAR2. + * Re-enable ACCESS on every active inbound UBUS remap after link events. + */ + for (int i = 1; i <= pcie->num_inbound_wins; ++i) + { + rt_uint32_t reg = brcm_ubus_reg_offset(i); + rt_uint32_t tmp; + + if (pcie->inbound_wins[i].size == 0) + { + continue; + } + + tmp = HWREG32(base + reg); + replace_u32_bitfield(&tmp, 1, + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK); + HWREG32(base + reg) = tmp; + } +} + +static void brcm_pcie_reapply_7712_maps(struct brcm_pcie *pcie) +{ + if (pcie->soc_data->type != BCM7712 || !pcie->num_inbound_wins) + { + return; + } + + brcm_pcie_reapply_inbound_access(pcie); + set_inbound_win_registers(pcie, pcie->inbound_wins, pcie->num_inbound_wins); + brcm_pcie_apply_outbound_wins(pcie); +} + +static rt_err_t brcm_pcie_setup(struct brcm_pcie *pcie) +{ + rt_err_t err; + void *base = pcie->base; + int num_out_wins = 0, num_inbound_wins = 0; + rt_uint32_t tmp, num_lanes = 0, num_lanes_cap = 0; + struct rt_pci_host_bridge *bridge = pcie->bridge; + struct inbound_win inbound_wins[PCIE_BRCM_MAX_INBOUND_WINS]; + + /* Reset the bridge */ + pcie->soc_data->bridge_sw_init_set(pcie, 1); + + /* Ensure that PERST# is asserted; some bootloaders may deassert it. */ + if (pcie->soc_data->type == BCM2711) + { + if ((err = pcie->soc_data->perst_set(pcie, 1))) + { + pcie->soc_data->bridge_sw_init_set(pcie, 0); + return err; + } + } + + rt_hw_us_delay(150); + + /* Take the bridge out of reset */ + if ((err = pcie->soc_data->bridge_sw_init_set(pcie, 0))) + { + return err; + } + + /* + * On some BCM2711 integrations this register window can raise SError + * immediately after bridge reset deassert; skip this write there. + */ + if (pcie->soc_data->type != BCM2711) + { + tmp = HWREG32(base + HARD_DEBUG(pcie)); + if (is_bmips(pcie)) + { + tmp &= ~PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; + } + else + { + tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; + } + HWREG32(base + HARD_DEBUG(pcie)) = tmp; + /* Wait for SerDes to be stable */ + rt_hw_us_delay(150); + } + + brcm_pcie_misc_ctrl_enable_access(pcie); + + num_inbound_wins = brcm_pcie_get_inbound_wins(pcie, inbound_wins); + if (num_inbound_wins < 0) + { + return num_inbound_wins; + } + + set_inbound_win_registers(pcie, inbound_wins, num_inbound_wins); + pcie->num_inbound_wins = (rt_uint8_t)num_inbound_wins; + rt_memcpy(pcie->inbound_wins, inbound_wins, sizeof(inbound_wins)); + + if (!brcm_pcie_rc_mode(pcie)) + { + LOG_E("PCIe RC controller misconfigured as Endpoint"); + return -RT_EINVAL; + } + + tmp = HWREG32(base + PCIE_MISC_MISC_CTRL); + + for (int memc = 0; memc < pcie->memc_nr; memc++) + { + rt_uint32_t scb_size_val = rt_ilog2(pcie->memc_size[memc]) - 15; + + if (memc == 0) + { + replace_u32_bitfield(&tmp, scb_size_val, SCB_SIZE_MASK(0)); + } + else if (memc == 1) + { + replace_u32_bitfield(&tmp, scb_size_val, SCB_SIZE_MASK(1)); + } + else if (memc == 2) + { + replace_u32_bitfield(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + } + } + + HWREG32(base + PCIE_MISC_MISC_CTRL) = tmp; + + /* + * We ideally want the MSI target address to be located in the 32bit + * addressable memory area. Some devices might depend on it. This is + * possible either when the inbound window is located above the lower + * 4GB or when the inbound area is smaller than 4GB (taking into + * account the rounding-up we're forced to perform). + */ + if (inbound_wins[2].pci_offset >= (4UL * SIZE_GB) || + (inbound_wins[2].size + inbound_wins[2].pci_offset) < (4UL * SIZE_GB)) + { + pcie->msi_data_address = BRCM_MSI_TARGET_ADDR_LT_4GB; + } + else + { + pcie->msi_data_address = BRCM_MSI_TARGET_ADDR_GT_4GB; + } + + /* Don't advertise L0s capability if 'aspm-no-l0s' */ + tmp = HWREG32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY); + if (rt_dm_dev_prop_read_bool(pcie->dev, "aspm-no-l0s")) + { + tmp &= ~PCI_EXP_LNKCAP_ASPM_L0S; + } + HWREG32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY) = tmp; + + num_lanes_cap = (tmp & PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK) >> 4; + + /* + * Use hardware negotiated Max Link Width value by default. If the + * "num-lanes" DT property is present, assume that the chip's default + * link width capability information is incorrect/undesired and use the + * specified value instead. + */ + if (!rt_dm_dev_prop_read_u32(pcie->dev, "num-lanes", &num_lanes) && + num_lanes && num_lanes <= 4 && num_lanes_cap != num_lanes) + { + replace_u32_bitfield(&tmp, num_lanes, + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK); + HWREG32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY) = tmp; + tmp = HWREG32(base + PCIE_RC_PL_REG_PHY_CTL_1); + replace_u32_bitfield(&tmp, 1, + PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK); + HWREG32(base + PCIE_RC_PL_REG_PHY_CTL_1) = tmp; + } + + /* + * For config space accesses on the RC, show the right class for + * a PCIe-PCIe bridge (the default setting is to be EP mode). + */ + tmp = HWREG32(base + PCIE_RC_CFG_PRIV1_ID_VAL3); + replace_u32_bitfield(&tmp, 0x060400, + PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK); + HWREG32(base + PCIE_RC_CFG_PRIV1_ID_VAL3) = tmp; + + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + struct rt_pci_bus_region *region = &bridge->bus_regions[i]; + + if (region->flags != PCI_BUS_REGION_F_MEM && + region->flags != PCI_BUS_REGION_F_PREFETCH) + { + continue; + } + + if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) + { + LOG_E("Too many outbound wins"); + return -RT_EINVAL; + } + + if (is_bmips(pcie)) + { + rt_uint64_t start = region->cpu_addr; + rt_off_t offset = region->cpu_addr - region->phy_addr; + rt_uint32_t nwins = region->size / 128 * SIZE_MB; + + /* BMIPS PCIe outbound windows have a 128MB max size */ + if (nwins > BRCM_NUM_PCIE_OUT_WINS) + { + nwins = BRCM_NUM_PCIE_OUT_WINS; + } + + for (int j = 0; j < nwins; ++j, start += 128 * SIZE_MB) + { + brcm_pcie_set_outbound_win(pcie, j, start, start - offset, 128 * SIZE_MB); + } + break; + } + + brcm_pcie_set_outbound_win(pcie, num_out_wins, + region->cpu_addr, region->phy_addr, region->size); + ++num_out_wins; + } + + /* PCIe->SCB endian mode for BAR */ + tmp = HWREG32(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); + replace_u32_bitfield(&tmp, PCIE_RC_CFG_VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN, + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); + HWREG32(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1) = tmp; + + if (pcie->soc_data->post_setup) + { + if ((err = pcie->soc_data->post_setup(pcie))) + { + return err; + } + } + + return RT_EOK; +} + +static void brcm_pcie_free(struct brcm_pcie *pcie) +{ + if (pcie->bridge) + { + rt_pci_host_bridge_remove(pcie->bridge); + } + + if (pcie->soc_data && pcie->soc_data->has_phy) + { + brcm_phy_stop(pcie); + } + + brcm_pcie_turn_off(pcie); + + if (!rt_is_err_or_null(pcie->rescal_rstc)) + { + rt_reset_control_assert(pcie->rescal_rstc); + rt_reset_control_put(pcie->rescal_rstc); + } + + if (!rt_is_err_or_null(pcie->perst_rstc)) + { + rt_reset_control_put(pcie->perst_rstc); + } + + if (!rt_is_err_or_null(pcie->bridge_rstc)) + { + rt_reset_control_put(pcie->bridge_rstc); + } + + if (!rt_is_err_or_null(pcie->swinit_rstc)) + { + rt_reset_control_put(pcie->swinit_rstc); + } + + if (!rt_is_err_or_null(pcie->clk)) + { + rt_clk_disable_unprepare(pcie->clk); + } + + if (pcie->base) + { + rt_iounmap(pcie->base); + } + + rt_pci_host_bridge_free(pcie->bridge); +} + +static rt_err_t brcm_pcie_get_optional_reset(struct rt_device *dev, const char *name, + struct rt_reset_control **rstc) +{ + struct rt_reset_control *rc = rt_reset_control_get_by_name(dev, name); + + if (rt_is_err(rc)) + { + if (rt_ptr_err(rc) == -RT_ENOENT) + { + *rstc = RT_NULL; + return RT_EOK; + } + + return rt_ptr_err(rc); + } + + *rstc = rc; + + return RT_EOK; +} + +static rt_err_t brcm_pcie_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct brcm_pcie *pcie; + struct rt_device *dev = &pdev->parent; + struct rt_pci_host_bridge *bridge; + struct rt_ofw_node *np = dev->ofw_node, *msi_np; + + bridge = rt_pci_host_bridge_alloc(sizeof(*pcie)); + + if (!bridge) + { + return -RT_ENOMEM; + } + + pcie = (void *)bridge->priv; + pcie->soc_data = pdev->id->data; + pcie->dev = dev; + pcie->bridge = bridge; + + pcie->base = rt_dm_dev_iomap(dev, 0); + + if (!pcie->base) + { + err = -RT_EIO; + goto _fail; + } + + pcie->clk = rt_clk_get_by_name(dev, "sw_pcie"); + + if (rt_is_err(pcie->clk)) + { + if (rt_ptr_err(pcie->clk) != -RT_ENOENT) + { + err = rt_ptr_err(pcie->clk); + goto _fail; + } + + pcie->clk = RT_NULL; + } + else if ((err = rt_clk_prepare_enable(pcie->clk))) + { + LOG_E("%s: could not enable clock", rt_dm_dev_get_name(dev)); + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "max-link-speed", &pcie->generation)) + { + pcie->generation = 0; + } + + pcie->ssc = rt_dm_dev_prop_read_bool(dev, "brcm,enable-ssc"); + rt_dm_dev_prop_read_u32(dev, "brcm,tperst-clk-ms", &pcie->tperst_clk_ms); + + if ((err = brcm_pcie_get_optional_reset(dev, "rescal", &pcie->rescal_rstc))) + { + goto _fail; + } + + if ((err = brcm_pcie_get_optional_reset(dev, "perst", &pcie->perst_rstc))) + { + goto _fail; + } + + if ((err = brcm_pcie_get_optional_reset(dev, "bridge", &pcie->bridge_rstc))) + { + goto _fail; + } + + if ((err = brcm_pcie_get_optional_reset(dev, "swinit", &pcie->swinit_rstc))) + { + goto _fail; + } + + pcie->soc_data->bridge_sw_init_set(pcie, 0); + + if (pcie->swinit_rstc) + { + if ((err = rt_reset_control_assert(pcie->swinit_rstc))) + { + goto _fail; + } + + rt_hw_us_delay(1); + + if ((err = rt_reset_control_deassert(pcie->swinit_rstc))) + { + goto _fail; + } + } + + if (pcie->rescal_rstc && + (err = rt_reset_control_reset(pcie->rescal_rstc))) + { + goto _fail; + } + + if ((err = brcm_phy_start(pcie))) + { + goto _fail; + } + + bridge->parent.ofw_node = np; + + if ((err = rt_pci_host_bridge_init(bridge))) + { + goto _fail; + } + + if ((err = brcm_pcie_setup(pcie))) + { + goto _fail; + } + + pcie->misc_revision = HWREG32(pcie->base + PCIE_MISC_REVISION); + + if (pcie->soc_data->type == BCM4908 && + pcie->misc_revision >= BRCM_PCIE_HW_REV_3_20) + { + LOG_E("%s: hardware revision with unsupported PERST# setup", + rt_dm_dev_get_name(dev)); + err = -RT_EINVAL; + goto _fail; + } + + msi_np = rt_ofw_parse_phandle(np, "msi-parent", 0); + + if (msi_np == np) + { + if ((err = brcm_pcie_enable_msi(pcie))) + { + LOG_E("%s: probe ofw internal MSI error = %s", + rt_dm_dev_get_name(dev), rt_strerror(err)); + + goto _fail; + } + } + + rt_ofw_node_put(msi_np); + + bridge->ops = pcie->soc_data->type == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops; + bridge->sysdata = pcie; + + if ((err = rt_pci_host_bridge_probe(bridge))) + { + goto _fail; + } + + if (!brcm_pcie_link_up(pcie)) + { + err = -RT_EINVAL; + goto _fail; + } + + brcm_pcie_reapply_7712_maps(pcie); + + dev->user_data = pcie; + + return RT_EOK; + +_fail: + if (pcie->msi) + { + rt_pic_cancel_irq(&pcie->msi->inner_pic); + } + + brcm_pcie_free(pcie); + + return err; +} + +static rt_err_t brcm_pcie_remove(struct rt_platform_device *pdev) +{ + struct brcm_pcie *pcie = pdev->parent.user_data; + + brcm_pcie_free(pcie); + + return RT_EOK; +} + +static const struct rt_ofw_node_id brcm_pcie_ofw_ids[] = +{ + { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, + { .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg }, + { .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg }, + { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, + { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, + { .compatible = "brcm,bcm7216-pcie", .data = &bcm7216_cfg }, + { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg }, + { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg }, + { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg }, + { .compatible = "brcm,bcm7712-pcie", .data = &bcm7712_cfg }, + { /* sentinel */ } +}; + +void brcm_pcie_reapply_maps(struct rt_pci_device *pdev) +{ + struct brcm_pcie *pcie; + struct rt_pci_host_bridge *host_bridge; + + if (!pdev || !pdev->bus) + { + return; + } + + if (!(host_bridge = rt_pci_find_host_bridge(pdev->bus))) + { + return; + } + + if ((pcie = host_bridge->sysdata)) + { + brcm_pcie_reapply_7712_maps(pcie); + } +} + +static struct rt_platform_driver brcm_pcie_driver = +{ + .name = "pcie-brcm", + .ids = brcm_pcie_ofw_ids, + + .probe = brcm_pcie_probe, + .remove = brcm_pcie_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(brcm_pcie_driver); diff --git a/bsp/raspberry-pi/dm/phy/Kconfig b/bsp/raspberry-pi/dm/phy/Kconfig new file mode 100755 index 0000000000..fc7d9d5e9c --- /dev/null +++ b/bsp/raspberry-pi/dm/phy/Kconfig @@ -0,0 +1,7 @@ +config RT_PHY_MDIO_BCM_UNIMAC + bool "Broadcom UniMAC MDIO bus controller (BCM2711 GENET)" + default n + +config RT_PHY_BCM54213 + bool "Broadcom BCM54213PE Ethernet PHY (Pi4/Pi5 RJ45)" + default n diff --git a/bsp/raspberry-pi/dm/phy/SConscript b/bsp/raspberry-pi/dm/phy/SConscript new file mode 100755 index 0000000000..a184e201fe --- /dev/null +++ b/bsp/raspberry-pi/dm/phy/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PHY_BCM54213']): + src += ['phy-bcm54213.c'] + +if GetDepend(['RT_PHY_MDIO_BCM_UNIMAC']): + src += ['mdio-bcm-unimac.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/phy/mdio-bcm-unimac.c b/bsp/raspberry-pi/dm/phy/mdio-bcm-unimac.c new file mode 100755 index 0000000000..3ad24f26dc --- /dev/null +++ b/bsp/raspberry-pi/dm/phy/mdio-bcm-unimac.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "phy.mdio.bcm-unimac" +#define DBG_LVL DBG_INFO +#include + +#define MDIO_CMD 0x00 +#define MDIO_START_BUSY (1 << 29) +#define MDIO_READ_FAIL (1 << 28) +#define MDIO_RD (2 << 26) +#define MDIO_WR (1 << 26) +#define MDIO_PMD_SHIFT 21 +#define MDIO_PMD_MASK 0x1f +#define MDIO_REG_SHIFT 16 +#define MDIO_REG_MASK 0x1f + +#define MDIO_CFG 0x04 +#define MDIO_C22 (1 << 0) +#define MDIO_C45 0 +#define MDIO_CLK_DIV_SHIFT 4 +#define MDIO_CLK_DIV_MASK 0x3f +#define MDIO_SUPP_PREAMBLE (1 << 12) + +struct unimac_mdio +{ + struct rt_device *dev; + struct mii_bus *mdio; + + void *base; + + rt_uint32_t clk_freq; + struct rt_clk *clk; +}; + +rt_inline void unimac_mdio_start(struct unimac_mdio *umdio) +{ + rt_uint32_t reg; + + reg = HWREG32(umdio->base + MDIO_CMD); + reg |= MDIO_START_BUSY; + HWREG32(umdio->base + MDIO_CMD) = reg; +} + +static rt_err_t unimac_mdio_poll(struct unimac_mdio *umdio) +{ + rt_uint32_t timeout = 1000; + + do { + if (!(HWREG32(umdio->base + MDIO_CMD) & MDIO_START_BUSY)) + { + return RT_EOK; + } + + rt_hw_us_delay(1500); + } while (--timeout); + + return -RT_ETIMEOUT; +} + +static int unimac_mdio_read(struct mii_bus *bus, int addr, int devad, int reg) +{ + int err; + rt_uint32_t cmd; + struct unimac_mdio *umdio = bus->priv; + + cmd = MDIO_RD | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); + HWREG32(umdio->base + MDIO_CMD) = cmd; + + unimac_mdio_start(umdio); + + if ((err = (int)unimac_mdio_poll(umdio))) + { + return err; + } + + cmd = HWREG32(umdio->base + MDIO_CMD); + + return cmd & 0xffff; +} + +static int unimac_mdio_write(struct mii_bus *bus, int addr, int devad, int reg, rt_uint16_t val) +{ + rt_uint32_t cmd; + struct unimac_mdio *umdio = bus->priv; + + cmd = MDIO_WR | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT) | (0xffff & val); + HWREG32(umdio->base + MDIO_CMD) = cmd; + + unimac_mdio_start(umdio); + + return (int)unimac_mdio_poll(umdio); +} + +static int unimac_mdio_reset(struct mii_bus *bus) +{ + rt_uint32_t read_mask = 0, addr; + struct unimac_mdio *umdio = bus->priv; + struct rt_ofw_node *np = umdio->dev->ofw_node, *child; + + if (!np) + { + read_mask = ~bus->phy_mask; + } + else + { + rt_ofw_foreach_available_child_node(np, child) + { + if (!rt_ofw_prop_read_u32(child, "reg", &addr) && addr < RT_PHY_MAX) + { + read_mask |= 1 << addr; + } + } + } + + for (addr = 0; addr < RT_PHY_MAX; ++addr) + { + if (read_mask & (1 << addr)) + { + unimac_mdio_read(bus, addr, 0, RT_MII_BMSR); + } + } + + return 0; +} + +#ifdef RT_USING_PM +static rt_err_t unimac_mdio_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + struct unimac_mdio *umdio = device->user_data; + + rt_clk_disable_unprepare(umdio->clk); + + return RT_EOK; +} + +static void unimac_mdio_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + struct unimac_mdio *umdio = device->user_data; + + rt_clk_prepare_enable(umdio->clk); +} + +static const struct rt_device_pm_ops unimac_mdio_pm_ops = +{ + .suspend = unimac_mdio_pm_suspend, + .resume = unimac_mdio_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t unimac_mdio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t base, size, mac_base; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *pnp; + struct unimac_mdio *umdio = rt_calloc(1, sizeof(*umdio)); + + if (!umdio) + { + return -RT_ENOMEM; + } + umdio->dev = dev; + + pnp = rt_ofw_get_parent(np); + rt_ofw_get_address(pnp, 0, &mac_base, RT_NULL); + rt_ofw_node_put(pnp); + rt_ofw_get_address(np, 0, &base, &size); + + umdio->base = rt_ioremap((void *)(mac_base + base), size); + + if (!umdio->base) + { + err = -RT_EIO; + goto _fail; + } + + umdio->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(umdio->clk)) + { + err = rt_ptr_err(umdio->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(umdio->clk))) + { + goto _fail; + } + + rt_dm_dev_prop_read_u32(dev, "clock-frequency", &umdio->clk_freq); + + if (umdio->clk_freq) + { + rt_uint32_t reg, div; + rt_ubase_t rate = 250000000; + + if (umdio->clk) + { + rate = rt_clk_get_rate(umdio->clk); + } + + div = (rate / (2 * umdio->clk_freq)) - 1; + + /* + * The MDIO clock is the reference clock (typically 250Mhz) divided by + * 2 x (MDIO_CLK_DIV + 1) + */ + reg = HWREG32(umdio->base + MDIO_CFG); + reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT); + reg |= div << MDIO_CLK_DIV_SHIFT; + HWREG32(umdio->base + MDIO_CFG) = reg; + } + + umdio->mdio = rt_mdio_alloc(); + + if (!umdio->mdio) + { + err = -RT_ENOMEM; + goto _free_clk; + } + + rt_sprintf(umdio->mdio->name, "unimac MII bus"); + umdio->mdio->priv = umdio; + umdio->mdio->read = unimac_mdio_read; + umdio->mdio->write = unimac_mdio_write; + umdio->mdio->reset = unimac_mdio_reset; + + dev->user_data = umdio; + + if ((err = rt_mdio_register(umdio->mdio))) + { + goto _free_clk; + } + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &unimac_mdio_pm_ops); +#endif + + return RT_EOK; + +_free_clk: + if (!rt_is_err_or_null(umdio->clk)) + { + rt_clk_disable_unprepare(umdio->clk); + } + +_fail: + if (umdio->base) + { + rt_iounmap(umdio->base); + } + + if (umdio->mdio) + { + rt_free(umdio->mdio); + } + + rt_free(umdio); + + return err; +} + +static rt_err_t unimac_mdio_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct unimac_mdio *umdio = dev->user_data; + +#ifdef RT_USING_PM + rt_pm_device_unregister(dev); +#endif + + rt_mdio_unregister(umdio->mdio); + + rt_clk_disable_unprepare(umdio->clk); + rt_clk_put(umdio->clk); + + rt_free(umdio->mdio); + rt_free(umdio); + + return RT_EOK; +} + +static const struct rt_ofw_node_id unimac_mdio_ofw_ids[] = +{ + { .compatible = "brcm,asp-v2.1-mdio", }, + { .compatible = "brcm,asp-v2.0-mdio", }, + { .compatible = "brcm,bcm6846-mdio", }, + { .compatible = "brcm,genet-mdio-v5", }, + { .compatible = "brcm,genet-mdio-v4", }, + { .compatible = "brcm,genet-mdio-v3", }, + { .compatible = "brcm,genet-mdio-v2", }, + { .compatible = "brcm,genet-mdio-v1", }, + { .compatible = "brcm,unimac-mdio", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver unimac_mdio_driver = +{ + .name = "unimac-mdio", + .ids = unimac_mdio_ofw_ids, + + .probe = unimac_mdio_probe, + .remove = unimac_mdio_remove, +}; + +static int unimac_mdio_drv_register(void) +{ + rt_platform_driver_register(&unimac_mdio_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(unimac_mdio_drv_register); diff --git a/bsp/raspberry-pi/dm/phy/phy-bcm54213.c b/bsp/raspberry-pi/dm/phy/phy-bcm54213.c new file mode 100644 index 0000000000..54f4e9f1ed --- /dev/null +++ b/bsp/raspberry-pi/dm/phy/phy-bcm54213.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-06-18 GuEe-GUI BCM54213PE PHY for BCM2711 GENET + */ + +#include +#include +#include +#include + +#define DBG_TAG "phy.bcm54213" +#define DBG_LVL DBG_INFO +#include + +/* BCM54213PE on Raspberry Pi 4 (BCM2711 GENET) */ +#define PHY_ID_BCM54213PE 0x600d84a2 + +#define MII_BCM54XX_AUX_CTL 0x18 +#define MII_BCM54XX_SHD 0x1c + +#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x07 +#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007 +#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12 +#define AUXCTL_MISC_RGMII_SKEW_EN (1 << 8) +#define AUXCTL_MISC_WREN (1 << 15) + +#define MII_BCM54XX_SHD_WRITE (1 << 15) +#define MII_BCM54XX_SHD_VAL(x) (((x) & 0x1f) << 10) +#define MII_BCM54XX_SHD_DATA(x) (((x) & 0x3ff) << 0) + +#define BCM54810_SHD_CLK_CTL 0x3 +#define CLK_CTL_GTXCLK_EN (1 << 9) + +static int bcm54xx_auxctl_read(struct rt_phy_device *phydev, rt_uint16_t regnum) +{ + rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_AUX_CTL, + MII_BCM54XX_AUXCTL_SHDWSEL_MASK | + (regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT)); + + return rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_AUX_CTL); +} + +static int bcm54xx_auxctl_write(struct rt_phy_device *phydev, rt_uint16_t regnum, rt_uint16_t val) +{ + return rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_AUX_CTL, regnum | val); +} + +static int bcm_phy_read_shadow(struct rt_phy_device *phydev, rt_uint16_t shadow) +{ + int val; + + rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); + val = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_SHD); + + return MII_BCM54XX_SHD_DATA(val); +} + +static int bcm_phy_write_shadow(struct rt_phy_device *phydev, rt_uint16_t shadow, rt_uint16_t val) +{ + return rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, MII_BCM54XX_SHD, + MII_BCM54XX_SHD_WRITE | MII_BCM54XX_SHD_VAL(shadow) | MII_BCM54XX_SHD_DATA(val)); +} + +static int bcm54xx_config_clock_delay(struct rt_phy_device *phydev) +{ + int val, err; + + val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); + if (val < 0) + { + return val; + } + + val |= AUXCTL_MISC_WREN; + + if (phydev->interface == RT_PHY_INTERFACE_MODE_RGMII || + phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_TXID) + { + val &= ~AUXCTL_MISC_RGMII_SKEW_EN; + } + else if (phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_RXID) + { + val |= AUXCTL_MISC_RGMII_SKEW_EN; + } + + err = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); + if (err < 0) + { + return err; + } + + val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); + if (val < 0) + { + return val; + } + + if (phydev->interface == RT_PHY_INTERFACE_MODE_RGMII || + phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_RXID) + { + val &= ~CLK_CTL_GTXCLK_EN; + } + else if (phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == RT_PHY_INTERFACE_MODE_RGMII_TXID) + { + val |= CLK_CTL_GTXCLK_EN; + } + + return bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); +} + +static int bcm54213pe_config(struct rt_phy_device *phydev) +{ + int err; + + err = bcm54xx_config_clock_delay(phydev); + if (err < 0) + { + return err; + } + + LOG_D("PHY config if=%d", phydev->interface); + + return rt_genphy_config(phydev); +} + +static int bcm54213pe_read_bmsr(struct rt_phy_device *phydev) +{ + int bmsr; + + /* BMSR link status is latch-low; read twice for current value */ + bmsr = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); + if (bmsr < 0) + { + return bmsr; + } + + return rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR); +} + +static int bcm54213pe_startup(struct rt_phy_device *phydev) +{ + int bmsr; + + /* + * Non-blocking startup: do not wait for autoneg in init context. + * Link-up / retry is handled by GENET link IRQ work and periodic poll. + */ + bmsr = bcm54213pe_read_bmsr(phydev); + if (bmsr < 0) + { + return bmsr; + } + + if (bmsr & RT_BMSR_LSTATUS) + { + phydev->link = 1; + rt_genphy_parse_link(phydev); + LOG_I("PHY up: speed=%d duplex=%d", phydev->speed, phydev->duplex); + return 0; + } + + phydev->link = 0; + LOG_I("PHY link down at boot, defer to link event / retry work"); + return 0; +} + +static struct rt_phy_driver bcm54213pe_driver = +{ + .uid = PHY_ID_BCM54213PE, + .mask = 0xffffffff, + .name = "Broadcom BCM54213PE", + .features = RT_PHY_GBIT_FEATURES, + .config = bcm54213pe_config, + .startup = bcm54213pe_startup, +}; + +static int bcm54213_phy_drv_register(void) +{ + rt_phy_driver_register(&bcm54213pe_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(bcm54213_phy_drv_register); diff --git a/bsp/raspberry-pi/dm/pic/Kconfig b/bsp/raspberry-pi/dm/pic/Kconfig new file mode 100755 index 0000000000..0d2112aa9c --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/Kconfig @@ -0,0 +1,19 @@ +config RT_PIC_BCM2712_MIP + bool "Broadcom 2712 MSI-X Interrupt Peripheral support" if RT_PCI_MSI + depends on RT_USING_OFW + default n + +config RT_PIC_BCM2835_INTC + bool "BCM2835 intc" + depends on RT_USING_OFW + default n + +config RT_PIC_BCM2836_L1_INTC + bool "BCM2836 L1 intc" + depends on RT_USING_OFW + default n + +config RT_PIC_BRCMSTB_L2_IRQ + bool "BRCMSTB L2 IRQ" + depends on RT_USING_OFW + default n diff --git a/bsp/raspberry-pi/dm/pic/SConscript b/bsp/raspberry-pi/dm/pic/SConscript new file mode 100755 index 0000000000..ab14380a57 --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/SConscript @@ -0,0 +1,22 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PIC_BCM2712_MIP']): + src += ['pic-bcm2712-mip.c'] + +if GetDepend(['RT_PIC_BCM2835_INTC']): + src += ['pic-bcm2835.c'] + +if GetDepend(['RT_PIC_BCM2836_L1_INTC']): + src += ['pic-bcm2836.c'] + +if GetDepend(['RT_PIC_BRCMSTB_L2_IRQ']): + src += ['pic-brcmstb-l2.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pic/pic-bcm2712-mip.c b/bsp/raspberry-pi/dm/pic/pic-bcm2712-mip.c new file mode 100755 index 0000000000..52b484a52a --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/pic-bcm2712-mip.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + * 2025-06-19 GuEe-GUI support upstream brcm,bcm2712-mip DT format + */ + +#include +#include +#include + +#define DBG_TAG "pic.mip-msi" +#define DBG_LVL DBG_INFO +#include + +#define MIP_INT_RAISE 0x00 +#define MIP_INT_CLEARE 0x10 +#define MIP_INT_CFGL_HOST 0x20 +#define MIP_INT_CFGH_HOST 0x30 +#define MIP_INT_MASKL_HOST 0x40 +#define MIP_INT_MASKH_HOST 0x50 +#define MIP_INT_MASKL_VPU 0x60 +#define MIP_INT_MASKH_VPU 0x70 +#define MIP_INT_STATUSL_HOST 0x80 +#define MIP_INT_STATUSH_HOST 0x90 +#define MIP_INT_STATUSL_VPU 0xa0 +#define MIP_INT_STATUSH_VPU 0xb0 + +struct mip_msi +{ + struct rt_pic parent; + struct rt_pic *ppic; + struct rt_ofw_node *pic_np; + + void *base; + rt_ubase_t msg_addr; + rt_uint32_t msi_base; /* The SGI/SPI number that MSIs start */ + rt_uint32_t spi_base; /* msi_base + 32, GIC INTID for MIP hwirq 0 */ + rt_uint32_t num_msis; /* The number of SGIs for MSIs */ + rt_uint32_t msi_offset; /* Shift the allocated msi up by N */ + rt_ubase_t *msi_map; + + struct rt_spinlock msi_map_lock; +}; + +#define raw_to_mip_msi(raw) rt_container_of(raw, struct mip_msi, parent) + +static rt_err_t mip_msi_parse_pci_addr(struct rt_ofw_node *np, rt_uint64_t *addr) +{ + int nr; + rt_uint32_t cells[2]; + + nr = rt_ofw_prop_read_u32_array_index(np, "brcm,msi-pci-addr", 0, 2, cells); + + if (nr < 2) + { + LOG_E("brcm,msi-pci-addr needs two u32 cells, got %d", nr); + return -RT_EINVAL; + } + + *addr = ((rt_uint64_t)cells[0] << 32) | cells[1]; + + if (rt_upper_32_bits(*addr) != 0xffU) + { + LOG_E("brcm,msi-pci-addr hi=%#x lo=%#x (expected hi=0xff)", + rt_upper_32_bits(*addr), rt_lower_32_bits(*addr)); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t mip_msi_parse_intc_dt(struct mip_msi *mip, struct rt_ofw_node *np) +{ + mip->pic_np = rt_ofw_find_irq_parent(np, RT_NULL); + if (!mip->pic_np) + { + LOG_E("Unable to find PIC parent"); + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "brcm,msi-base-spi", &mip->msi_base)) + { + LOG_E("Unable to parse MSI base"); + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "brcm,msi-num-spis", &mip->num_msis)) + { + LOG_E("Unable to parse MSI numbers"); + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "brcm,msi-offset", &mip->msi_offset)) + { + mip->msi_offset = 0; + } + + if (mip_msi_parse_pci_addr(np, &mip->msg_addr)) + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t mip_msi_parse_upstream_dt(struct mip_msi *mip, struct rt_ofw_node *np) +{ + rt_err_t err; + rt_uint64_t size; + struct rt_ofw_cell_args args; + + if (rt_ofw_prop_read_u32(np, "brcm,msi-offset", &mip->msi_offset)) + { + mip->msi_offset = 0; + } + + err = rt_ofw_parse_phandle_cells(np, "msi-ranges", "#interrupt-cells", 0, &args); + if (err) + { + LOG_E("Unable to parse msi-ranges"); + return err; + } + + mip->pic_np = args.data; + if (!mip->pic_np) + { + LOG_E("Unable to find MSI parent from msi-ranges"); + return -RT_EINVAL; + } + + if (args.args_count < 2) + { + LOG_E("Invalid msi-ranges interrupt specifier"); + return -RT_EINVAL; + } + + mip->msi_base = args.args[1]; + + if (rt_ofw_prop_read_u32_index(np, "msi-ranges", args.args_count + 1, &mip->num_msis)) + { + LOG_E("Unable to parse MSI count from msi-ranges"); + return -RT_EINVAL; + } + + if (rt_ofw_get_address(np, 1, &mip->msg_addr, &size)) + { + LOG_E("Unable to parse MSI doorbell address"); + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t mip_msi_irq_init(struct rt_pic *pic) +{ + struct mip_msi *mip = raw_to_mip_msi(pic); + + mip->ppic = rt_ofw_data(mip->pic_np); + + return mip->ppic ? RT_EOK : -RT_ENOSYS; +} + +static int mip_msi_parent_hwirq(struct mip_msi *mip, int hwirq) +{ + return hwirq + mip->spi_base; +} + +static rt_err_t mip_msi_link_parent(struct mip_msi *mip, struct rt_pic_irq *pirq) +{ + rt_err_t err; + int parent_irq; + + if (!mip || !pirq || !mip->ppic) + { + return -RT_EINVAL; + } + + if (pirq->parent) + { + return RT_EOK; + } + + parent_irq = mip->ppic->ops->irq_map(mip->ppic, + mip_msi_parent_hwirq(mip, pirq->hwirq), RT_IRQ_MODE_EDGE_RISING); + if (parent_irq < 0) + { + return parent_irq; + } + + err = rt_pic_cascade(pirq, parent_irq); + if (err) + { + LOG_E("MIP cascade virq=%d parent_irq=%d err=%d", pirq->irq, parent_irq, err); + } + + return err; +} + +static void mip_msi_irq_mask(struct rt_pic_irq *pirq) +{ + rt_pci_msi_mask_irq(pirq); + rt_pic_irq_parent_mask(pirq); +} + +static void mip_msi_irq_unmask(struct rt_pic_irq *pirq) +{ + struct mip_msi *mip = raw_to_mip_msi(pirq->pic); + + mip_msi_link_parent(mip, pirq); + rt_pci_msi_unmask_irq(pirq); + rt_pic_irq_parent_unmask(pirq); +} + +static void mip_msi_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) +{ + struct mip_msi *mip = raw_to_mip_msi(pirq->pic); + + msg->address_hi = rt_upper_32_bits(mip->msg_addr); + msg->address_lo = rt_lower_32_bits(mip->msg_addr); + msg->data = pirq->hwirq; +} + +static int mip_msi_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) +{ + rt_ubase_t level; + rt_err_t err; + int irq, hwirq, hwirq_index; + struct rt_pic_irq *pirq; + struct mip_msi *mip = raw_to_mip_msi(pic); + + RT_UNUSED(msi_desc); + + if (!mip->ppic) + { + LOG_E("MIP parent PIC not ready"); + return -RT_ENOSYS; + } + + level = rt_spin_lock_irqsave(&mip->msi_map_lock); + hwirq_index = rt_bitmap_next_clear_bit(mip->msi_map, 0, mip->num_msis); + + if (hwirq_index >= mip->num_msis) + { + irq = -RT_EEMPTY; + goto _out_lock; + } + + hwirq = hwirq_index + mip->msi_offset; + + irq = rt_pic_config_irq(pic, hwirq_index, hwirq); + if (irq < 0) + { + goto _out_lock; + } + pirq = rt_pic_find_irq(pic, hwirq_index); + + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + err = mip_msi_link_parent(mip, pirq); + if (err) + { + irq = err; + goto _out_lock; + } + + rt_bitmap_set_bit(mip->msi_map, hwirq_index); + +_out_lock: + rt_spin_unlock_irqrestore(&mip->msi_map_lock, level); + + return irq; +} + +static void mip_msi_irq_free_msi(struct rt_pic *pic, int irq) +{ + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct mip_msi *mip = raw_to_mip_msi(pic); + + pirq = rt_pic_find_pirq(pic, irq); + + if (!pirq) + { + return; + } + + rt_hw_interrupt_mask(irq); + rt_pic_uncascade(pirq); + + level = rt_spin_lock_irqsave(&mip->msi_map_lock); + rt_bitmap_clear_bit(mip->msi_map, pirq->hwirq - mip->msi_offset); + rt_spin_unlock_irqrestore(&mip->msi_map_lock, level); +} + +static rt_err_t mip_msi_irq_set_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t state) +{ + struct mip_msi *mip = raw_to_mip_msi(pic); + struct rt_pic *ppic = mip->ppic; + + if (ppic->ops->irq_set_state) + { + return ppic->ops->irq_set_state(ppic, mip_msi_parent_hwirq(mip, hwirq), + type, state); + } + + return -RT_ENOSYS; +} + +static rt_err_t mip_msi_irq_get_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state) +{ + struct mip_msi *mip = raw_to_mip_msi(pic); + struct rt_pic *ppic = mip->ppic; + + if (ppic->ops->irq_get_state) + { + return ppic->ops->irq_get_state(ppic, mip_msi_parent_hwirq(mip, hwirq), + type, out_state); + } + + return -RT_ENOSYS; +} + +const static struct rt_pic_ops mip_msi_ops = +{ + .name = "MIP-MSI", + .irq_init = mip_msi_irq_init, + .irq_mask = mip_msi_irq_mask, + .irq_unmask = mip_msi_irq_unmask, + /* irq_eoi omitted: GIC root handler performs a single EOI. */ + .irq_set_affinity = rt_pic_irq_parent_set_affinity, + .irq_set_triger_mode = rt_pic_irq_parent_set_triger_mode, + .irq_compose_msi_msg = mip_msi_compose_msi_msg, + .irq_alloc_msi = mip_msi_irq_alloc_msi, + .irq_free_msi = mip_msi_irq_free_msi, + .irq_set_state = mip_msi_irq_set_state, + .irq_get_state = mip_msi_irq_get_state, + .flags = RT_PIC_F_IRQ_ROUTING, +}; + +static rt_err_t mip_msi_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) +{ + rt_err_t err; + struct mip_msi *mip = rt_calloc(1, sizeof(*mip)); + + if (!mip) + { + return -RT_ENOMEM; + } + + if (!rt_strcmp(id->compatible, "brcm,bcm2712-mip-intc")) + { + err = mip_msi_parse_intc_dt(mip, np); + } + else + { + err = mip_msi_parse_upstream_dt(mip, np); + } + + if (err) + { + goto _fail; + } + + /* SPI offset from MSI base */ + mip->spi_base = mip->msi_base + 32; + + mip->base = rt_ofw_iomap(np, 0); + + if (!mip->base) + { + err = -RT_EIO; + goto _fail; + } + + mip->msi_map = rt_calloc(RT_BITS_TO_LONGS(mip->num_msis), sizeof(*mip->msi_map)); + + if (!mip->msi_map) + { + err = -RT_ENOMEM; + goto _fail; + } + + /* + * Begin with all MSI-Xs masked in for the host, masked out for the VPU, + * and edge-triggered. + */ + HWREG32(mip->base + MIP_INT_MASKL_HOST) = 0; + HWREG32(mip->base + MIP_INT_MASKH_HOST) = 0; + HWREG32(mip->base + MIP_INT_MASKL_VPU) = ~0; + HWREG32(mip->base + MIP_INT_MASKH_VPU) = ~0; + HWREG32(mip->base + MIP_INT_CFGL_HOST) = ~0; + HWREG32(mip->base + MIP_INT_CFGH_HOST) = ~0; + + LOG_D("Found %d MSIx, starting at %d (offset %d)", mip->num_msis, mip->msi_base, mip->msi_offset); + + rt_spin_lock_init(&mip->msi_map_lock); + + mip->parent.priv_data = mip; + mip->parent.ops = &mip_msi_ops; + + rt_pic_linear_irq(&mip->parent, mip->num_msis); + rt_pic_user_extends(&mip->parent); + + rt_ofw_data(np) = &mip->parent; + rt_ofw_node_set_flag(np, RT_OFW_F_READLY); + + return RT_EOK; + +_fail: + if (mip->base) + { + rt_iounmap(mip->base); + } + + if (mip->msi_map) + { + rt_free(mip->msi_map); + } + + rt_free(mip); + + return err; +} + +static const struct rt_ofw_node_id mip_msi_ofw_ids[] = +{ + { .compatible = "brcm,bcm2712-mip-intc" }, + { .compatible = "brcm,bcm2712-mip" }, + { /* sentinel */ } +}; +RT_PIC_OFW_DECLARE(mip_msi, mip_msi_ofw_ids, mip_msi_ofw_init); diff --git a/bsp/raspberry-pi/dm/pic/pic-bcm2835.c b/bsp/raspberry-pi/dm/pic/pic-bcm2835.c new file mode 100755 index 0000000000..2851b4ea04 --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/pic-bcm2835.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-12 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pic.bcm2835" +#define DBG_LVL DBG_INFO +#include + +/* Put the bank and irq (32 bits) into the hwirq */ +#define MAKE_HWIRQ(b, n) ((b << 5) | (n)) +#define HWIRQ_BANK(i) (i >> 5) +#define HWIRQ_BIT(i) RT_BIT(i & 0x1f) + +#define NR_IRQS_BANK0 8 +#define BANK0_HWIRQ_MASK 0xff +/* Shortcuts can't be disabled so any unknown new ones need to be masked */ +#define SHORTCUT1_MASK 0x00007c00 +#define SHORTCUT2_MASK 0x001f8000 +#define SHORTCUT_SHIFT 10 +#define BANK1_HWIRQ RT_BIT(8) +#define BANK2_HWIRQ RT_BIT(9) +#define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ | SHORTCUT1_MASK | SHORTCUT2_MASK) + +#define REG_FIQ_CONTROL 0x0c +#define FIQ_CONTROL_ENABLE RT_BIT(7) + +#define NR_BANKS 3 +#define IRQS_PER_BANK 32 + +struct bcm2835_arm_intc +{ + struct rt_pic parent; + + void *base; + void *pending[NR_BANKS]; + void *enable[NR_BANKS]; + void *disable[NR_BANKS]; +}; + +static struct bcm2835_arm_intc intc; + +static const int shortcuts[] = +{ + 7, 9, 10, 18, 19, /* Bank 1 */ + 21, 22, 23, 24, 25, 30 /* Bank 2 */ +}; + +/* + * Handle each interrupt across the entire interrupt controller. This reads the + * status register before handling each interrupt, which is necessary given that + * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. + */ + +static rt_uint32_t bcm2835_arm_intc_translate_bank(int bank) +{ + rt_uint32_t status = HWREG32(intc.pending[bank]); + + return MAKE_HWIRQ(bank, __rt_ffs(status) - 1); +} + +static rt_uint32_t bcm2835_arm_intc_translate_shortcut(int bank, rt_uint32_t status) +{ + return MAKE_HWIRQ(bank, shortcuts[__rt_ffs(status >> SHORTCUT_SHIFT) - 1]); +} + +static rt_uint32_t bcm2835_arm_intc_get_next_armctrl_hwirq(void) +{ + rt_uint32_t ret; + rt_uint32_t status = HWREG32(intc.pending[0]) & BANK0_VALID_MASK; + + if (status == 0) + { + ret = ~0; + } + else if (status & BANK0_HWIRQ_MASK) + { + ret = MAKE_HWIRQ(0, __rt_ffs(status & BANK0_HWIRQ_MASK) - 1); + } + else if (status & SHORTCUT1_MASK) + { + ret = bcm2835_arm_intc_translate_shortcut(1, status & SHORTCUT1_MASK); + } + else if (status & SHORTCUT2_MASK) + { + ret = bcm2835_arm_intc_translate_shortcut(2, status & SHORTCUT2_MASK); + } + else if (status & BANK1_HWIRQ) + { + ret = bcm2835_arm_intc_translate_bank(1); + } + else if (status & BANK2_HWIRQ) + { + ret = bcm2835_arm_intc_translate_bank(2); + } + else + { + LOG_E("IRQ status panic = %d", status); + RT_ASSERT(0); + } + + return ret; +} + +static void bcm2835_arm_intc_mask_irq(struct rt_pic_irq *pirq) +{ + int hwirq = pirq->hwirq; + + HWREG32(intc.disable[HWIRQ_BANK(hwirq)]) = HWIRQ_BIT(hwirq); +} + +static void bcm2835_arm_intc_unmask_irq(struct rt_pic_irq *pirq) +{ + int hwirq = pirq->hwirq; + + HWREG32(intc.enable[HWIRQ_BANK(hwirq)]) = HWIRQ_BIT(hwirq); +} + +static int bcm2835_arm_intc_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + pirq->mode = mode; + RT_IRQ_AFFINITY_SET(pirq->affinity, rt_hw_cpu_id()); + + return rt_pic_config_irq(pic, hwirq, hwirq); +} + +static rt_err_t bcm2835_arm_intc_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + + if (args->args_count == 2 && + args->args[0] < NR_BANKS && + args->args[1] < IRQS_PER_BANK && + (args->args[0] != 0 || args->args[1])) + { + out_pirq->hwirq = MAKE_HWIRQ(args->args[0], args->args[1]); + out_pirq->mode = RT_IRQ_MODE_EDGE_RISING; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +const static struct rt_pic_ops bcm2835_arm_intc_ops = +{ + .name = "BCM2835-ARMCTRL-level", + .irq_mask = bcm2835_arm_intc_mask_irq, + .irq_unmask = bcm2835_arm_intc_unmask_irq, + .irq_map = bcm2835_arm_intc_irq_map, + .irq_parse = bcm2835_arm_intc_irq_parse, +}; + +static rt_bool_t bcm2835_arm_intc_handler(void *data) +{ + rt_uint32_t hwirq; + rt_bool_t res = RT_FALSE; + + while ((hwirq = bcm2835_arm_intc_get_next_armctrl_hwirq()) != ~0) + { + struct rt_pic_irq *pirq = rt_pic_find_irq(&intc.parent, hwirq); + + rt_pic_handle_isr(pirq); + + res = RT_TRUE; + } + + return res; +} + +static rt_err_t bcm2835_arm_ofw_intc(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) +{ + rt_err_t err = RT_EOK; + + intc.base = rt_ofw_iomap(np, 0); + + if (intc.base) + { + rt_uint32_t reg; + + int reg_pending[] = { 0x00, 0x04, 0x08 }; + int reg_enable[] = { 0x18, 0x10, 0x14 }; + int reg_disable[] = { 0x24, 0x1c, 0x20 }; + + for (int i = 0; i < NR_BANKS; ++i) + { + intc.pending[i] = intc.base + reg_pending[i]; + intc.enable[i] = intc.base + reg_enable[i]; + intc.disable[i] = intc.base + reg_disable[i]; + + reg = HWREG32(intc.enable[i]); + + if (reg) + { + HWREG32(intc.disable[i]) = reg; + + LOG_E("Bootloader left irq enabled: bank = %d irq-bitmask = %08x", i, reg); + } + } + + reg = HWREG32(intc.base + REG_FIQ_CONTROL); + + if (reg & FIQ_CONTROL_ENABLE) + { + HWREG32(intc.base + REG_FIQ_CONTROL) = 0; + + LOG_E("Bootloader left fiq enabled"); + } + + intc.parent.priv_data = &intc; + intc.parent.ops = &bcm2835_arm_intc_ops; + + rt_ofw_data(np) = &intc.parent; + + rt_pic_linear_irq(&intc.parent, MAKE_HWIRQ(NR_BANKS, 0)); + + rt_pic_add_traps(bcm2835_arm_intc_handler, &intc); + } + else + { + err = -RT_ERROR; + } + + return err; +} + +static const struct rt_ofw_node_id bcm2835_arm_intc_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-armctrl-ic", }, + { .compatible = "brcm,bcm2836-armctrl-ic", }, + { /* sentinel */ } +}; +RT_PIC_OFW_DECLARE(bcm2835_arm_intc, bcm2835_arm_intc_ofw_ids, bcm2835_arm_ofw_intc); diff --git a/bsp/raspberry-pi/dm/pic/pic-bcm2836.c b/bsp/raspberry-pi/dm/pic/pic-bcm2836.c new file mode 100755 index 0000000000..d952076f23 --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/pic-bcm2836.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pic.bcm2836" +#define DBG_LVL DBG_INFO +#include + +#include + +#define LOCAL_CONTROL 0x00 +#define LOCAL_PRESCALER 0x08 + +/* + * The low 2 bits identify the CPU that the GPU IRQ goes to, and the next 2 bits + * identify the CPU that the GPU FIQ goes to. + */ +#define LOCAL_GPU_ROUTING 0x0c +/* When setting bits 0-3, enables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_SET 0x10 +/* When setting bits 0-3, disables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_CLR 0x14 +/* + * The low 4 bits of this are the CPU's timer IRQ enables, and the next 4 bits + * are the CPU's timer FIQ enables (which override the IRQ bits). + */ +#define LOCAL_TIMER_INT_CONTROL0 0x40 +/* + * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and the next 4 + * bits are the CPU's per-mailbox FIQ enables (which override the IRQ bits). + */ +#define LOCAL_MAILBOX_INT_CONTROL0 0x50 +/* + * The CPU's interrupt status register. Bits are defined by the LOCAL_IRQ_* bits + * below. + */ +#define LOCAL_IRQ_PENDING0 0x60 +/* Same status bits as above, but for FIQ. */ +#define LOCAL_FIQ_PENDING0 0x70 +/* + * Mailbox write-to-set bits. There are 16 mailboxes, 4 per CPU, and these bits + * are organized by mailbox number and then CPU number. We use mailbox 0 for + * IPIs. The mailbox's interrupt is raised while any bit is set. + */ +#define LOCAL_MAILBOX0_SET0 0x80 +#define LOCAL_MAILBOX3_SET0 0x8c +/* Mailbox write-to-clear bits. */ +#define LOCAL_MAILBOX0_CLR0 0xc0 +#define LOCAL_MAILBOX3_CLR0 0xcc + +#define LOCAL_IRQ_CNTPSIRQ 0 +#define LOCAL_IRQ_CNTPNSIRQ 1 +#define LOCAL_IRQ_CNTHPIRQ 2 +#define LOCAL_IRQ_CNTVIRQ 3 +#define LOCAL_IRQ_MAILBOX0 4 +#define LOCAL_IRQ_MAILBOX1 5 +#define LOCAL_IRQ_MAILBOX2 6 +#define LOCAL_IRQ_MAILBOX3 7 +#define LOCAL_IRQ_GPU_FAST 8 +#define LOCAL_IRQ_PMU_FAST 9 +#define LAST_IRQ LOCAL_IRQ_PMU_FAST + +struct bcm2836_arm_intc +{ + struct rt_pic parent; + + void *base; +}; + +static struct bcm2836_arm_intc intc; + +static void bcm2836_arm_irqchip_mask_ipi(rt_uint32_t reg_offset, rt_uint32_t bit, int cpu) +{ + void *reg = intc.base + reg_offset + 4 * cpu; + + HWREG32(reg) &= ~RT_BIT(bit); +} + +static void bcm2836_arm_irqchip_unmask_ipi(rt_uint32_t reg_offset, rt_uint32_t bit, int cpu) +{ + void *reg = intc.base + reg_offset + 4 * cpu; + + HWREG32(reg) |= RT_BIT(bit); +} + +static void bcm2836_arm_irqchip_mask_timer_irq(int hwirq) +{ + bcm2836_arm_irqchip_mask_ipi(LOCAL_TIMER_INT_CONTROL0, hwirq - LOCAL_IRQ_CNTPSIRQ, rt_hw_cpu_id()); +} + +static void bcm2836_arm_irqchip_unmask_timer_irq(int hwirq) +{ + bcm2836_arm_irqchip_unmask_ipi(LOCAL_TIMER_INT_CONTROL0, hwirq - LOCAL_IRQ_CNTPSIRQ, rt_hw_cpu_id()); +} + +static void bcm2836_arm_irqchip_mask_gpu_irq(void) +{ +} + +static void bcm2836_arm_irqchip_unmask_gpu_irq(void) +{ +} + +static void bcm2836_arm_irqchip_mask_pmu_irq(void) +{ + HWREG32(intc.base + LOCAL_PM_ROUTING_CLR) = 1 << rt_hw_cpu_id(); +} + +static void bcm2836_arm_irqchip_unmask_pmu_irq(void) +{ + HWREG32(intc.base + LOCAL_PM_ROUTING_SET) = 1 << rt_hw_cpu_id(); +} + +static void bcm2836_arm_irqchip_irq_ops(int hwirq, rt_bool_t mask) +{ +#define CALL_OPS(name, ...) \ + if (mask) { \ + bcm2836_arm_irqchip_mask_##name(__VA_ARGS__); \ + } else { \ + bcm2836_arm_irqchip_unmask_##name(__VA_ARGS__); \ + } + + switch (hwirq) + { + case LOCAL_IRQ_MAILBOX0: + case LOCAL_IRQ_MAILBOX1: + case LOCAL_IRQ_MAILBOX2: + case LOCAL_IRQ_MAILBOX3: + CALL_OPS(ipi, LOCAL_MAILBOX_INT_CONTROL0, 0, rt_hw_cpu_id()); + break; + case LOCAL_IRQ_CNTPSIRQ: + case LOCAL_IRQ_CNTPNSIRQ: + case LOCAL_IRQ_CNTHPIRQ: + case LOCAL_IRQ_CNTVIRQ: + CALL_OPS(timer_irq, hwirq); + break; + case LOCAL_IRQ_GPU_FAST: + CALL_OPS(gpu_irq); + break; + case LOCAL_IRQ_PMU_FAST: + CALL_OPS(pmu_irq); + break; + default: + LOG_W("Unexpected hwirq = %d", hwirq); + break; + } +#undef CALL_OPS +} + +static void bcm2836_arm_l1_intc_irq_mask(struct rt_pic_irq *pirq) +{ + bcm2836_arm_irqchip_irq_ops(pirq->hwirq, RT_TRUE); +} + +static void bcm2836_arm_l1_intc_irq_unmask(struct rt_pic_irq *pirq) +{ + bcm2836_arm_irqchip_irq_ops(pirq->hwirq, RT_FALSE); +} + +static void bcm2836_arm_l1_intc_irq_send_ipi(struct rt_pic_irq *pirq, rt_bitmap_t *cpumask) +{ + int cpu, hwirq = pirq->hwirq; + void *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; + + /* + * Ensure that stores to normal memory are visible to the other CPUs before + * issuing the IPI. + */ + rt_hw_wmb(); + + rt_bitmap_for_each_set_bit(cpumask, cpu, RT_CPUS_NR) + { + HWREG32(mailbox0_base + 16 * cpu) = RT_BIT(hwirq); + } +} + +static int bcm2836_arm_l1_intc_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + pirq->mode = mode; + + switch (hwirq) + { + case LOCAL_IRQ_CNTPSIRQ: + case LOCAL_IRQ_CNTPNSIRQ: + case LOCAL_IRQ_CNTHPIRQ: + case LOCAL_IRQ_CNTVIRQ: + for (int cpuid = 0; cpuid < RT_CPUS_NR; ++cpuid) + { + RT_IRQ_AFFINITY_SET(pirq->affinity, cpuid); + } + break; + + default: + RT_IRQ_AFFINITY_SET(pirq->affinity, rt_hw_cpu_id()); + break; + } + + return rt_pic_config_irq(pic, hwirq, hwirq); +} + +static rt_err_t bcm2836_arm_l1_intc_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + + if (args->args_count == 2) + { + out_pirq->hwirq = args->args[0]; + out_pirq->mode = args->args[1]; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +const static struct rt_pic_ops bcm2836_arm_l1_intc_ops = +{ + .name = "BCM2836-ARM-L1-INTC", + .irq_mask = bcm2836_arm_l1_intc_irq_mask, + .irq_unmask = bcm2836_arm_l1_intc_irq_unmask, + .irq_send_ipi = bcm2836_arm_l1_intc_irq_send_ipi, + .irq_map = bcm2836_arm_l1_intc_irq_map, + .irq_parse = bcm2836_arm_l1_intc_irq_parse, +}; + +static rt_bool_t bcm2836_arm_l1_intc_handler(void *data) +{ + rt_uint32_t hwirq; + rt_bool_t res = RT_FALSE; + int cpu_id = rt_hw_cpu_id(); + rt_uint32_t status = HWREG32(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu_id); + + if (!status) + { + status = HWREG32(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu_id); + } + + if (status) + { + struct rt_pic_irq *pirq; + + hwirq = __rt_ffs(status) - 1; + + if (hwirq > LOCAL_IRQ_MAILBOX3 || hwirq < LOCAL_IRQ_MAILBOX0) + { + pirq = rt_pic_find_irq(&intc.parent, hwirq); + } + else + { + HWREG32(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * rt_hw_cpu_id()) = RT_BIT(hwirq); + + pirq = rt_pic_find_ipi(&intc.parent, hwirq - LOCAL_IRQ_MAILBOX0); + } + + rt_pic_handle_isr(pirq); + + res = RT_TRUE; + } + + return res; +} + +/* + * The LOCAL_IRQ_CNT* timer firings are based off of the external oscillator + * with some scaling. The firmware sets up CNTFRQ to report 19.2Mhz, but + * doesn't set up the scaling registers. + */ +static void bcm2835_init_local_timer_frequency(void) +{ + /* + * Set the timer to source from the 19.2Mhz crystal clock (bit 8 unset), and + * only increment by 1 instead of 2 (bit 9 unset). + */ + HWREG32(intc.base + LOCAL_CONTROL) = 0; + + /* Set the timer prescaler to 1:1 (timer freq = input freq * 2**31 / prescaler) */ + HWREG32(intc.base + LOCAL_PRESCALER) = 0x80000000; +} + +static rt_err_t bcm2836_arm_l1_intc_init(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) +{ + rt_err_t err = RT_EOK; + + intc.base = rt_ofw_iomap(np, 0); + + if (intc.base) + { + bcm2835_init_local_timer_frequency(); + + intc.parent.priv_data = &intc; + intc.parent.ops = &bcm2836_arm_l1_intc_ops; + rt_ofw_data(np) = &intc.parent; + + rt_pic_linear_irq(&intc.parent, LAST_IRQ + 1); + + for (int ipi = 0; ipi < RT_MAX_IPI; ++ipi) + { + struct rt_pic_irq *pirq; + + if (LOCAL_IRQ_MAILBOX0 + ipi > LOCAL_IRQ_MAILBOX3) + { + RT_ASSERT(0); + break; + } + + rt_pic_config_ipi(&intc.parent, ipi, LOCAL_IRQ_MAILBOX0 + ipi); + pirq = rt_pic_find_ipi(&intc.parent, ipi); + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + } + + rt_pic_add_traps(bcm2836_arm_l1_intc_handler, &intc); + } + else + { + err = -RT_ERROR; + } + + return err; +} + +static const struct rt_ofw_node_id bcm2836_arm_l1_intc_ofw_ids[] = +{ + { .compatible = "brcm,bcm2836-l1-intc" }, + { /* sentinel */ } +}; +RT_PIC_OFW_DECLARE(bcm2836_arm_l1_intc, bcm2836_arm_l1_intc_ofw_ids, bcm2836_arm_l1_intc_init); diff --git a/bsp/raspberry-pi/dm/pic/pic-brcmstb-l2.c b/bsp/raspberry-pi/dm/pic/pic-brcmstb-l2.c new file mode 100644 index 0000000000..ded70ef69e --- /dev/null +++ b/bsp/raspberry-pi/dm/pic/pic-brcmstb-l2.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pic.brcmstb_l2" +#define DBG_LVL DBG_INFO +#include + +struct brcmstb_intc_init_params +{ + int cpu_status; + int cpu_clear; + int cpu_mask_status; + int cpu_mask_set; + int cpu_mask_clear; +}; + +struct brcmstb_l2_intc +{ + struct rt_pic parent; + + int irq; + void *regs; + rt_bool_t can_wake; + struct rt_ofw_node *np; + + const struct brcmstb_intc_init_params *params; +}; + +#define raw_to_brcmstb_l2_intc(raw) rt_container_of(raw, struct brcmstb_l2_intc, parent) + +/* Register offsets in the L2 latched interrupt controller */ +static const struct brcmstb_intc_init_params l2_edge_intc = +{ + .cpu_status = 0x00, + .cpu_clear = 0x08, + .cpu_mask_status = 0x0c, + .cpu_mask_set = 0x10, + .cpu_mask_clear = 0x14 +}; + +/* Register offsets in the L2 level interrupt controller */ +static const struct brcmstb_intc_init_params l2_lvl_intc = +{ + .cpu_status = 0x00, + .cpu_clear = -1, /* Register not present */ + .cpu_mask_status = 0x04, + .cpu_mask_set = 0x08, + .cpu_mask_clear = 0x0c +}; + +/* Register offsets in the 2711 L2 level interrupt controller */ +static const struct brcmstb_intc_init_params l2_2711_lvl_intc = +{ + .cpu_status = 0x00, + .cpu_clear = 0x08, + .cpu_mask_status = 0x0c, + .cpu_mask_set = 0x10, + .cpu_mask_clear = 0x14 +}; + +static void brcmstb_l2_intc_isr(int irqno, void *params); + +static rt_err_t brcmstb_l2_intc_irq_init(struct rt_pic *pic) +{ + struct brcmstb_l2_intc *bl2 = raw_to_brcmstb_l2_intc(pic); + + bl2->irq = rt_ofw_get_irq(bl2->np, 0); + + if (bl2->irq < 0) + { + LOG_E("Failed to find parent interrupt"); + return -RT_EINVAL; + } + + rt_hw_interrupt_install(bl2->irq, brcmstb_l2_intc_isr, bl2, "BRCMSTB-L2-INTC"); + rt_hw_interrupt_umask(bl2->irq); + + return RT_EOK; +} + +static void brcmstb_l2_intc_irq_ack(struct rt_pic_irq *pirq) +{ + struct brcmstb_l2_intc *bl2 = raw_to_brcmstb_l2_intc(pirq->pic); + + if (bl2->params->cpu_clear >= 0) + { + HWREG32(bl2->regs + bl2->params->cpu_clear) = RT_BIT(pirq->hwirq); + } +} + +static void brcmstb_l2_intc_irq_mask(struct rt_pic_irq *pirq) +{ + struct brcmstb_l2_intc *bl2 = raw_to_brcmstb_l2_intc(pirq->pic); + + HWREG32(bl2->regs + bl2->params->cpu_mask_set) = RT_BIT(pirq->hwirq); +} + +static void brcmstb_l2_intc_irq_unmask(struct rt_pic_irq *pirq) +{ + struct brcmstb_l2_intc *bl2 = raw_to_brcmstb_l2_intc(pirq->pic); + + HWREG32(bl2->regs + bl2->params->cpu_mask_clear) = RT_BIT(pirq->hwirq); +} + +static int brcmstb_l2_intc_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + RT_IRQ_AFFINITY_SET(pirq->affinity, rt_hw_cpu_id()); + pirq->mode = mode; + + return rt_pic_config_irq(pic, hwirq, hwirq); +} + +static rt_err_t brcmstb_l2_intc_irq_parse(struct rt_pic *pic, + struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + struct brcmstb_l2_intc *bl2 = rt_container_of(pic, struct brcmstb_l2_intc, parent); + + if (args->args_count == 1) + { + out_pirq->hwirq = args->args[0]; + + if (bl2->params == &l2_edge_intc) + { + out_pirq->mode = RT_IRQ_MODE_EDGE_RISING; + } + else if (bl2->params == &l2_lvl_intc || bl2->params == &l2_2711_lvl_intc) + { + out_pirq->mode = RT_IRQ_MODE_LEVEL_HIGH; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +const static struct rt_pic_ops brcmstb_l2_intc_ops = +{ + .name = "BRCMSTB-L2-INTC", + .irq_init = brcmstb_l2_intc_irq_init, + .irq_ack = brcmstb_l2_intc_irq_ack, + .irq_mask = brcmstb_l2_intc_irq_mask, + .irq_unmask = brcmstb_l2_intc_irq_unmask, + .irq_map = brcmstb_l2_intc_irq_map, + .irq_parse = brcmstb_l2_intc_irq_parse, +}; + +static void brcmstb_l2_intc_isr(int irqno, void *params) +{ + struct rt_pic_irq *pirq; + rt_uint32_t hwirq, raw_status, mask_status, status; + struct brcmstb_l2_intc *bl2 = params; + + RT_UNUSED(irqno); + + raw_status = HWREG32(bl2->regs + bl2->params->cpu_status); + mask_status = HWREG32(bl2->regs + bl2->params->cpu_mask_status); + status = raw_status & ~mask_status; + + if (!status) + { + return; + } + + do { + hwirq = __rt_ffs(status) - 1; + status &= ~RT_BIT(hwirq); + + pirq = rt_pic_find_irq(&bl2->parent, hwirq); + if (!pirq) + { + if (bl2->params->cpu_clear >= 0) + { + HWREG32(bl2->regs + bl2->params->cpu_clear) = RT_BIT(hwirq); + } + continue; + } + + brcmstb_l2_intc_irq_ack(pirq); + + rt_pic_handle_isr(pirq); + } while (status); +} + +static rt_err_t brcmstb_l2_intc_ofw_intc(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) +{ + rt_err_t err; + const struct brcmstb_intc_init_params *params; + struct brcmstb_l2_intc *bl2 = rt_calloc(1, sizeof(*bl2)); + + if (!bl2) + { + return -RT_ENOMEM; + } + + bl2->regs = rt_ofw_iomap(np, 0); + + if (!bl2->regs) + { + err = -RT_EIO; + goto _fail; + } + + bl2->params = params = id->data; + bl2->irq = -RT_EEMPTY; + + /* Disable all interrupts by default */ + HWREG32(bl2->regs + params->cpu_mask_set) = 0xffffffff; + + /* Wakeup interrupts may be retained from S5 (cold boot) */ + bl2->can_wake = rt_ofw_prop_read_bool(np, "brcm,irq-can-wake"); + if (!bl2->can_wake && params->cpu_clear >= 0) + { + HWREG32(bl2->regs + params->cpu_clear) = 0xffffffff; + } + + bl2->parent.priv_data = bl2; + bl2->parent.ops = &brcmstb_l2_intc_ops; + + bl2->np = np; + rt_ofw_data(np) = &bl2->parent; + + rt_pic_linear_irq(&bl2->parent, 32); + + return RT_EOK; + +_fail: + if (bl2->regs) + { + rt_iounmap(bl2->regs); + } + + rt_free(bl2); + + return err; +} + +static const struct rt_ofw_node_id brcmstb_l2_intc_ofw_ids[] = +{ + { .compatible = "brcm,l2-intc", .data = &l2_edge_intc }, + { .compatible = "brcm,hif-spi-l2-intc", .data = &l2_edge_intc }, + { .compatible = "brcm,upg-aux-aon-l2-intc", .data = &l2_edge_intc }, + { .compatible = "brcm,bcm7271-l2-intc", .data = &l2_lvl_intc }, + { .compatible = "brcm,bcm2711-l2-intc", .data = &l2_2711_lvl_intc }, + { /* sentinel */ } +}; + +rt_err_t brcmstb_l2_intc_request_node(struct rt_ofw_node *np) +{ + rt_err_t err; + struct rt_pic *pic; + struct brcmstb_l2_intc *bl2; + struct rt_ofw_prop *compat_prop; + struct rt_ofw_node_id *id; + + if (!np || !rt_ofw_node_is_available(np)) + { + return -RT_EINVAL; + } + + pic = rt_pic_dynamic_cast(rt_ofw_data(np)); + if (pic) + { + bl2 = raw_to_brcmstb_l2_intc(pic); + if (bl2->irq < 0) + { + err = brcmstb_l2_intc_irq_init(pic); + if (!err) + { + rt_ofw_node_set_flag(np, RT_OFW_F_READLY); + } + + return err; + } + + return RT_EOK; + } + + compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL); + id = rt_ofw_prop_match(compat_prop, brcmstb_l2_intc_ofw_ids); + if (!id) + { + return -RT_ENOSYS; + } + + err = brcmstb_l2_intc_ofw_intc(np, id); + if (err) + { + return err; + } + + pic = rt_pic_dynamic_cast(rt_ofw_data(np)); + if (!pic) + { + return -RT_EIO; + } + + err = brcmstb_l2_intc_irq_init(pic); + if (err) + { + return err; + } + rt_ofw_node_set_flag(np, RT_OFW_F_READLY); + + return RT_EOK; +} + +RT_PIC_OFW_DECLARE(brcmstb_l2_intc, brcmstb_l2_intc_ofw_ids, brcmstb_l2_intc_ofw_intc); diff --git a/bsp/raspberry-pi/dm/pin/Kconfig b/bsp/raspberry-pi/dm/pin/Kconfig new file mode 100755 index 0000000000..016fd764da --- /dev/null +++ b/bsp/raspberry-pi/dm/pin/Kconfig @@ -0,0 +1,15 @@ +config RT_PIN_BCM_VIRT + bool "Broadcom Virt GPIO support" + depends on RT_USING_PIN + default n + +config RT_PIN_BRCMSTB + bool "BRCMSTB GPIO support" + depends on RT_USING_PIN + default n + +config RT_PIN_RASPBERRYPI_EXP + bool "Raspberry Pi 3 GPIO Expander" + depends on RT_USING_PIN + depends on RT_FIRMWARE_RASPBERRYPI + default n diff --git a/bsp/raspberry-pi/dm/pin/SConscript b/bsp/raspberry-pi/dm/pin/SConscript new file mode 100755 index 0000000000..4f39edb52d --- /dev/null +++ b/bsp/raspberry-pi/dm/pin/SConscript @@ -0,0 +1,19 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/pin'] + +if GetDepend(['RT_PIN_BCM_VIRT']): + src += ['pin-bcm-virt.c'] + +if GetDepend(['RT_PIN_BRCMSTB']): + src += ['pin-brcmstb.c'] + +if GetDepend(['RT_PIN_RASPBERRYPI_EXP']): + src += ['pin-raspberrypi-exp.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pin/pin-bcm-virt.c b/bsp/raspberry-pi/dm/pin/pin-bcm-virt.c new file mode 100755 index 0000000000..69085138d2 --- /dev/null +++ b/bsp/raspberry-pi/dm/pin/pin-bcm-virt.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#include + +#include "dev_pin_dm.h" + +#define NUM_GPIO 2 + +struct brcmvirt_gpio +{ + struct rt_device_pin parent; + rt_uint32_t *ts_base; + + rt_uint32_t enables_disables[NUM_GPIO]; + rt_ubase_t bus_addr; +}; + +#define raw_to_brcmvirt_gpio(raw) rt_container_of(raw, struct brcmvirt_gpio, parent) + +static void brcmvirt_gpio_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ +} + +static void brcmvirt_gpio_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + rt_bool_t lit; + rt_uint16_t enables, disables; + struct brcmvirt_gpio *gpio = raw_to_brcmvirt_gpio(device); + + enables = gpio->enables_disables[pin] >> 16; + disables = gpio->enables_disables[pin] >> 0; + lit = (rt_int16_t)(enables - disables) > 0; + + if ((value && lit) || (!value && !lit)) + { + return; + } + + if (value) + { + enables++; + } + else + { + disables++; + } + + gpio->enables_disables[pin] = (enables << 16) | (disables << 0); + HWREG32(gpio->ts_base + pin) = gpio->enables_disables[pin]; +} + +static rt_ssize_t brcmvirt_gpio_read(struct rt_device *device, rt_base_t pin) +{ + rt_uint32_t value; + struct brcmvirt_gpio *gpio = raw_to_brcmvirt_gpio(device); + + value = HWREG32(gpio->ts_base + pin); + + return (rt_int16_t)((value >> 16) - value) > 0; +} + +static const struct rt_pin_ops brcmvirt_gpio_ops = +{ + .pin_mode = brcmvirt_gpio_mode, + .pin_write = brcmvirt_gpio_write, + .pin_read = brcmvirt_gpio_read, +}; + +static rt_err_t brcmvirt_gpio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + void *ts_base; + rt_uint32_t virtbuf; + struct rpi_firmware *rpi_fw = RT_NULL; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct brcmvirt_gpio *gpio = rt_calloc(1, sizeof(*gpio)); + + if (!gpio) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + ts_base = rt_dma_alloc_coherent(dev, ARCH_PAGE_SIZE, &gpio->bus_addr); + + if (!ts_base) + { + err = -RT_ENOMEM; + goto _fail; + } + + virtbuf = (rt_uint32_t)gpio->bus_addr; + err = rpi_firmware_property(rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF, &gpio->bus_addr, sizeof(virtbuf)); + + if (err) + { + goto _fail; + } + + err = rpi_firmware_property(rpi_fw, + RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF, &virtbuf, sizeof(virtbuf)); + + if (err) + { + goto _fail; + } + + virtbuf &= ~0xc0000000; + gpio->ts_base = rt_ioremap((void *)(rt_ubase_t)virtbuf, ARCH_PAGE_SIZE); + + if (!gpio->ts_base) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, &gpio->parent); + + gpio->parent.ops = &brcmvirt_gpio_ops; + pin_api_init(&gpio->parent, NUM_GPIO); + + return RT_EOK; + +_fail: + if (gpio->bus_addr) + { + rt_dma_free_coherent(dev, ARCH_PAGE_SIZE, ts_base, gpio->bus_addr); + } + + if (rpi_fw) + { + rpi_firmware_put(rpi_fw); + } + + rt_free(gpio); + + return err; +} + +static const struct rt_ofw_node_id brcmvirt_gpio_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-virtgpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmvirt_gpio_driver = +{ + .name = "brcmvirt-gpio", + .ids = brcmvirt_gpio_ofw_ids, + + .probe = brcmvirt_gpio_probe, +}; + +static int brcmvirt_gpio_drv_register(void) +{ + rt_platform_driver_register(&brcmvirt_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(brcmvirt_gpio_drv_register); diff --git a/bsp/raspberry-pi/dm/pin/pin-brcmstb.c b/bsp/raspberry-pi/dm/pin/pin-brcmstb.c new file mode 100644 index 0000000000..59a56f3483 --- /dev/null +++ b/bsp/raspberry-pi/dm/pin/pin-brcmstb.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pin.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +enum gio_reg_index +{ + GIO_REG_ODEN = 0, + GIO_REG_DATA, + GIO_REG_IODIR, + GIO_REG_EC, + GIO_REG_EI, + GIO_REG_MASK, + GIO_REG_LEVEL, + GIO_REG_STAT, + NUMBER_OF_GIO_REGISTERS +}; + +#define MAX_GPIO_PER_BANK 32 +#define brcmstb_gpio_bit(pin) RT_BIT((pin) % MAX_GPIO_PER_BANK) + +struct brcmstb_gpio; + +struct brcmstb_gpio_bank +{ + int id; + struct brcmstb_gpio *gpio; + + rt_uint32_t width; +}; + +struct brcmstb_gpio +{ + struct rt_device_pin parent; + + void *base; + int irq; + + struct rt_spinlock lock; + + rt_uint32_t num_banks; + struct brcmstb_gpio_bank *banks; +}; + +extern rt_err_t brcmstb_l2_intc_request_node(struct rt_ofw_node *np); + +rt_inline struct brcmstb_gpio_bank *raw_to_brcmstb_gpio_bank(struct rt_device *raw, rt_ubase_t pin) +{ + struct brcmstb_gpio *gpio = rt_container_of(raw, struct brcmstb_gpio, parent); + rt_ubase_t bank_id = pin / MAX_GPIO_PER_BANK; + + if (bank_id >= gpio->num_banks) + { + return RT_NULL; + } + + return &gpio->banks[bank_id]; +} + +rt_inline rt_bool_t brcmstb_gpio_bank_is_valid(struct brcmstb_gpio_bank *bank, rt_base_t pin) +{ + return bank && bank->width && (pin % MAX_GPIO_PER_BANK) < bank->width; +} + +rt_inline rt_uint32_t brcmstb_gpio_valid_mask(struct brcmstb_gpio_bank *bank) +{ + if (bank->width >= MAX_GPIO_PER_BANK) + { + return 0xffffffffU; + } + + return RT_BIT(bank->width) - 1; +} + +rt_inline rt_uint32_t brcmstb_gpio_offset(struct brcmstb_gpio_bank *bank, rt_uint32_t reg) +{ + return bank->id * NUMBER_OF_GIO_REGISTERS * sizeof(rt_uint32_t) + reg * sizeof(rt_uint32_t); +} + +rt_inline rt_uint32_t brcmstb_gpio_readl(struct brcmstb_gpio_bank *bank, rt_uint32_t reg) +{ + return HWREG32(bank->gpio->base + brcmstb_gpio_offset(bank, reg)); +} + +rt_inline void brcmstb_gpio_writel(struct brcmstb_gpio_bank *bank, rt_uint32_t reg, rt_uint32_t value) +{ + HWREG32(bank->gpio->base + brcmstb_gpio_offset(bank, reg)) = value; +} + +static void brcmstb_gpio_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_ubase_t level; + rt_uint32_t oden, iodir, bit = brcmstb_gpio_bit(pin); + struct brcmstb_gpio_bank *bank = raw_to_brcmstb_gpio_bank(device, pin); + + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return; + } + + level = rt_spin_lock_irqsave(&bank->gpio->lock); + + oden = brcmstb_gpio_readl(bank, GIO_REG_ODEN); + iodir = brcmstb_gpio_readl(bank, GIO_REG_IODIR); + + switch (mode) + { + case PIN_MODE_OUTPUT: + brcmstb_gpio_writel(bank, GIO_REG_ODEN, oden & ~bit); + brcmstb_gpio_writel(bank, GIO_REG_IODIR, iodir & ~bit); + break; + + case PIN_MODE_OUTPUT_OD: + brcmstb_gpio_writel(bank, GIO_REG_ODEN, oden | bit); + brcmstb_gpio_writel(bank, GIO_REG_IODIR, iodir & ~bit); + break; + + case PIN_MODE_INPUT: + case PIN_MODE_INPUT_PULLUP: + case PIN_MODE_INPUT_PULLDOWN: + brcmstb_gpio_writel(bank, GIO_REG_IODIR, iodir | bit); + break; + + default: + break; + } + + rt_spin_unlock_irqrestore(&bank->gpio->lock, level); +} + +static void brcmstb_gpio_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + rt_ubase_t level; + rt_uint32_t data, bit = brcmstb_gpio_bit(pin); + struct brcmstb_gpio_bank *bank = raw_to_brcmstb_gpio_bank(device, pin); + + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return; + } + + level = rt_spin_lock_irqsave(&bank->gpio->lock); + + data = brcmstb_gpio_readl(bank, GIO_REG_DATA); + if (value) + { + data |= bit; + } + else + { + data &= ~bit; + } + brcmstb_gpio_writel(bank, GIO_REG_DATA, data); + + rt_spin_unlock_irqrestore(&bank->gpio->lock, level); +} + +static rt_ssize_t brcmstb_gpio_read(struct rt_device *device, rt_base_t pin) +{ + struct brcmstb_gpio_bank *bank = raw_to_brcmstb_gpio_bank(device, pin); + + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return 0; + } + + return !!(brcmstb_gpio_readl(bank, GIO_REG_DATA) & brcmstb_gpio_bit(pin)); +} + +static rt_err_t brcmstb_gpio_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_ubase_t level; + rt_uint32_t imask, mask = brcmstb_gpio_bit(pin); + struct brcmstb_gpio_bank *bank = raw_to_brcmstb_gpio_bank(device, pin); + + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&bank->gpio->lock); + + imask = brcmstb_gpio_readl(bank, GIO_REG_MASK); + if (enabled) + { + imask |= mask; + } + else + { + imask &= ~mask; + } + brcmstb_gpio_writel(bank, GIO_REG_MASK, imask); + + rt_spin_unlock_irqrestore(&bank->gpio->lock, level); + + return RT_EOK; +} + +static rt_err_t brcmstb_gpio_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_ubase_t level; + rt_uint32_t mask = brcmstb_gpio_bit(pin); + rt_uint32_t int_level, ilevel; + rt_uint32_t edge_config, iedge_config; + rt_uint32_t edge_insensitive, iedge_insensitive; + struct brcmstb_gpio_bank *bank = raw_to_brcmstb_gpio_bank(device, pin); + + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return -RT_EINVAL; + } + + switch (mode) + { + case PIN_IRQ_MODE_LOW_LEVEL: + int_level = mask; + edge_config = 0; + edge_insensitive = 0; + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + int_level = mask; + edge_config = mask; + edge_insensitive = 0; + break; + + case PIN_IRQ_MODE_FALLING: + int_level = 0; + edge_config = 0; + edge_insensitive = 0; + break; + + case PIN_IRQ_MODE_RISING: + int_level = 0; + edge_config = mask; + edge_insensitive = 0; + break; + + case PIN_IRQ_MODE_RISING_FALLING: + int_level = 0; + edge_config = 0; + edge_insensitive = mask; + break; + + default: + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&bank->gpio->lock); + + iedge_config = brcmstb_gpio_readl(bank, GIO_REG_EC) & ~mask; + iedge_insensitive = brcmstb_gpio_readl(bank, GIO_REG_EI) & ~mask; + ilevel = brcmstb_gpio_readl(bank, GIO_REG_LEVEL) & ~mask; + + brcmstb_gpio_writel(bank, GIO_REG_EC, iedge_config | edge_config); + brcmstb_gpio_writel(bank, GIO_REG_EI, iedge_insensitive | edge_insensitive); + brcmstb_gpio_writel(bank, GIO_REG_LEVEL, ilevel | int_level); + + rt_spin_unlock_irqrestore(&bank->gpio->lock, level); + + return RT_EOK; +} + +static rt_err_t brcmstb_gpio_attach_irq(struct rt_device *device, rt_base_t pin, + rt_uint8_t mode, void (*hdr)(void *args), void *args) +{ + rt_err_t err; + struct brcmstb_gpio *gpio = rt_container_of(device, struct brcmstb_gpio, parent); + struct rt_pin_irq_hdr *legacy_isr; + + if (!brcmstb_gpio_bank_is_valid(raw_to_brcmstb_gpio_bank(device, pin), pin)) + { + return -RT_EINVAL; + } + + if (!gpio->parent.legacy_isr) + { + return -RT_ENOSYS; + } + + err = brcmstb_gpio_irq_mode(device, pin, mode); + if (err) + { + return err; + } + + legacy_isr = &gpio->parent.legacy_isr[pin]; + legacy_isr->pin = pin; + legacy_isr->mode = mode; + legacy_isr->hdr = hdr; + legacy_isr->args = args; + + return RT_EOK; +} + +static rt_ssize_t brcmstb_gpio_parse(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + struct brcmstb_gpio_bank *bank; + rt_base_t pin; + + if (!args || args->args_count < 2) + { + return -RT_EINVAL; + } + + pin = args->args[0]; + bank = raw_to_brcmstb_gpio_bank(device, pin); + if (!brcmstb_gpio_bank_is_valid(bank, pin)) + { + return -RT_EINVAL; + } + + if (flags) + { + *flags = args->args[1]; + } + + return pin; +} + +static const struct rt_pin_ops brcmstb_gpio_ops = +{ + .pin_mode = brcmstb_gpio_mode, + .pin_write = brcmstb_gpio_write, + .pin_read = brcmstb_gpio_read, + .pin_attach_irq = brcmstb_gpio_attach_irq, + .pin_irq_enable = brcmstb_gpio_irq_enable, + .pin_irq_mode = brcmstb_gpio_irq_mode, + .pin_parse = brcmstb_gpio_parse, +}; + +static void brcmstb_gpio_isr(int irqno, void *param) +{ + rt_ubase_t level; + rt_uint32_t mask, status; + struct brcmstb_gpio *gpio = param; + + RT_UNUSED(irqno); + + for (int i = 0; i < gpio->num_banks; ++i) + { + struct brcmstb_gpio_bank *bank = &gpio->banks[i]; + + while (RT_TRUE) + { + level = rt_spin_lock_irqsave(&gpio->lock); + status = brcmstb_gpio_readl(bank, GIO_REG_STAT); + status &= brcmstb_gpio_readl(bank, GIO_REG_MASK); + status &= brcmstb_gpio_valid_mask(bank); + rt_spin_unlock_irqrestore(&gpio->lock, level); + + if (!status) + { + break; + } + + for (rt_ubase_t pin = 0; pin < bank->width; ++pin) + { + mask = RT_BIT(pin); + + if (mask & status) + { + brcmstb_gpio_writel(bank, GIO_REG_STAT, mask); + pin_pic_handle_isr(&gpio->parent, bank->id * MAX_GPIO_PER_BANK + pin); + } + } + } + } +} + +static void brcmstb_gpio_apply_hogs(struct brcmstb_gpio *gpio) +{ + struct rt_device *dev = &gpio->parent.parent; + struct rt_ofw_node *child; + + rt_ofw_foreach_child_node(dev->ofw_node, child) + { + rt_uint32_t cells[2]; + rt_ssize_t nr; + struct brcmstb_gpio_bank *bank; + + if (!rt_ofw_get_prop(child, "gpio-hog", RT_NULL)) + { + continue; + } + + nr = rt_ofw_prop_read_u32_array_index(child, "gpios", 0, 2, cells); + if (nr < 2) + { + continue; + } + + bank = raw_to_brcmstb_gpio_bank(dev, cells[0]); + if (!brcmstb_gpio_bank_is_valid(bank, cells[0])) + { + continue; + } + + if (rt_ofw_get_prop(child, "input", RT_NULL)) + { + brcmstb_gpio_mode(dev, cells[0], PIN_MODE_INPUT); + } + else if (rt_ofw_get_prop(child, "output-high", RT_NULL)) + { + brcmstb_gpio_write(dev, cells[0], 1); + brcmstb_gpio_mode(dev, cells[0], PIN_MODE_OUTPUT); + } + else if (rt_ofw_get_prop(child, "output-low", RT_NULL)) + { + brcmstb_gpio_write(dev, cells[0], 0); + brcmstb_gpio_mode(dev, cells[0], PIN_MODE_OUTPUT); + } + } +} + +static rt_err_t brcmstb_gpio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = -RT_EINVAL; + const fdt32_t *cell; + rt_uint32_t num_banks, value; + struct rt_ofw_prop *prop; + struct rt_device *dev = &pdev->parent; + struct brcmstb_gpio_bank *bank = RT_NULL; + struct brcmstb_gpio *gpio = rt_calloc(1, sizeof(*gpio)); + + if (!gpio) + { + return -RT_ENOMEM; + } + + gpio->base = rt_dm_dev_iomap(dev, 0); + + if (!gpio->base) + { + err = -RT_EIO; + goto _fail; + } + + if (dev->ofw_node) + { + struct rt_ofw_node *irq_parent; + + irq_parent = rt_ofw_find_irq_parent(dev->ofw_node, RT_NULL); + if (irq_parent) + { + brcmstb_l2_intc_request_node(irq_parent); + rt_ofw_node_put(irq_parent); + } + } + + gpio->irq = rt_dm_dev_get_irq(dev, 0); + + if (gpio->irq < 0 && gpio->irq != -RT_EEMPTY && gpio->irq != -RT_EIO) + { + err = gpio->irq; + goto _fail; + } + + num_banks = 0; + rt_ofw_foreach_prop_u32(dev->ofw_node, "brcm,gpio-bank-widths", prop, cell, value) + { + struct brcmstb_gpio_bank *new_bank; + + if (!(new_bank = rt_realloc(bank, sizeof(*bank) * (num_banks + 1)))) + { + LOG_E("No memory for bank(%u)", num_banks + 1); + err = -RT_ENOMEM; + goto _fail; + } + + bank = new_bank; + new_bank += num_banks; + + rt_memset(new_bank, 0, sizeof(*new_bank)); + new_bank->id = num_banks; + new_bank->gpio = gpio; + + if (value > MAX_GPIO_PER_BANK) + { + LOG_E("Invalid bank width %u", value); + goto _fail; + } + + new_bank->width = value; + ++num_banks; + } + + if (!num_banks) + { + LOG_E("No valid gpio banks described"); + goto _fail; + } + + gpio->num_banks = num_banks; + gpio->banks = bank; + rt_spin_lock_init(&gpio->lock); + + gpio->parent.ops = &brcmstb_gpio_ops; + pin_api_init(&gpio->parent, MAX_GPIO_PER_BANK * gpio->num_banks); + + if (gpio->irq >= 0) + { + for (rt_ubase_t i = 0; i < gpio->num_banks; ++i) + { + brcmstb_gpio_writel(&gpio->banks[i], GIO_REG_MASK, 0); + } + + pin_pic_init(&gpio->parent, gpio->irq); + rt_hw_interrupt_install(gpio->irq, brcmstb_gpio_isr, gpio, "brcmstb-gpio"); + rt_hw_interrupt_umask(gpio->irq); + } + + rt_ofw_data(dev->ofw_node) = &gpio->parent; + + brcmstb_gpio_apply_hogs(gpio); + + return RT_EOK; + +_fail: + if (bank) + { + rt_free(bank); + } + + if (gpio->base) + { + rt_iounmap(gpio->base); + } + + rt_free(gpio); + + return err; +} + +static const struct rt_ofw_node_id brcmstb_gpio_ofw_ids[] = +{ + { .compatible = "brcm,brcmstb-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmstb_gpio_driver = +{ + .name = "brcmstb-gpio", + .ids = brcmstb_gpio_ofw_ids, + + .probe = brcmstb_gpio_probe, +}; + +static int brcmstb_gpio_register(void) +{ + rt_platform_driver_register(&brcmstb_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(brcmstb_gpio_register); diff --git a/bsp/raspberry-pi/dm/pin/pin-raspberrypi-exp.c b/bsp/raspberry-pi/dm/pin/pin-raspberrypi-exp.c new file mode 100755 index 0000000000..13e1b4e881 --- /dev/null +++ b/bsp/raspberry-pi/dm/pin/pin-raspberrypi-exp.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "pin.raspberrypi-exp" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define RPI_EXP_GPIO_BASE 128 + +#define RPI_EXP_GPIO_DIR_IN 0 +#define RPI_EXP_GPIO_DIR_OUT 1 + +#define RPI_EXP_GPIO_NR 8 + +struct gpio_set_config +{ + struct rpi_firmware_property_tag_header hdr; + + rt_uint32_t gpio; + rt_uint32_t direction; + rt_uint32_t polarity; + rt_uint32_t term_en; + rt_uint32_t term_pull_up; + rt_uint32_t state; +}; + +struct gpio_get_config +{ + struct rpi_firmware_property_tag_header hdr; + + rt_uint32_t gpio; + rt_uint32_t direction; + rt_uint32_t polarity; + rt_uint32_t term_en; + rt_uint32_t term_pull_up; +}; + +struct gpio_get_set_state +{ + struct rpi_firmware_property_tag_header hdr; + + rt_uint32_t gpio; + rt_uint32_t state; +}; + +struct rpi_exp_gpio +{ + struct rt_device_pin parent; + + void *property; + rt_ubase_t property_dma; + struct rpi_firmware *rpi_fw; + struct rt_spinlock lock; +}; + +#define raw_to_rpi_exp_gpio(raw) rt_container_of(raw, struct rpi_exp_gpio, parent) + +static int rpi_exp_gpio_get_polarity(struct rpi_exp_gpio *regpio, rt_base_t pin) +{ + rt_err_t err; + struct gpio_get_config *get = regpio->property; + + get->gpio = pin + RPI_EXP_GPIO_BASE; + + if ((err = rpi_firmware_property_raw(regpio->rpi_fw, RPI_FIRMWARE_GET_GPIO_CONFIG, + regpio->property_dma, (void *)get, sizeof(*get))) || get->gpio != 0) + { + LOG_E("Failed to get PIN %u config (%s, %x)", pin, rt_strerror(err), get->gpio); + + return err ? err : -RT_EIO; + } + + return get->polarity; +} + +static void rpi_exp_gpio_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_err_t err; + rt_int32_t polarity; + union + { + struct gpio_set_config in; + struct gpio_set_config out; + } *set; + struct rpi_exp_gpio *regpio = raw_to_rpi_exp_gpio(device); + + if (pin >= RPI_EXP_GPIO_NR) + { + return; + } + + rt_hw_spin_lock(®pio->lock.lock); + + switch (mode) + { + case PIN_MODE_OUTPUT: + if ((polarity = rpi_exp_gpio_get_polarity(regpio, pin)) < 0) + { + LOG_E("Failed to get PIN %u polarity error = %s", pin, rt_strerror(polarity)); + + break; + } + set = regpio->property; + set->out.gpio = pin + RPI_EXP_GPIO_BASE; + set->out.direction = RPI_EXP_GPIO_DIR_OUT; + set->out.term_en = 0; /* n/a as an output */ + set->out.term_pull_up = 0; /* n/a as termination disabled */ + set->out.state = 1; /* Output state */ + set->out.polarity = polarity; /* Retain existing setting */ + + if ((err = rpi_firmware_property_raw(regpio->rpi_fw, RPI_FIRMWARE_SET_GPIO_CONFIG, + regpio->property_dma, (void *)&set->out, sizeof(set->out))) || set->out.gpio != 0) + { + LOG_E("Failed to set PIN %u to output (%s, %x)", pin, rt_strerror(err), set->out.gpio); + } + + break; + + case PIN_MODE_INPUT: + if ((polarity = rpi_exp_gpio_get_polarity(regpio, pin)) < 0) + { + LOG_E("Failed to get PIN %u polarity error = %s", pin, rt_strerror(polarity)); + + break; + } + set = regpio->property; + set->in.gpio = pin + RPI_EXP_GPIO_BASE; + set->in.direction = RPI_EXP_GPIO_DIR_IN; + set->in.term_en = 0; /* Termination disabled */ + set->in.term_pull_up = 0; /* n/a as termination disabled */ + set->in.state = 0; /* n/a as configured as an input */ + set->in.polarity = polarity; /* Retain existing setting */ + + if ((err = rpi_firmware_property_raw(regpio->rpi_fw, RPI_FIRMWARE_SET_GPIO_CONFIG, + regpio->property_dma, (void *)&set->in, sizeof(set->in))) || set->in.gpio != 0) + { + LOG_E("Failed to set PIN %u to input (%s, %x)", pin, rt_strerror(err), set->in.gpio); + } + break; + + default: + break; + } + + rt_hw_spin_unlock(®pio->lock.lock); +} + +static void rpi_exp_gpio_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + rt_err_t err; + struct gpio_get_set_state *set; + struct rpi_exp_gpio *regpio = raw_to_rpi_exp_gpio(device); + + if (pin >= RPI_EXP_GPIO_NR) + { + return; + } + + rt_hw_spin_lock(®pio->lock.lock); + + set = regpio->property; + set->gpio = pin + RPI_EXP_GPIO_BASE; + set->state = value; + + if ((err = rpi_firmware_property_raw(regpio->rpi_fw, RPI_FIRMWARE_SET_GPIO_STATE, + regpio->property_dma, (void *)set, sizeof(*set))) || set->gpio != 0) + { + LOG_E("Failed to set PIN %u state (%s, %x)", pin, rt_strerror(err), set->gpio); + } + + rt_hw_spin_unlock(®pio->lock.lock); +} + +static rt_ssize_t rpi_exp_gpio_pin_read(struct rt_device *device, rt_base_t pin) +{ + rt_ssize_t res; + struct gpio_get_set_state *get; + struct rpi_exp_gpio *regpio = raw_to_rpi_exp_gpio(device); + + if (pin >= RPI_EXP_GPIO_NR) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(®pio->lock.lock); + + get = regpio->property; + get->gpio = pin + RPI_EXP_GPIO_BASE; + get->state = 0; + + if ((res = rpi_firmware_property_raw(regpio->rpi_fw, RPI_FIRMWARE_GET_GPIO_STATE, + regpio->property_dma, (void *)get, sizeof(*get))) || get->gpio != 0) + { + LOG_E("Failed to get PIN %u state (%s, %x)", pin, rt_strerror(res), get->gpio); + + res = res ? : -RT_EIO; + } + else + { + res = !!get->state; + } + + rt_hw_spin_unlock(®pio->lock.lock); + + return res; +} + +static const struct rt_pin_ops rpi_exp_gpio_pin_ops = +{ + .pin_mode = rpi_exp_gpio_pin_mode, + .pin_write = rpi_exp_gpio_pin_write, + .pin_read = rpi_exp_gpio_pin_read, +}; + +static rt_err_t rpi_exp_gpio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_size_t size; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_exp_gpio *rpi_gpio = rt_calloc(1, sizeof(*rpi_gpio)); + + if (!rpi_gpio) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_get_parent(np); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_gpio->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_gpio->rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + size = sizeof(struct gpio_set_config); + size = rt_max_t(rt_size_t, sizeof(struct gpio_get_config), size); + size = rt_max_t(rt_size_t, sizeof(struct gpio_get_set_state), size); + + rpi_gpio->property = rpi_firmware_property_raw_alloc(rpi_gpio->rpi_fw, size, + &rpi_gpio->property_dma); + + if (!rpi_gpio->property) + { + err = -RT_ENOMEM; + goto _fail; + } + + rt_spin_lock_init(&rpi_gpio->lock); + + rpi_gpio->parent.ops = &rpi_exp_gpio_pin_ops; + pin_api_init(&rpi_gpio->parent, RPI_EXP_GPIO_NR); + rt_dm_dev_bind_fwdata(dev, RT_NULL, &rpi_gpio->parent); + + return RT_EOK; + +_fail: + if (rpi_gpio->rpi_fw) + { + rpi_firmware_put(rpi_gpio->rpi_fw); + } + + rt_free(rpi_gpio); + + return err; +} + +static const struct rt_ofw_node_id rpi_exp_gpio_ofw_ids[] = +{ + { .compatible = "raspberrypi,firmware-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_exp_gpio_driver = +{ + .name = "raspberrypi-exp-gpio", + .ids = rpi_exp_gpio_ofw_ids, + + .probe = rpi_exp_gpio_probe, +}; + +static int rpi_exp_gpio_register(void) +{ + rt_platform_driver_register(&rpi_exp_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rpi_exp_gpio_register); diff --git a/bsp/raspberry-pi/dm/pinctrl/Kconfig b/bsp/raspberry-pi/dm/pinctrl/Kconfig new file mode 100755 index 0000000000..6fd1174e84 --- /dev/null +++ b/bsp/raspberry-pi/dm/pinctrl/Kconfig @@ -0,0 +1,14 @@ +config RT_PINCTRL_BCM2712 + bool "Broadcom BCM2712 PINCONF driver" + depends on RT_USING_PINCTRL + default n + +config RT_PINCTRL_BCM2835 + bool "Broadcom BCM2835 GPIO (with PINCONF) driver" + depends on RT_USING_PINCTRL + default n + +config RT_PINCTRL_RP1 + bool "Pinctrl driver for RP1" + depends on RT_USING_PINCTRL + default n diff --git a/bsp/raspberry-pi/dm/pinctrl/SConscript b/bsp/raspberry-pi/dm/pinctrl/SConscript new file mode 100755 index 0000000000..b5f3f87ada --- /dev/null +++ b/bsp/raspberry-pi/dm/pinctrl/SConscript @@ -0,0 +1,19 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PINCTRL_BCM2712']): + src += ['pinctrl-bcm2712.c'] + +if GetDepend(['RT_PINCTRL_BCM2835']): + src += ['pinctrl-bcm2835.c'] + +if GetDepend(['RT_PINCTRL_RP1']): + src += ['pinctrl-rp1.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2712.c b/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2712.c new file mode 100755 index 0000000000..03f3ba8222 --- /dev/null +++ b/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2712.c @@ -0,0 +1,988 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pinctrl.bcm2712" +#define DBG_LVL DBG_INFO +#include + +#define BCM2712_PULL_NONE 0 +#define BCM2712_PULL_DOWN 1 +#define BCM2712_PULL_UP 2 +#define BCM2712_PULL_MASK 0x3 + +#define BCM2712_FSEL_COUNT 9 +#define BCM2712_FSEL_MASK 0xf + +#define REG_BIT_INVALID 0xffff + +#define BIT_TO_REG(b) (((b) >> 5) << 2) +#define BIT_TO_SHIFT(b) ((b) & 0x1f) + +#define GPIO_REGS(n, mr, mb, pr, pb) [n] = { ((mr)*4)*8 + (mb)*4, ((pr)*4)*8 + (pb)*2 } +#define EMMC_REGS(n, r, b) [n] = { 0, ((r)*4)*8 + (b)*2 } +#define AGPIO_REGS(n, mr, mb, pr, pb) [n] = { ((mr)*4)*8 + (mb)*4, ((pr)*4)*8 + (pb)*2 } +#define SGPIO_REGS(n, mr, mb) [n+32] = { ((mr)*4)*8 + (mb)*4, REG_BIT_INVALID } + +#define GPIO_PIN(a) { .number = a, .name = "gpio" #a } +#define AGPIO_PIN(a) { .number = a, .name = "aon_gpio" #a } +#define SGPIO_PIN(a) { .number = a+32, .name = "aon_sgpio" #a } + +enum bcm2712_funcs +{ + func_gpio, + func_alt1, + func_alt2, + func_alt3, + func_alt4, + func_alt5, + func_alt6, + func_alt7, + func_alt8, + func_aon_cpu_standbyb, + func_aon_fp_4sec_resetb, + func_aon_gpclk, + func_aon_pwm, + func_arm_jtag, + func_aud_fs_clk0, + func_avs_pmu_bsc, + func_bsc_m0, + func_bsc_m1, + func_bsc_m2, + func_bsc_m3, + func_clk_observe, + func_ctl_hdmi_5v, + func_enet0, + func_enet0_mii, + func_enet0_rgmii, + func_ext_sc_clk, + func_fl0, + func_fl1, + func_gpclk0, + func_gpclk1, + func_gpclk2, + func_hdmi_tx0_auto_i2c, + func_hdmi_tx0_bsc, + func_hdmi_tx1_auto_i2c, + func_hdmi_tx1_bsc, + func_i2s_in, + func_i2s_out, + func_ir_in, + func_mtsif, + func_mtsif_alt, + func_mtsif_alt1, + func_pdm, + func_pkt, + func_pm_led_out, + func_sc0, + func_sd0, + func_sd2, + func_sd_card_a, + func_sd_card_b, + func_sd_card_c, + func_sd_card_d, + func_sd_card_e, + func_sd_card_f, + func_sd_card_g, + func_spdif_out, + func_spi_m, + func_spi_s, + func_sr_edm_sense, + func_te0, + func_te1, + func_tsio, + func_uart0, + func_uart1, + func_uart2, + func_usb_pwr, + func_usb_vbus, + func_uui, + func_vc_i2c0, + func_vc_i2c3, + func_vc_i2c4, + func_vc_i2c5, + func_vc_i2csl, + func_vc_pcm, + func_vc_pwm0, + func_vc_pwm1, + func_vc_spi0, + func_vc_spi3, + func_vc_spi4, + func_vc_spi5, + func_vc_uart0, + func_vc_uart2, + func_vc_uart3, + func_vc_uart4, + func__, + func_count = func__, +}; + +struct bcm2712_pin_desc +{ + rt_uint32_t number; + const char *name; +}; + +struct bcm2712_pin_funcs +{ +#define PIN(i, f1, f2, f3, f4, f5, f6, f7, f8) \ + [i] = { \ + .funcs = { \ + func_##f1, \ + func_##f2, \ + func_##f3, \ + func_##f4, \ + func_##f5, \ + func_##f6, \ + func_##f7, \ + func_##f8, \ + }, \ + } + rt_uint8_t funcs[BCM2712_FSEL_COUNT - 1]; +}; + +struct bcm2712_pin_regs +{ + rt_uint16_t mux_bit; + rt_uint16_t pad_bit; +}; + +struct bcm2712_pinctrl_soc_data +{ + rt_size_t num_pins; + const struct bcm2712_pin_desc *desc; + const struct bcm2712_pin_funcs *funcs; + const struct bcm2712_pin_regs *regs; +}; + +struct bcm2712_pinctrl +{ + struct rt_device_pin parent; + const struct bcm2712_pinctrl_soc_data *soc_data; + + void *base; + struct rt_spinlock lock; +}; + +#define raw_to_bcm2712_pinctrl(raw) rt_container_of(raw, struct bcm2712_pinctrl, parent) + +static const char * const bcm2712_func_names[] = +{ +#define FUNC_NAME(name) [func_##name] = #name + FUNC_NAME(gpio), + FUNC_NAME(alt1), + FUNC_NAME(alt2), + FUNC_NAME(alt3), + FUNC_NAME(alt4), + FUNC_NAME(alt5), + FUNC_NAME(alt6), + FUNC_NAME(alt7), + FUNC_NAME(alt8), + FUNC_NAME(aon_cpu_standbyb), + FUNC_NAME(aon_fp_4sec_resetb), + FUNC_NAME(aon_gpclk), + FUNC_NAME(aon_pwm), + FUNC_NAME(arm_jtag), + FUNC_NAME(aud_fs_clk0), + FUNC_NAME(avs_pmu_bsc), + FUNC_NAME(bsc_m0), + FUNC_NAME(bsc_m1), + FUNC_NAME(bsc_m2), + FUNC_NAME(bsc_m3), + FUNC_NAME(clk_observe), + FUNC_NAME(ctl_hdmi_5v), + FUNC_NAME(enet0), + FUNC_NAME(enet0_mii), + FUNC_NAME(enet0_rgmii), + FUNC_NAME(ext_sc_clk), + FUNC_NAME(fl0), + FUNC_NAME(fl1), + FUNC_NAME(gpclk0), + FUNC_NAME(gpclk1), + FUNC_NAME(gpclk2), + FUNC_NAME(hdmi_tx0_auto_i2c), + FUNC_NAME(hdmi_tx0_bsc), + FUNC_NAME(hdmi_tx1_auto_i2c), + FUNC_NAME(hdmi_tx1_bsc), + FUNC_NAME(i2s_in), + FUNC_NAME(i2s_out), + FUNC_NAME(ir_in), + FUNC_NAME(mtsif), + FUNC_NAME(mtsif_alt), + FUNC_NAME(mtsif_alt1), + FUNC_NAME(pdm), + FUNC_NAME(pkt), + FUNC_NAME(pm_led_out), + FUNC_NAME(sc0), + FUNC_NAME(sd0), + FUNC_NAME(sd2), + FUNC_NAME(sd_card_a), + FUNC_NAME(sd_card_b), + FUNC_NAME(sd_card_c), + FUNC_NAME(sd_card_d), + FUNC_NAME(sd_card_e), + FUNC_NAME(sd_card_f), + FUNC_NAME(sd_card_g), + FUNC_NAME(spdif_out), + FUNC_NAME(spi_m), + FUNC_NAME(spi_s), + FUNC_NAME(sr_edm_sense), + FUNC_NAME(te0), + FUNC_NAME(te1), + FUNC_NAME(tsio), + FUNC_NAME(uart0), + FUNC_NAME(uart1), + FUNC_NAME(uart2), + FUNC_NAME(usb_pwr), + FUNC_NAME(usb_vbus), + FUNC_NAME(uui), + FUNC_NAME(vc_i2c0), + FUNC_NAME(vc_i2c3), + FUNC_NAME(vc_i2c4), + FUNC_NAME(vc_i2c5), + FUNC_NAME(vc_i2csl), + FUNC_NAME(vc_pcm), + FUNC_NAME(vc_pwm0), + FUNC_NAME(vc_pwm1), + FUNC_NAME(vc_spi0), + FUNC_NAME(vc_spi3), + FUNC_NAME(vc_spi4), + FUNC_NAME(vc_spi5), + FUNC_NAME(vc_uart0), + FUNC_NAME(vc_uart2), + FUNC_NAME(vc_uart3), + FUNC_NAME(vc_uart4), +#undef FUNC_NAME +}; + +rt_inline rt_uint32_t bcm2712_reg_rd(struct bcm2712_pinctrl *pc, int reg) +{ + return HWREG32(pc->base + reg); +} + +rt_inline void bcm2712_reg_wr(struct bcm2712_pinctrl *pc, int reg, rt_uint32_t val) +{ + HWREG32(pc->base + reg) = val; +} + +static void bcm2712_pinctrl_fsel_set(struct bcm2712_pinctrl *pc, rt_ubase_t pin, + enum bcm2712_funcs func) +{ + int fsel, cur; + const rt_uint8_t *pin_funcs; + rt_uint32_t bit = pc->soc_data->regs[pin].mux_bit, val; + + if (!bit || func >= func_count) + { + return; + } + + fsel = BCM2712_FSEL_COUNT; + + if (func >= BCM2712_FSEL_COUNT) + { + /* Convert to an fsel number */ + pin_funcs = pc->soc_data->funcs[pin].funcs; + + for (int i = 1; i < BCM2712_FSEL_COUNT; ++i) + { + if (pin_funcs[i - 1] == func) + { + fsel = i; + break; + } + } + } + else + { + fsel = (enum bcm2712_funcs)func; + } + + if (fsel >= BCM2712_FSEL_COUNT) + { + return; + } + + val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); + cur = (val >> BIT_TO_SHIFT(bit)) & BCM2712_FSEL_MASK; + + if (cur != fsel) + { + val &= ~(BCM2712_FSEL_MASK << BIT_TO_SHIFT(bit)); + val |= fsel << BIT_TO_SHIFT(bit); + + bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); + } +} + +static void bcm2712_pull_config_set(struct bcm2712_pinctrl *pc, rt_ubase_t pin, + rt_uint32_t arg) +{ + rt_uint32_t bit = pc->soc_data->regs[pin].pad_bit, val; + + if (bit == REG_BIT_INVALID) + { + return; + } + + val = bcm2712_reg_rd(pc, BIT_TO_REG(bit)); + val &= ~(BCM2712_PULL_MASK << BIT_TO_SHIFT(bit)); + val |= (arg << BIT_TO_SHIFT(bit)); + bcm2712_reg_wr(pc, BIT_TO_REG(bit), val); +} + +static const struct rt_pin_ctrl_conf_params bcm2712_conf_params[] = +{ + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, +}; + +static rt_err_t bcm2712_pinctrl_confs_apply_once(struct bcm2712_pinctrl *pc, + struct rt_ofw_node *np) +{ + rt_err_t err = RT_EOK; + rt_ubase_t pin; + const char *string; + struct rt_ofw_prop *prop; + enum bcm2712_funcs func = func_count; + const struct rt_pin_ctrl_conf_params *conf = RT_NULL; + + if (rt_ofw_prop_read_string(np, "function", &string)) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(bcm2712_func_names); ++i) + { + if (!rt_strcmp(string, bcm2712_func_names[i])) + { + func = (enum bcm2712_funcs)i; + break; + } + } + + if (func == func_count) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(bcm2712_conf_params); ++i) + { + if (rt_ofw_prop_read_bool(np, bcm2712_conf_params[i].propname)) + { + conf = &bcm2712_conf_params[i]; + break; + } + } + + rt_ofw_foreach_prop_string(np, "pins", prop, string) + { + pin = pc->soc_data->num_pins; + + for (int i = 0; i < pc->soc_data->num_pins; ++i) + { + if (!rt_strcmp(pc->soc_data->desc[i].name, string)) + { + pin = pc->soc_data->desc[i].number; + break; + } + } + + if (pin == pc->soc_data->num_pins) + { + err = -RT_EINVAL; + break; + } + + bcm2712_pinctrl_fsel_set(pc, pin, func); + + if (conf) + { + switch (conf->param) + { + case PIN_CONFIG_BIAS_DISABLE: + bcm2712_pull_config_set(pc, pin, BCM2712_PULL_NONE); + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + bcm2712_pull_config_set(pc, pin, BCM2712_PULL_DOWN); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + bcm2712_pull_config_set(pc, pin, BCM2712_PULL_UP); + break; + + default: + err = -RT_ENOSYS; + break; + } + } + } + + return err; +} + +static rt_err_t bcm2712_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + rt_err_t err; + rt_bool_t stage2 = RT_FALSE; + struct rt_ofw_node *conf_np = fw_conf_np, *child; + struct bcm2712_pinctrl *pc = raw_to_bcm2712_pinctrl(device); + + rt_hw_spin_lock(&pc->lock.lock); + + rt_ofw_foreach_child_node(conf_np, child) + { + stage2 = RT_TRUE; + + if ((err = bcm2712_pinctrl_confs_apply_once(pc, child))) + { + goto _unlock; + } + } + + if (!stage2) + { + err = bcm2712_pinctrl_confs_apply_once(pc, conf_np); + } + +_unlock: + rt_hw_spin_unlock(&pc->lock.lock); + + return err; +} + +static const struct rt_pin_ops bcm2712_pinctrl_ops = +{ + .pin_ctrl_confs_apply = bcm2712_pinctrl_confs_apply, +}; + +static rt_err_t bcm2712_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct bcm2712_pinctrl *pc = rt_calloc(1, sizeof(*pc)); + + if (!pc) + { + return -RT_ENOMEM; + } + pc->soc_data = pdev->id->data; + + if (!(pc->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + rt_spin_lock_init(&pc->lock); + pc->parent.ops = &bcm2712_pinctrl_ops; + + rt_ofw_data(dev->ofw_node) = &pc->parent; + + return RT_EOK; + +_fail: + rt_free(pc); + + return err; +} + +static const struct bcm2712_pin_desc bcm2712_c0_gpio_pins[] = +{ + GPIO_PIN(0), + GPIO_PIN(1), + GPIO_PIN(2), + GPIO_PIN(3), + GPIO_PIN(4), + GPIO_PIN(5), + GPIO_PIN(6), + GPIO_PIN(7), + GPIO_PIN(8), + GPIO_PIN(9), + GPIO_PIN(10), + GPIO_PIN(11), + GPIO_PIN(12), + GPIO_PIN(13), + GPIO_PIN(14), + GPIO_PIN(15), + GPIO_PIN(16), + GPIO_PIN(17), + GPIO_PIN(18), + GPIO_PIN(19), + GPIO_PIN(20), + GPIO_PIN(21), + GPIO_PIN(22), + GPIO_PIN(23), + GPIO_PIN(24), + GPIO_PIN(25), + GPIO_PIN(26), + GPIO_PIN(27), + GPIO_PIN(28), + GPIO_PIN(29), + GPIO_PIN(30), + GPIO_PIN(31), + GPIO_PIN(32), + GPIO_PIN(33), + GPIO_PIN(34), + GPIO_PIN(35), + GPIO_PIN(36), + GPIO_PIN(37), + GPIO_PIN(38), + GPIO_PIN(39), + GPIO_PIN(40), + GPIO_PIN(41), + GPIO_PIN(42), + GPIO_PIN(43), + GPIO_PIN(44), + GPIO_PIN(45), + GPIO_PIN(46), + GPIO_PIN(47), + GPIO_PIN(48), + GPIO_PIN(49), + GPIO_PIN(50), + GPIO_PIN(51), + GPIO_PIN(52), + GPIO_PIN(53), + { 54, "emmc_cmd" }, + { 55, "emmc_ds" }, + { 56, "emmc_clk" }, + { 57, "emmc_dat0" }, + { 58, "emmc_dat1" }, + { 59, "emmc_dat2" }, + { 60, "emmc_dat3" }, + { 61, "emmc_dat4" }, + { 62, "emmc_dat5" }, + { 63, "emmc_dat6" }, + { 64, "emmc_dat7" }, +}; + +static const struct bcm2712_pin_funcs bcm2712_c0_gpio_pin_funcs[] = +{ + PIN(0, bsc_m3, vc_i2c0, gpclk0, enet0, vc_pwm1, vc_spi0, ir_in, _), + PIN(1, bsc_m3, vc_i2c0, gpclk1, enet0, vc_pwm1, sr_edm_sense, vc_spi0, vc_uart3), + PIN(2, pdm, i2s_in, gpclk2, vc_spi4, pkt, vc_spi0, vc_uart3, _), + PIN(3, pdm, i2s_in, vc_spi4, pkt, vc_spi0, vc_uart3, _, _), + PIN(4, pdm, i2s_in, arm_jtag, vc_spi4, pkt, vc_spi0, vc_uart3, _), + PIN(5, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), + PIN(6, pdm, vc_i2c3, arm_jtag, sd_card_e, vc_spi4, pkt, vc_pcm, vc_i2c5), + PIN(7, i2s_out, spdif_out, arm_jtag, sd_card_e, vc_i2c3, enet0_rgmii, vc_pcm, vc_spi4), + PIN(8, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, vc_i2c3, enet0_mii, vc_pcm, vc_spi4), + PIN(9, i2s_out, aud_fs_clk0, arm_jtag, sd_card_e, enet0_mii, sd_card_c, vc_spi4, _), + PIN(10, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), + PIN(11, bsc_m3, mtsif_alt1, i2s_in, i2s_out, vc_spi5, enet0_mii, sd_card_c, vc_spi4), + PIN(12, spi_s, mtsif_alt1, i2s_in, i2s_out, vc_spi5, vc_i2csl, sd0, sd_card_d), + PIN(13, spi_s, mtsif_alt1, i2s_out, usb_vbus, vc_spi5, vc_i2csl, sd0, sd_card_d), + PIN(14, spi_s, vc_i2csl, enet0_rgmii, arm_jtag, vc_spi5, vc_pwm0, vc_i2c4, sd_card_d), + PIN(15, spi_s, vc_i2csl, vc_spi3, arm_jtag, vc_pwm0, vc_i2c4, gpclk0, _), + PIN(16, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, gpclk1, _), + PIN(17, sd_card_b, i2s_out, vc_spi3, i2s_in, ext_sc_clk, sd0, enet0_rgmii, gpclk2), + PIN(18, sd_card_b, i2s_out, vc_spi3, i2s_in, sd0, enet0_rgmii, vc_pwm1, _), + PIN(19, sd_card_b, usb_pwr, vc_spi3, pkt, spdif_out, sd0, ir_in, vc_pwm1), + PIN(20, sd_card_b, uui, vc_uart0, arm_jtag, uart2, usb_pwr, vc_pcm, vc_uart4), + PIN(21, usb_pwr, uui, vc_uart0, arm_jtag, uart2, sd_card_b, vc_pcm, vc_uart4), + PIN(22, usb_pwr, enet0, vc_uart0, mtsif, uart2, usb_vbus, vc_pcm, vc_i2c5), + PIN(23, usb_vbus, enet0, vc_uart0, mtsif, uart2, i2s_out, vc_pcm, vc_i2c5), + PIN(24, mtsif, pkt, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3, _), + PIN(25, mtsif, pkt, sc0, uart0, enet0_rgmii, enet0_rgmii, vc_i2c4, vc_uart3), + PIN(26, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), + PIN(27, mtsif, pkt, sc0, uart0, enet0_rgmii, vc_uart4, vc_spi5, _), + PIN(28, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), + PIN(29, mtsif, pkt, sc0, enet0_rgmii, vc_uart4, vc_spi5, _, _), + PIN(30, mtsif, pkt, sc0, sd2, enet0_rgmii, gpclk0, vc_pwm0, _), + PIN(31, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_pwm0, _), + PIN(32, mtsif, pkt, sc0, sd2, enet0_rgmii, vc_spi3, vc_uart3, _), + PIN(33, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_uart3, _, _), + PIN(34, mtsif, pkt, ext_sc_clk, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _), + PIN(35, mtsif, pkt, sd2, enet0_rgmii, vc_spi3, vc_i2c5, _, _), + PIN(36, sd0, mtsif, sc0, i2s_in, vc_uart3, vc_uart2, _, _), + PIN(37, sd0, mtsif, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), + PIN(38, sd0, mtsif_alt, sc0, vc_spi0, i2s_in, vc_uart3, vc_uart2, _), + PIN(39, sd0, mtsif_alt, sc0, vc_spi0, vc_uart3, vc_uart2, _, _), + PIN(40, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), + PIN(41, sd0, mtsif_alt, sc0, vc_spi0, bsc_m3, _, _, _), + PIN(42, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), + PIN(43, vc_spi0, mtsif_alt, vc_i2c0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), + PIN(44, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), + PIN(45, vc_spi0, mtsif_alt, enet0, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m), + PIN(46, vc_spi0, mtsif_alt, sd_card_a, mtsif_alt1, arm_jtag, pdm, spi_m, _), + PIN(47, enet0, mtsif_alt, i2s_out, mtsif_alt1, arm_jtag, _, _, _), + PIN(48, sc0, usb_pwr, spdif_out, mtsif, _, _, _, _), + PIN(49, sc0, usb_pwr, aud_fs_clk0, mtsif, _, _, _, _), + PIN(50, sc0, usb_vbus, sc0, _, _, _, _, _), + PIN(51, sc0, enet0, sc0, sr_edm_sense, _, _, _, _), + PIN(52, sc0, enet0, vc_pwm1, _, _, _, _, _), + PIN(53, sc0, enet0_rgmii, ext_sc_clk, _, _, _, _, _), +}; + +static const struct bcm2712_pin_regs bcm2712_c0_gpio_pin_regs[] = +{ + GPIO_REGS(0, 0, 0, 7, 7), + GPIO_REGS(1, 0, 1, 7, 8), + GPIO_REGS(2, 0, 2, 7, 9), + GPIO_REGS(3, 0, 3, 7, 10), + GPIO_REGS(4, 0, 4, 7, 11), + GPIO_REGS(5, 0, 5, 7, 12), + GPIO_REGS(6, 0, 6, 7, 13), + GPIO_REGS(7, 0, 7, 7, 14), + GPIO_REGS(8, 1, 0, 8, 0), + GPIO_REGS(9, 1, 1, 8, 1), + GPIO_REGS(10, 1, 2, 8, 2), + GPIO_REGS(11, 1, 3, 8, 3), + GPIO_REGS(12, 1, 4, 8, 4), + GPIO_REGS(13, 1, 5, 8, 5), + GPIO_REGS(14, 1, 6, 8, 6), + GPIO_REGS(15, 1, 7, 8, 7), + GPIO_REGS(16, 2, 0, 8, 8), + GPIO_REGS(17, 2, 1, 8, 9), + GPIO_REGS(18, 2, 2, 8, 10), + GPIO_REGS(19, 2, 3, 8, 11), + GPIO_REGS(20, 2, 4, 8, 12), + GPIO_REGS(21, 2, 5, 8, 13), + GPIO_REGS(22, 2, 6, 8, 14), + GPIO_REGS(23, 2, 7, 9, 0), + GPIO_REGS(24, 3, 0, 9, 1), + GPIO_REGS(25, 3, 1, 9, 2), + GPIO_REGS(26, 3, 2, 9, 3), + GPIO_REGS(27, 3, 3, 9, 4), + GPIO_REGS(28, 3, 4, 9, 5), + GPIO_REGS(29, 3, 5, 9, 6), + GPIO_REGS(30, 3, 6, 9, 7), + GPIO_REGS(31, 3, 7, 9, 8), + GPIO_REGS(32, 4, 0, 9, 9), + GPIO_REGS(33, 4, 1, 9, 10), + GPIO_REGS(34, 4, 2, 9, 11), + GPIO_REGS(35, 4, 3, 9, 12), + GPIO_REGS(36, 4, 4, 9, 13), + GPIO_REGS(37, 4, 5, 9, 14), + GPIO_REGS(38, 4, 6, 10, 0), + GPIO_REGS(39, 4, 7, 10, 1), + GPIO_REGS(40, 5, 0, 10, 2), + GPIO_REGS(41, 5, 1, 10, 3), + GPIO_REGS(42, 5, 2, 10, 4), + GPIO_REGS(43, 5, 3, 10, 5), + GPIO_REGS(44, 5, 4, 10, 6), + GPIO_REGS(45, 5, 5, 10, 7), + GPIO_REGS(46, 5, 6, 10, 8), + GPIO_REGS(47, 5, 7, 10, 9), + GPIO_REGS(48, 6, 0, 10, 10), + GPIO_REGS(49, 6, 1, 10, 11), + GPIO_REGS(50, 6, 2, 10, 12), + GPIO_REGS(51, 6, 3, 10, 13), + GPIO_REGS(52, 6, 4, 10, 14), + GPIO_REGS(53, 6, 5, 11, 0), + EMMC_REGS(54, 11, 1), /* EMMC_CMD */ + EMMC_REGS(55, 11, 2), /* EMMC_DS */ + EMMC_REGS(56, 11, 3), /* EMMC_CLK */ + EMMC_REGS(57, 11, 4), /* EMMC_DAT0 */ + EMMC_REGS(58, 11, 5), /* EMMC_DAT1 */ + EMMC_REGS(59, 11, 6), /* EMMC_DAT2 */ + EMMC_REGS(60, 11, 7), /* EMMC_DAT3 */ + EMMC_REGS(61, 11, 8), /* EMMC_DAT4 */ + EMMC_REGS(62, 11, 9), /* EMMC_DAT5 */ + EMMC_REGS(63, 11, 10), /* EMMC_DAT6 */ + EMMC_REGS(64, 11, 11), /* EMMC_DAT7 */ +}; + +static struct bcm2712_pinctrl_soc_data bcm2712_c0_data = +{ + .num_pins = RT_ARRAY_SIZE(bcm2712_c0_gpio_pins), + .desc = bcm2712_c0_gpio_pins, + .funcs = bcm2712_c0_gpio_pin_funcs, + .regs = bcm2712_c0_gpio_pin_regs, +}; + +static struct bcm2712_pin_desc bcm2712_c0_aon_gpio_pins[] = +{ + AGPIO_PIN(0), + AGPIO_PIN(1), + AGPIO_PIN(2), + AGPIO_PIN(3), + AGPIO_PIN(4), + AGPIO_PIN(5), + AGPIO_PIN(6), + AGPIO_PIN(7), + AGPIO_PIN(8), + AGPIO_PIN(9), + AGPIO_PIN(10), + AGPIO_PIN(11), + AGPIO_PIN(12), + AGPIO_PIN(13), + AGPIO_PIN(14), + AGPIO_PIN(15), + AGPIO_PIN(16), + SGPIO_PIN(0), + SGPIO_PIN(1), + SGPIO_PIN(2), + SGPIO_PIN(3), + SGPIO_PIN(4), + SGPIO_PIN(5), +}; + +static const struct bcm2712_pin_funcs bcm2712_c0_aon_gpio_pin_funcs[] = +{ + PIN(0, ir_in, vc_spi0, vc_uart3, vc_i2c3, te0, vc_i2c0, _, _), + PIN(1, vc_pwm0, vc_spi0, vc_uart3, vc_i2c3, te1, aon_pwm, vc_i2c0, vc_pwm1), + PIN(2, vc_pwm0, vc_spi0, vc_uart3, ctl_hdmi_5v, fl0, aon_pwm, ir_in, vc_pwm1), + PIN(3, ir_in, vc_spi0, vc_uart3, aon_fp_4sec_resetb, fl1, sd_card_g, aon_gpclk, _), + PIN(4, gpclk0, vc_spi0, vc_i2csl, aon_gpclk, pm_led_out, aon_pwm, sd_card_g, vc_pwm0), + PIN(5, gpclk1, ir_in, vc_i2csl, clk_observe, aon_pwm, sd_card_g, vc_pwm0, _), + PIN(6, uart1, vc_uart4, gpclk2, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), + PIN(7, uart1, vc_uart4, gpclk0, aon_pwm, vc_uart0, vc_spi3, _, _), + PIN(8, uart1, vc_uart4, vc_i2csl, ctl_hdmi_5v, vc_uart0, vc_spi3, _, _), + PIN(9, uart1, vc_uart4, vc_i2csl, aon_pwm, vc_uart0, vc_spi3, _, _), + PIN(10, tsio, ctl_hdmi_5v, sc0, spdif_out, vc_spi5, usb_pwr, aon_gpclk, sd_card_f), + PIN(11, tsio, uart0, sc0, aud_fs_clk0, vc_spi5, usb_vbus, vc_uart2, sd_card_f), + PIN(12, tsio, uart0, vc_uart0, tsio, vc_spi5, usb_pwr, vc_uart2, sd_card_f), + PIN(13, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), + PIN(14, bsc_m1, uart0, vc_uart0, uui, vc_spi5, arm_jtag, vc_uart2, vc_i2c3), + PIN(15, ir_in, aon_fp_4sec_resetb, vc_uart0, pm_led_out, ctl_hdmi_5v, aon_pwm, aon_gpclk, _), + PIN(16, aon_cpu_standbyb, gpclk0, pm_led_out, ctl_hdmi_5v, vc_pwm0, usb_pwr, aud_fs_clk0, _), +}; + +static const struct bcm2712_pin_regs bcm2712_c0_aon_gpio_pin_regs[] = +{ + AGPIO_REGS(0, 3, 0, 6, 10), + AGPIO_REGS(1, 3, 1, 6, 11), + AGPIO_REGS(2, 3, 2, 6, 12), + AGPIO_REGS(3, 3, 3, 6, 13), + AGPIO_REGS(4, 3, 4, 6, 14), + AGPIO_REGS(5, 3, 5, 7, 0), + AGPIO_REGS(6, 3, 6, 7, 1), + AGPIO_REGS(7, 3, 7, 7, 2), + AGPIO_REGS(8, 4, 0, 7, 3), + AGPIO_REGS(9, 4, 1, 7, 4), + AGPIO_REGS(10, 4, 2, 7, 5), + AGPIO_REGS(11, 4, 3, 7, 6), + AGPIO_REGS(12, 4, 4, 7, 7), + AGPIO_REGS(13, 4, 5, 7, 8), + AGPIO_REGS(14, 4, 6, 7, 9), + AGPIO_REGS(15, 4, 7, 7, 10), + AGPIO_REGS(16, 5, 0, 7, 11), + SGPIO_REGS(0, 0, 0), + SGPIO_REGS(1, 0, 1), + SGPIO_REGS(2, 0, 2), + SGPIO_REGS(3, 0, 3), + SGPIO_REGS(4, 1, 0), + SGPIO_REGS(5, 2, 0), +}; + +static struct bcm2712_pinctrl_soc_data bcm2712_c0_aon_data = +{ + .num_pins = RT_ARRAY_SIZE(bcm2712_c0_aon_gpio_pins), + .desc = bcm2712_c0_aon_gpio_pins, + .funcs = bcm2712_c0_aon_gpio_pin_funcs, + .regs = bcm2712_c0_aon_gpio_pin_regs, +}; + +static const struct bcm2712_pin_desc bcm2712_d0_gpio_pins[] = +{ + GPIO_PIN(1), + GPIO_PIN(2), + GPIO_PIN(3), + GPIO_PIN(4), + GPIO_PIN(10), + GPIO_PIN(11), + GPIO_PIN(12), + GPIO_PIN(13), + GPIO_PIN(14), + GPIO_PIN(15), + GPIO_PIN(18), + GPIO_PIN(19), + GPIO_PIN(20), + GPIO_PIN(21), + GPIO_PIN(22), + GPIO_PIN(23), + GPIO_PIN(24), + GPIO_PIN(25), + GPIO_PIN(26), + GPIO_PIN(27), + GPIO_PIN(28), + GPIO_PIN(29), + GPIO_PIN(30), + GPIO_PIN(31), + GPIO_PIN(32), + GPIO_PIN(33), + GPIO_PIN(34), + GPIO_PIN(35), +}; + +static const struct bcm2712_pin_funcs bcm2712_d0_gpio_pin_funcs[] = +{ + PIN(1, vc_i2c0, usb_pwr, gpclk0, sd_card_e, vc_spi3, sr_edm_sense, vc_spi0, vc_uart0), + PIN(2, vc_i2c0, usb_pwr, gpclk1, sd_card_e, vc_spi3, clk_observe, vc_spi0, vc_uart0), + PIN(3, vc_i2c3, usb_vbus, gpclk2, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), + PIN(4, vc_i2c3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, vc_spi0, vc_uart0, _), + PIN(10, bsc_m3, vc_pwm1, vc_spi3, sd_card_e, vc_spi3, gpclk0, _, _), + PIN(11, bsc_m3, vc_spi3, clk_observe, sd_card_c, gpclk1, _, _, _), + PIN(12, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), + PIN(13, spi_s, vc_spi3, sd_card_c, sd_card_d, _, _, _, _), + PIN(14, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, sd_card_d, _, _), + PIN(15, spi_s, uui, arm_jtag, vc_pwm0, vc_i2c0, gpclk0, _, _), + PIN(18, sd_card_f, vc_pwm1, _, _, _, _, _, _), + PIN(19, sd_card_f, usb_pwr, vc_pwm1, _, _, _, _, _), + PIN(20, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), + PIN(21, vc_i2c3, uui, vc_uart0, arm_jtag, vc_uart2, _, _, _), + PIN(22, sd_card_f, vc_uart0, vc_i2c3, _, _, _, _, _), + PIN(23, vc_uart0, vc_i2c3, _, _, _, _, _, _), + PIN(24, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), + PIN(25, sd_card_b, vc_spi0, arm_jtag, uart0, usb_pwr, vc_uart2, vc_uart0, _), + PIN(26, sd_card_b, vc_spi0, arm_jtag, uart0, usb_vbus, vc_uart2, vc_spi0, _), + PIN(27, sd_card_b, vc_spi0, arm_jtag, uart0, vc_uart2, vc_spi0, _, _), + PIN(28, sd_card_b, vc_spi0, arm_jtag, vc_i2c0, vc_spi0, _, _, _), + PIN(29, arm_jtag, vc_i2c0, vc_spi0, _, _, _, _, _), + PIN(30, sd2, gpclk0, vc_pwm0, _, _, _, _, _), + PIN(31, sd2, vc_spi3, vc_pwm0, _, _, _, _, _), + PIN(32, sd2, vc_spi3, vc_uart3, _, _, _, _, _), + PIN(33, sd2, vc_spi3, vc_uart3, _, _, _, _, _), + PIN(34, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), + PIN(35, sd2, vc_spi3, vc_i2c5, _, _, _, _, _), +}; + +static const struct bcm2712_pin_regs bcm2712_d0_gpio_pin_regs[] = +{ + GPIO_REGS(1, 0, 0, 4, 5), + GPIO_REGS(2, 0, 1, 4, 6), + GPIO_REGS(3, 0, 2, 4, 7), + GPIO_REGS(4, 0, 3, 4, 8), + GPIO_REGS(10, 0, 4, 4, 9), + GPIO_REGS(11, 0, 5, 4, 10), + GPIO_REGS(12, 0, 6, 4, 11), + GPIO_REGS(13, 0, 7, 4, 12), + GPIO_REGS(14, 1, 0, 4, 13), + GPIO_REGS(15, 1, 1, 4, 14), + GPIO_REGS(18, 1, 2, 5, 0), + GPIO_REGS(19, 1, 3, 5, 1), + GPIO_REGS(20, 1, 4, 5, 2), + GPIO_REGS(21, 1, 5, 5, 3), + GPIO_REGS(22, 1, 6, 5, 4), + GPIO_REGS(23, 1, 7, 5, 5), + GPIO_REGS(24, 2, 0, 5, 6), + GPIO_REGS(25, 2, 1, 5, 7), + GPIO_REGS(26, 2, 2, 5, 8), + GPIO_REGS(27, 2, 3, 5, 9), + GPIO_REGS(28, 2, 4, 5, 10), + GPIO_REGS(29, 2, 5, 5, 11), + GPIO_REGS(30, 2, 6, 5, 12), + GPIO_REGS(31, 2, 7, 5, 13), + GPIO_REGS(32, 3, 0, 5, 14), + GPIO_REGS(33, 3, 1, 6, 0), + GPIO_REGS(34, 3, 2, 6, 1), + GPIO_REGS(35, 3, 3, 6, 2), +}; + +static struct bcm2712_pinctrl_soc_data bcm2712_d0_data = +{ + .num_pins = RT_ARRAY_SIZE(bcm2712_d0_gpio_pins), + .desc = bcm2712_d0_gpio_pins, + .funcs = bcm2712_d0_gpio_pin_funcs, + .regs = bcm2712_d0_gpio_pin_regs, +}; + +static struct bcm2712_pin_desc bcm2712_d0_aon_gpio_pins[] = +{ + AGPIO_PIN(0), + AGPIO_PIN(1), + AGPIO_PIN(2), + AGPIO_PIN(3), + AGPIO_PIN(4), + AGPIO_PIN(5), + AGPIO_PIN(6), + AGPIO_PIN(8), + AGPIO_PIN(9), + AGPIO_PIN(12), + AGPIO_PIN(13), + AGPIO_PIN(14), + SGPIO_PIN(0), + SGPIO_PIN(1), + SGPIO_PIN(2), + SGPIO_PIN(3), + SGPIO_PIN(4), + SGPIO_PIN(5), +}; + +static const struct bcm2712_pin_funcs bcm2712_d0_aon_gpio_pin_funcs[] = +{ + PIN(0, ir_in, vc_spi0, vc_uart0, vc_i2c3, uart0, vc_i2c0, _, _), + PIN(1, vc_pwm0, vc_spi0, vc_uart0, vc_i2c3, uart0, aon_pwm, vc_i2c0, vc_pwm1), + PIN(2, vc_pwm0, vc_spi0, vc_uart0, ctl_hdmi_5v, uart0, aon_pwm, ir_in, vc_pwm1), + PIN(3, ir_in, vc_spi0, vc_uart0, uart0, sd_card_g, aon_gpclk, _, _), + PIN(4, gpclk0, vc_spi0, pm_led_out, aon_pwm, sd_card_g, vc_pwm0, _, _), + PIN(5, gpclk1, ir_in, aon_pwm, sd_card_g, vc_pwm0, _, _, _), + PIN(6, uart1, vc_uart2, ctl_hdmi_5v, gpclk2, vc_spi3, _, _, _), + PIN(7, _, _, _, _, _, _, _, _), + PIN(8, uart1, vc_uart2, ctl_hdmi_5v, vc_spi0, vc_spi3, _, _, _), + PIN(9, uart1, vc_uart2, vc_uart0, aon_pwm, vc_spi0, vc_uart2, vc_spi3, _), + PIN(10, _, _, _, _, _, _, _, _), + PIN(11, _, _, _, _, _, _, _, _), + PIN(12, uart1, vc_uart2, vc_uart0, vc_spi0, usb_pwr, vc_uart2, vc_spi3, _), + PIN(13, bsc_m1, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3, _), + PIN(14, bsc_m1, aon_gpclk, vc_uart0, uui, vc_spi0, arm_jtag, vc_uart2, vc_i2c3), +}; + +static const struct bcm2712_pin_regs bcm2712_d0_aon_gpio_pin_regs[] = +{ + AGPIO_REGS(0, 3, 0, 5, 9), + AGPIO_REGS(1, 3, 1, 5, 10), + AGPIO_REGS(2, 3, 2, 5, 11), + AGPIO_REGS(3, 3, 3, 5, 12), + AGPIO_REGS(4, 3, 4, 5, 13), + AGPIO_REGS(5, 3, 5, 5, 14), + AGPIO_REGS(6, 3, 6, 6, 0), + AGPIO_REGS(8, 3, 7, 6, 1), + AGPIO_REGS(9, 4, 0, 6, 2), + AGPIO_REGS(12, 4, 1, 6, 3), + AGPIO_REGS(13, 4, 2, 6, 4), + AGPIO_REGS(14, 4, 3, 6, 5), + SGPIO_REGS(0, 0, 0), + SGPIO_REGS(1, 0, 1), + SGPIO_REGS(2, 0, 2), + SGPIO_REGS(3, 0, 3), + SGPIO_REGS(4, 1, 0), + SGPIO_REGS(5, 2, 0), +}; + +static struct bcm2712_pinctrl_soc_data bcm2712_d0_aon_data = +{ + .num_pins = RT_ARRAY_SIZE(bcm2712_d0_aon_gpio_pins), + .desc = bcm2712_d0_aon_gpio_pins, + .funcs = bcm2712_d0_aon_gpio_pin_funcs, + .regs = bcm2712_d0_aon_gpio_pin_regs, +}; + +static const struct rt_ofw_node_id bcm2712_pinctrl_ofw_ids[] = +{ + { .compatible = "brcm,bcm2712-pinctrl", .data = &bcm2712_c0_data }, + { .compatible = "brcm,bcm2712-aon-pinctrl", .data = &bcm2712_c0_aon_data }, + { .compatible = "brcm,bcm2712c0-pinctrl", .data = &bcm2712_c0_data }, + { .compatible = "brcm,bcm2712c0-aon-pinctrl", .data = &bcm2712_c0_aon_data }, + { .compatible = "brcm,bcm2712d0-pinctrl", .data = &bcm2712_d0_data }, + { .compatible = "brcm,bcm2712d0-aon-pinctrl", .data = &bcm2712_d0_aon_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2712_pinctrl_driver = +{ + .name = "pinctrl-bcm2712", + .ids = bcm2712_pinctrl_ofw_ids, + + .probe = bcm2712_pinctrl_probe, +}; + +static int bcm2712_pinctrl_register(void) +{ + rt_platform_driver_register(&bcm2712_pinctrl_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2712_pinctrl_register); diff --git a/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2835.c b/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2835.c new file mode 100755 index 0000000000..2e78c8d3a4 --- /dev/null +++ b/bsp/raspberry-pi/dm/pinctrl/pinctrl-bcm2835.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pinctrl.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +/* GPIO register offsets */ +#define GPFSEL0 0x0 /* Function Select */ +#define GPSET0 0x1c /* Pin Output Set */ +#define GPCLR0 0x28 /* Pin Output Clear */ +#define GPLEV0 0x34 /* Pin Level */ +#define GPEDS0 0x40 /* Pin Event Detect Status */ +#define GPREN0 0x4c /* Pin Rising Edge Detect Enable */ +#define GPFEN0 0x58 /* Pin Falling Edge Detect Enable */ +#define GPHEN0 0x64 /* Pin High Detect Enable */ +#define GPLEN0 0x70 /* Pin Low Detect Enable */ +#define GPAREN0 0x7c /* Pin Async Rising Edge Detect */ +#define GPAFEN0 0x88 /* Pin Async Falling Edge Detect */ +#define GPPUD 0x94 /* Pin Pull-up/down Enable */ +#define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */ +#define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */ + +#define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4)) +#define FSEL_SHIFT(p) (((p) % 10) * 3) +#define GPIO_REG_OFFSET(p) ((p) / 32) +#define GPIO_REG_SHIFT(p) ((p) % 32) + +#define PUD_2711_MASK 0x3 +#define PUD_2711_REG_OFFSET(p) ((p) / 16) +#define PUD_2711_REG_SHIFT(p) (((p) % 16) * 2) + +/* argument: bcm2835_pinconf_pull */ +#define BCM2835_PINCONF_PARAM_PULL (PIN_CONFIG_END + 1) + +#define BCM2835_NUM_GPIOS 54 +#define BCM2711_NUM_GPIOS 58 +#define BCM2835_NUM_BANKS 2 +#define BCM2835_NUM_IRQS 3 + +#define BCM2711_PULL_NONE 0x0 +#define BCM2711_PULL_UP 0x1 +#define BCM2711_PULL_DOWN 0x2 + +enum +{ + SOC_TYPE_BCM2835, + SOC_TYPE_BCM2711, + SOC_TYPE_BCM7211, +}; + +enum bcm2835_fsel +{ + BCM2835_FSEL_COUNT = 8, + BCM2835_FSEL_MASK = 0x7, +}; + +struct bcm2835_pinctrl_soc_data +{ + rt_uint32_t soc_type; + rt_uint32_t num_gpios; +}; + +struct bcm2835_pinctrl +{ + struct rt_device_pin parent; + const struct bcm2835_pinctrl_soc_data *soc_data; + + void *base; + int irqs[BCM2835_NUM_IRQS]; + + rt_bitmap_t enabled_irq_map[BCM2835_NUM_BANKS]; + rt_uint8_t irq_type[BCM2711_NUM_GPIOS]; + + struct rt_spinlock irq_lock[BCM2835_NUM_BANKS]; + struct rt_spinlock fsel_lock; /* Protect FSEL registers */ +}; + +#define raw_to_bcm2835_pinctrl(raw) rt_container_of(raw, struct bcm2835_pinctrl, parent) + +rt_inline rt_uint32_t bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, int reg) +{ + return HWREG32(pc->base + reg); +} + +rt_inline void bcm2835_gpio_wr(struct bcm2835_pinctrl *pc, int reg, rt_uint32_t val) +{ + HWREG32(pc->base + reg) = val; +} + +rt_inline int bcm2835_gpio_get_bit(struct bcm2835_pinctrl *pc, int reg, int bit) +{ + reg += GPIO_REG_OFFSET(bit) * 4; + return (bcm2835_gpio_rd(pc, reg) >> GPIO_REG_SHIFT(bit)) & 1; +} + +/* note NOT a read/modify/write cycle */ +rt_inline void bcm2835_gpio_set_bit(struct bcm2835_pinctrl *pc, int reg, int bit) +{ + reg += GPIO_REG_OFFSET(bit) * 4; + bcm2835_gpio_wr(pc, reg, RT_BIT(GPIO_REG_SHIFT(bit))); +} + +rt_inline enum bcm2835_fsel bcm2835_pinctrl_fsel_get(struct bcm2835_pinctrl *pc, + rt_ubase_t pin) +{ + rt_uint32_t val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); + + return (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; +} + +static void bcm2835_pinctrl_fsel_set(struct bcm2835_pinctrl *pc, rt_ubase_t pin, + enum bcm2835_fsel fsel) +{ + rt_uint32_t val; + rt_ubase_t level; + enum bcm2835_fsel cur; + + level = rt_spin_lock_irqsave(&pc->fsel_lock); + + val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); + cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; + + if (cur == fsel) + { + goto _out_lock; + } + + if (cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN) + { + /* Always transition through GPIO_IN */ + val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); + val |= BCM2835_FSEL_GPIO_IN << FSEL_SHIFT(pin); + + bcm2835_gpio_wr(pc, FSEL_REG(pin), val); + } + + val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin)); + val |= fsel << FSEL_SHIFT(pin); + + bcm2835_gpio_wr(pc, FSEL_REG(pin), val); + +_out_lock: + rt_spin_unlock_irqrestore(&pc->fsel_lock, level); +} + +static void bcm2835_gpio_irq_config_reg(struct bcm2835_pinctrl *pc, + int reg, int offset, rt_bool_t enable) +{ + rt_uint32_t value; + + reg += GPIO_REG_OFFSET(offset) * 4; + value = bcm2835_gpio_rd(pc, reg); + + if (enable) + { + value |= RT_BIT(GPIO_REG_SHIFT(offset)); + } + else + { + value &= ~(RT_BIT(GPIO_REG_SHIFT(offset))); + } + + bcm2835_gpio_wr(pc, reg, value); +} + +/* fast path for IRQ handler */ +static void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, int offset, rt_bool_t enable) +{ + switch (pc->irq_type[offset]) + { + case PIN_IRQ_MODE_RISING: + bcm2835_gpio_irq_config_reg(pc, GPREN0, offset, enable); + break; + + case PIN_IRQ_MODE_FALLING: + bcm2835_gpio_irq_config_reg(pc, GPFEN0, offset, enable); + break; + + case PIN_IRQ_MODE_RISING_FALLING: + bcm2835_gpio_irq_config_reg(pc, GPREN0, offset, enable); + bcm2835_gpio_irq_config_reg(pc, GPFEN0, offset, enable); + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + bcm2835_gpio_irq_config_reg(pc, GPHEN0, offset, enable); + break; + + case PIN_IRQ_MODE_LOW_LEVEL: + bcm2835_gpio_irq_config_reg(pc, GPLEN0, offset, enable); + break; + } +} + +static rt_err_t bcm2835_gpio_irq_set_type_enabled(struct bcm2835_pinctrl *pc, + int offset, rt_uint8_t type) +{ + switch (type) + { + case PIN_IRQ_MODE_RISING: + if (pc->irq_type[offset] == PIN_IRQ_MODE_RISING_FALLING) + { + /* RISING already enabled, disable FALLING */ + pc->irq_type[offset] = PIN_IRQ_MODE_FALLING; + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + } + else if (pc->irq_type[offset] != type) + { + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + } + break; + + case PIN_IRQ_MODE_FALLING: + if (pc->irq_type[offset] == PIN_IRQ_MODE_RISING_FALLING) + { + /* FALLING already enabled, disable RISING */ + pc->irq_type[offset] = PIN_IRQ_MODE_RISING; + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + } + else if (pc->irq_type[offset] != type) + { + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + } + break; + + case PIN_IRQ_MODE_RISING_FALLING: + if (pc->irq_type[offset] == PIN_IRQ_MODE_RISING) + { + /* RISING already enabled, enable FALLING too */ + pc->irq_type[offset] = PIN_IRQ_MODE_FALLING; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + pc->irq_type[offset] = type; + } + else if (pc->irq_type[offset] == PIN_IRQ_MODE_FALLING) + { + /* FALLING already enabled, enable RISING too */ + pc->irq_type[offset] = PIN_IRQ_MODE_RISING; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + pc->irq_type[offset] = type; + } + else if (pc->irq_type[offset] != type) + { + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + } + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + case PIN_IRQ_MODE_LOW_LEVEL: + if (pc->irq_type[offset] != type) + { + bcm2835_gpio_irq_config(pc, offset, RT_FALSE); + pc->irq_type[offset] = type; + bcm2835_gpio_irq_config(pc, offset, RT_TRUE); + } + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc, + int offset, rt_uint8_t type) +{ + switch (type) + { + case PIN_IRQ_MODE_RISING: + case PIN_IRQ_MODE_FALLING: + case PIN_IRQ_MODE_RISING_FALLING: + case PIN_IRQ_MODE_HIGH_LEVEL: + case PIN_IRQ_MODE_LOW_LEVEL: + pc->irq_type[offset] = type; + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc, int pin, rt_uint32_t arg) +{ + rt_uint32_t off, bit; + + off = GPIO_REG_OFFSET(pin); + bit = GPIO_REG_SHIFT(pin); + + bcm2835_gpio_wr(pc, GPPUD, arg & 3); + /* + * BCM2835 datasheet say to wait 150 cycles, but not of what. + * But the VideoCore firmware delay for this operation + * based nearly on the same amount of VPU cycles and this clock + * runs at 250 MHz. + */ + rt_hw_us_delay(1); + bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), RT_BIT(bit)); + rt_hw_us_delay(1); + bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0); +} + +static void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc, int pin, rt_uint32_t arg) +{ + rt_uint32_t shifter, value, off; + + off = PUD_2711_REG_OFFSET(pin); + shifter = PUD_2711_REG_SHIFT(pin); + + value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4)); + value &= ~(PUD_2711_MASK << shifter); + value |= (arg << shifter); + bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value); +} + +static void bcm2835_pinctrl_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + switch (mode) + { + case PIN_MODE_OUTPUT: + bcm2835_pinctrl_fsel_set(pc, pin, BCM2835_FSEL_GPIO_OUT); + break; + + case PIN_MODE_INPUT: + bcm2835_pinctrl_fsel_set(pc, pin, BCM2835_FSEL_GPIO_IN); + break; + + default: + break; + } +} + +static void bcm2835_pinctrl_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, pin); +} + +static rt_ssize_t bcm2835_pinctrl_read(struct rt_device *device, rt_base_t pin) +{ + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + return bcm2835_gpio_get_bit(pc, GPLEV0, pin); +} + +static rt_err_t bcm2835_pinctrl_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_ubase_t level; + rt_uint32_t offset, bank; + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + offset = GPIO_REG_SHIFT(pin); + bank = GPIO_REG_OFFSET(pin); + + level = rt_spin_lock_irqsave(&pc->irq_lock[bank]); + + if (enabled) + { + rt_bitmap_set_bit(&pc->enabled_irq_map[bank], offset); + bcm2835_gpio_irq_config(pc, pin, RT_TRUE); + } + else + { + bcm2835_gpio_irq_config(pc, pin, RT_FALSE); + /* Clear events that were latched prior to clearing event sources */ + bcm2835_gpio_set_bit(pc, GPEDS0, pin); + rt_bitmap_clear_bit(&pc->enabled_irq_map[bank], offset); + } + + rt_spin_unlock_irqrestore(&pc->irq_lock[bank], level); + + return RT_EOK; +} + +static rt_err_t bcm2835_pinctrl_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_err_t err; + rt_ubase_t level; + rt_uint32_t offset, bank; + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + offset = GPIO_REG_SHIFT(pin); + bank = GPIO_REG_OFFSET(pin); + + level = rt_spin_lock_irqsave(&pc->irq_lock[bank]); + + if (rt_bitmap_test_bit(&pc->enabled_irq_map[bank], offset)) + { + err = bcm2835_gpio_irq_set_type_enabled(pc, pin, mode); + } + else + { + err = bcm2835_gpio_irq_set_type_disabled(pc, pin, mode); + } + + rt_spin_unlock_irqrestore(&pc->irq_lock[bank], level); + + return err; +} + +static rt_err_t bcm2835_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + int pin; + rt_err_t err; + const fdt32_t *cell; + rt_uint32_t value, idx; + enum bcm2835_fsel fsel; + struct rt_ofw_prop *prop; + struct rt_ofw_node *conf_np = fw_conf_np; + struct bcm2835_pinctrl *pc = raw_to_bcm2835_pinctrl(device); + + if ((err = rt_ofw_prop_read_u32(conf_np, "brcm,function", &value))) + { + return err; + } + fsel = value; + + idx = 0; + rt_ofw_foreach_prop_u32(conf_np, "brcm,pins", prop, cell, value) + { + if (prop->length < sizeof(*cell)) + { + break; + } + + pin = value; + bcm2835_pinctrl_fsel_set(pc, pin, fsel); + + if (rt_ofw_prop_read_u32_index(conf_np, "brcm,pull", idx++, &value)) + { + continue; + } + + if (pc->soc_data->soc_type == SOC_TYPE_BCM2835) + { + bcm2835_pull_config_set(pc, pin, value); + } + else + { + bcm2711_pull_config_set(pc, pin, value); + } + } + + return RT_EOK; +} + +static const struct rt_pin_ops bcm2835_pinctrl_ops = +{ + .pin_mode = bcm2835_pinctrl_mode, + .pin_write = bcm2835_pinctrl_write, + .pin_read = bcm2835_pinctrl_read, + .pin_irq_enable = bcm2835_pinctrl_irq_enable, + .pin_irq_mode = bcm2835_pinctrl_irq_mode, + .pin_ctrl_confs_apply = bcm2835_pinctrl_confs_apply, +}; + +static void bcm2835_gpio_bank_isr(struct bcm2835_pinctrl *pc, int bank, rt_uint32_t mask) +{ + rt_ubase_t events; + rt_uint32_t offset, gpio, levs, levs2; + + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); + levs = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4); + events &= mask; + events &= pc->enabled_irq_map[bank]; + bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events); + +_retry: + rt_bitmap_for_each_set_bit(&events, offset, 32) + { + gpio = (32 * bank) + offset; + + pin_pic_handle_isr(&pc->parent, gpio); + } + + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); + levs2 = bcm2835_gpio_rd(pc, GPLEV0 + bank * 4); + + events |= levs2 & ~levs & bcm2835_gpio_rd(pc, GPREN0 + bank * 4); + events |= ~levs2 & levs & bcm2835_gpio_rd(pc, GPFEN0 + bank * 4); + events &= mask; + events &= pc->enabled_irq_map[bank]; + + if (events) + { + bcm2835_gpio_wr(pc, GPEDS0 + bank * 4, events); + levs = levs2; + goto _retry; + } +} + +static void bcm2835_pinctrl_isr(int irq, void *param) +{ + int group = 0; + struct bcm2835_pinctrl *pc = param; + + for (int i = 0; i < BCM2835_NUM_IRQS; ++i) + { + if (pc->irqs[i] == irq) + { + group = i; + break; + } + } + + switch (group) + { + case 0: /* IRQ0 covers GPIOs 0-27 */ + bcm2835_gpio_bank_isr(pc, 0, 0x0fffffff); + break; + + case 1: /* IRQ1 covers GPIOs 28-45 */ + bcm2835_gpio_bank_isr(pc, 0, 0xf0000000); + bcm2835_gpio_bank_isr(pc, 1, 0x00003fff); + break; + + case 2: /* IRQ2 covers GPIOs 46-57 */ + bcm2835_gpio_bank_isr(pc, 1, 0x003fc000); + break; + } +} + +static rt_err_t bcm2835_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + const struct bcm2835_pinctrl_soc_data *soc_data; + struct bcm2835_pinctrl *pc = rt_calloc(1, sizeof(*pc)); + + if (!pc) + { + return -RT_ENOMEM; + } + soc_data = pdev->id->data; + pc->soc_data = soc_data; + + if (!(pc->base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + rt_spin_lock_init(&pc->fsel_lock); + + for (int i = 0; i < BCM2835_NUM_BANKS; ++i) + { + int offset; + rt_ubase_t events; + + /* clear event detection flags */ + bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0); + bcm2835_gpio_wr(pc, GPFEN0 + i * 4, 0); + bcm2835_gpio_wr(pc, GPHEN0 + i * 4, 0); + bcm2835_gpio_wr(pc, GPLEN0 + i * 4, 0); + bcm2835_gpio_wr(pc, GPAREN0 + i * 4, 0); + bcm2835_gpio_wr(pc, GPAFEN0 + i * 4, 0); + + /* clear all the events */ + events = bcm2835_gpio_rd(pc, GPEDS0 + i * 4); + rt_bitmap_for_each_set_bit(&events, offset, 32) + { + bcm2835_gpio_wr(pc, GPEDS0 + i * 4, RT_BIT(offset)); + } + + rt_spin_lock_init(&pc->irq_lock[i]); + } + + pc->parent.ops = &bcm2835_pinctrl_ops; + pin_api_init(&pc->parent, soc_data->num_gpios); + pin_pic_init(&pc->parent, pc->irqs[0]); + + for (int i = 0; i < RT_ARRAY_SIZE(pc->irqs); ++i) + { + pc->irqs[i] = rt_dm_dev_get_irq(dev, i); + + if (soc_data->soc_type != SOC_TYPE_BCM7211) + { + if (pc->irqs[i] < 0) + { + break; + } + + continue; + } + else if (pc->irqs[i] < 0) + { + err = pc->irqs[i]; + goto _fail; + } + } + + for (int i = 0; i < RT_ARRAY_SIZE(pc->irqs); ++i) + { + int irq = pc->irqs[i]; + + if (irq < 0) + { + break; + } + + rt_hw_interrupt_install(irq, bcm2835_pinctrl_isr, pc, "bcm2835-pinctrl"); + rt_hw_interrupt_umask(irq); + } + + rt_ofw_data(np) = &pc->parent; + + return RT_EOK; + +_fail: + rt_free(pc); + + return err; +} + +static struct bcm2835_pinctrl_soc_data bcm2835_data = +{ + .soc_type = SOC_TYPE_BCM2835, + .num_gpios = BCM2835_NUM_GPIOS, +}; + +static struct bcm2835_pinctrl_soc_data bcm2711_data = +{ + .soc_type = SOC_TYPE_BCM2711, + .num_gpios = BCM2711_NUM_GPIOS, +}; + +static struct bcm2835_pinctrl_soc_data bcm7211_data = +{ + .soc_type = SOC_TYPE_BCM7211, + .num_gpios = BCM2711_NUM_GPIOS, +}; + +static const struct rt_ofw_node_id bcm2835_pinctrl_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-gpio", .data = &bcm2835_data }, + { .compatible = "brcm,bcm2711-gpio", .data = &bcm2711_data }, + { .compatible = "brcm,bcm7211-gpio", .data = &bcm7211_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_pinctrl_driver = +{ + .name = "pinctrl-bcm2835", + .ids = bcm2835_pinctrl_ofw_ids, + + .probe = bcm2835_pinctrl_probe, +}; + +static int bcm2835_pinctrl_register(void) +{ + rt_platform_driver_register(&bcm2835_pinctrl_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_pinctrl_register); diff --git a/bsp/raspberry-pi/dm/pinctrl/pinctrl-rp1.c b/bsp/raspberry-pi/dm/pinctrl/pinctrl-rp1.c new file mode 100755 index 0000000000..a829009de3 --- /dev/null +++ b/bsp/raspberry-pi/dm/pinctrl/pinctrl-rp1.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pinctrl.rp1" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#define RP1_NUM_GPIOS 54 +#define RP1_NUM_BANKS 3 + +#define RP1_RW_OFFSET 0x0000 +#define RP1_XOR_OFFSET 0x1000 +#define RP1_SET_OFFSET 0x2000 +#define RP1_CLR_OFFSET 0x3000 + +#define RP1_GPIO_STATUS 0x0000 +#define RP1_GPIO_CTRL 0x0004 + +#define RP1_GPIO_PCIE_INTE 0x011c +#define RP1_GPIO_PCIE_INTS 0x0124 + +#define RP1_GPIO_EVENTS_SHIFT_RAW 20 +#define RP1_GPIO_STATUS_FALLING RT_BIT(20) +#define RP1_GPIO_STATUS_RISING RT_BIT(21) +#define RP1_GPIO_STATUS_LOW RT_BIT(22) +#define RP1_GPIO_STATUS_HIGH RT_BIT(23) + +#define RP1_GPIO_EVENTS_SHIFT_FILTERED 24 +#define RP1_GPIO_STATUS_F_FALLING RT_BIT(24) +#define RP1_GPIO_STATUS_F_RISING RT_BIT(25) +#define RP1_GPIO_STATUS_F_LOW RT_BIT(26) +#define RP1_GPIO_STATUS_F_HIGH RT_BIT(27) + +#define RP1_GPIO_CTRL_FUNCSEL_LSB 0 +#define RP1_GPIO_CTRL_FUNCSEL_MASK 0x0000001f +#define RP1_GPIO_CTRL_OUTOVER_LSB 12 +#define RP1_GPIO_CTRL_OUTOVER_MASK 0x00003000 +#define RP1_GPIO_CTRL_OEOVER_LSB 14 +#define RP1_GPIO_CTRL_OEOVER_MASK 0x0000c000 +#define RP1_GPIO_CTRL_INOVER_LSB 16 +#define RP1_GPIO_CTRL_INOVER_MASK 0x00030000 +#define RP1_GPIO_CTRL_IRQEN_FALLING RT_BIT(20) +#define RP1_GPIO_CTRL_IRQEN_RISING RT_BIT(21) +#define RP1_GPIO_CTRL_IRQEN_LOW RT_BIT(22) +#define RP1_GPIO_CTRL_IRQEN_HIGH RT_BIT(23) +#define RP1_GPIO_CTRL_IRQEN_F_FALLING RT_BIT(24) +#define RP1_GPIO_CTRL_IRQEN_F_RISING RT_BIT(25) +#define RP1_GPIO_CTRL_IRQEN_F_LOW RT_BIT(26) +#define RP1_GPIO_CTRL_IRQEN_F_HIGH RT_BIT(27) +#define RP1_GPIO_CTRL_IRQRESET RT_BIT(28) +#define RP1_GPIO_CTRL_IRQOVER_LSB 30 +#define RP1_GPIO_CTRL_IRQOVER_MASK 0xc0000000 + +#define RP1_INT_EDGE_FALLING RT_BIT(0) +#define RP1_INT_EDGE_RISING RT_BIT(1) +#define RP1_INT_LEVEL_LOW RT_BIT(2) +#define RP1_INT_LEVEL_HIGH RT_BIT(3) +#define RP1_INT_MASK 0xf + +#define RP1_INT_EDGE_BOTH (RP1_INT_EDGE_FALLING | RP1_INT_EDGE_RISING) +#define RP1_PUD_OFF 0 +#define RP1_PUD_DOWN 1 +#define RP1_PUD_UP 2 + +#define RP1_FSEL_COUNT 9 + +#define RP1_FSEL_ALT0 0x00 +#define RP1_FSEL_GPIO 0x05 +#define RP1_FSEL_NONE 0x09 +#define RP1_FSEL_NONE_HW 0x1f + +#define RP1_DIR_OUTPUT 0 +#define RP1_DIR_INPUT 1 + +#define RP1_OUTOVER_PERI 0 +#define RP1_OUTOVER_INVPERI 1 +#define RP1_OUTOVER_LOW 2 +#define RP1_OUTOVER_HIGH 3 + +#define RP1_OEOVER_PERI 0 +#define RP1_OEOVER_INVPERI 1 +#define RP1_OEOVER_DISABLE 2 +#define RP1_OEOVER_ENABLE 3 + +#define RP1_INOVER_PERI 0 +#define RP1_INOVER_INVPERI 1 +#define RP1_INOVER_LOW 2 +#define RP1_INOVER_HIGH 3 + +#define RP1_RIO_OUT 0x00 +#define RP1_RIO_OE 0x04 +#define RP1_RIO_IN 0x08 + +#define RP1_PAD_SLEWFAST_MASK 0x00000001 +#define RP1_PAD_SLEWFAST_LSB 0 +#define RP1_PAD_SCHMITT_MASK 0x00000002 +#define RP1_PAD_SCHMITT_LSB 1 +#define RP1_PAD_PULL_MASK 0x0000000c +#define RP1_PAD_PULL_LSB 2 +#define RP1_PAD_DRIVE_MASK 0x00000030 +#define RP1_PAD_DRIVE_LSB 4 +#define RP1_PAD_IN_ENABLE_MASK 0x00000040 +#define RP1_PAD_IN_ENABLE_LSB 6 +#define RP1_PAD_OUT_DISABLE_MASK 0x00000080 +#define RP1_PAD_OUT_DISABLE_LSB 7 + +#define RP1_PAD_DRIVE_2MA 0x00000000 +#define RP1_PAD_DRIVE_4MA 0x00000010 +#define RP1_PAD_DRIVE_8MA 0x00000020 +#define RP1_PAD_DRIVE_12MA 0x00000030 + +#define FLD_GET(r, f) (((r) & (f ## _MASK)) >> (f ## _LSB)) +#define FLD_SET(r, f, v) r = (((r) & ~(f ## _MASK)) | ((v) << (f ## _LSB))) + +enum rp1_funcs +{ + func_alt0, + func_alt1, + func_alt2, + func_alt3, + func_alt4, + func_gpio, + func_alt6, + func_alt7, + func_alt8, + func_none, + func_aaud, + func_dcd0, + func_dpi, + func_dsi0_te_ext, + func_dsi1_te_ext, + func_dsr0, + func_dtr0, + func_gpclk0, + func_gpclk1, + func_gpclk2, + func_gpclk3, + func_gpclk4, + func_gpclk5, + func_i2c0, + func_i2c1, + func_i2c2, + func_i2c3, + func_i2c4, + func_i2c5, + func_i2c6, + func_i2s0, + func_i2s1, + func_i2s2, + func_ir, + func_mic, + func_pcie_clkreq_n, + func_pio, + func_proc_rio, + func_pwm0, + func_pwm1, + func_ri0, + func_sd0, + func_sd1, + func_spi0, + func_spi1, + func_spi2, + func_spi3, + func_spi4, + func_spi5, + func_spi6, + func_spi7, + func_spi8, + func_uart0, + func_uart1, + func_uart2, + func_uart3, + func_uart4, + func_uart5, + func_vbus0, + func_vbus1, + func_vbus2, + func_vbus3, + func__, + func_count = func__, +}; + +struct rp1_pin_funcs +{ +#define PIN(i, f0, f1, f2, f3, f4, f5, f6, f7, f8) \ + [i] = { \ + .funcs = { \ + func_##f0, \ + func_##f1, \ + func_##f2, \ + func_##f3, \ + func_##f4, \ + func_##f5, \ + func_##f6, \ + func_##f7, \ + func_##f8, \ + }, \ + } + rt_uint8_t funcs[RP1_FSEL_COUNT]; +}; + +struct rp1_pin_desc +{ + rt_uint32_t number; + const char *name; +}; + +struct rp1_iobank_desc +{ + int min_gpio; + int num_gpios; + int gpio_offset; + int inte_offset; + int ints_offset; + int rio_offset; + int pads_offset; +}; + +struct rp1_pinctrl; + +struct rp1_pin_info +{ + rt_uint8_t num; + rt_uint8_t bank; + rt_uint8_t offset; + rt_uint8_t fsel; + rt_uint8_t irq_type; + + void *gpio; + void *rio; + void *inte; + void *ints; + void *pad; +}; + +struct rp1_pinctrl +{ + struct rt_device_pin parent; + + void *gpio_base; + void *rio_base; + void *pads_base; + int irqs[RP1_NUM_BANKS]; + struct rp1_pin_info pins[RP1_NUM_GPIOS]; + struct rt_spinlock irq_lock[RP1_NUM_BANKS]; +}; + +#define raw_to_rp1_pinctrl(raw) rt_container_of(raw, struct rp1_pinctrl, parent) + +/* Pins are just named GPIO0..GPIO53 */ +static struct rp1_pin_desc rp1_gpio_pins[] = +{ +#define RP1_GPIO_PIN(a) { a, "gpio" #a } + RP1_GPIO_PIN(0), + RP1_GPIO_PIN(1), + RP1_GPIO_PIN(2), + RP1_GPIO_PIN(3), + RP1_GPIO_PIN(4), + RP1_GPIO_PIN(5), + RP1_GPIO_PIN(6), + RP1_GPIO_PIN(7), + RP1_GPIO_PIN(8), + RP1_GPIO_PIN(9), + RP1_GPIO_PIN(10), + RP1_GPIO_PIN(11), + RP1_GPIO_PIN(12), + RP1_GPIO_PIN(13), + RP1_GPIO_PIN(14), + RP1_GPIO_PIN(15), + RP1_GPIO_PIN(16), + RP1_GPIO_PIN(17), + RP1_GPIO_PIN(18), + RP1_GPIO_PIN(19), + RP1_GPIO_PIN(20), + RP1_GPIO_PIN(21), + RP1_GPIO_PIN(22), + RP1_GPIO_PIN(23), + RP1_GPIO_PIN(24), + RP1_GPIO_PIN(25), + RP1_GPIO_PIN(26), + RP1_GPIO_PIN(27), + RP1_GPIO_PIN(28), + RP1_GPIO_PIN(29), + RP1_GPIO_PIN(30), + RP1_GPIO_PIN(31), + RP1_GPIO_PIN(32), + RP1_GPIO_PIN(33), + RP1_GPIO_PIN(34), + RP1_GPIO_PIN(35), + RP1_GPIO_PIN(36), + RP1_GPIO_PIN(37), + RP1_GPIO_PIN(38), + RP1_GPIO_PIN(39), + RP1_GPIO_PIN(40), + RP1_GPIO_PIN(41), + RP1_GPIO_PIN(42), + RP1_GPIO_PIN(43), + RP1_GPIO_PIN(44), + RP1_GPIO_PIN(45), + RP1_GPIO_PIN(46), + RP1_GPIO_PIN(47), + RP1_GPIO_PIN(48), + RP1_GPIO_PIN(49), + RP1_GPIO_PIN(50), + RP1_GPIO_PIN(51), + RP1_GPIO_PIN(52), + RP1_GPIO_PIN(53), +#undef RP1_GPIO_PIN +}; + +static const char * const rp1_func_names[] = +{ +#define FUNC_NAME(name) [func_##name] = #name + FUNC_NAME(alt0), + FUNC_NAME(alt1), + FUNC_NAME(alt2), + FUNC_NAME(alt3), + FUNC_NAME(alt4), + FUNC_NAME(gpio), + FUNC_NAME(alt6), + FUNC_NAME(alt7), + FUNC_NAME(alt8), + FUNC_NAME(none), + FUNC_NAME(aaud), + FUNC_NAME(dcd0), + FUNC_NAME(dpi), + FUNC_NAME(dsi0_te_ext), + FUNC_NAME(dsi1_te_ext), + FUNC_NAME(dsr0), + FUNC_NAME(dtr0), + FUNC_NAME(gpclk0), + FUNC_NAME(gpclk1), + FUNC_NAME(gpclk2), + FUNC_NAME(gpclk3), + FUNC_NAME(gpclk4), + FUNC_NAME(gpclk5), + FUNC_NAME(i2c0), + FUNC_NAME(i2c1), + FUNC_NAME(i2c2), + FUNC_NAME(i2c3), + FUNC_NAME(i2c4), + FUNC_NAME(i2c5), + FUNC_NAME(i2c6), + FUNC_NAME(i2s0), + FUNC_NAME(i2s1), + FUNC_NAME(i2s2), + FUNC_NAME(ir), + FUNC_NAME(mic), + FUNC_NAME(pcie_clkreq_n), + FUNC_NAME(pio), + FUNC_NAME(proc_rio), + FUNC_NAME(pwm0), + FUNC_NAME(pwm1), + FUNC_NAME(ri0), + FUNC_NAME(sd0), + FUNC_NAME(sd1), + FUNC_NAME(spi0), + FUNC_NAME(spi1), + FUNC_NAME(spi2), + FUNC_NAME(spi3), + FUNC_NAME(spi4), + FUNC_NAME(spi5), + FUNC_NAME(spi6), + FUNC_NAME(spi7), + FUNC_NAME(spi8), + FUNC_NAME(uart0), + FUNC_NAME(uart1), + FUNC_NAME(uart2), + FUNC_NAME(uart3), + FUNC_NAME(uart4), + FUNC_NAME(uart5), + FUNC_NAME(vbus0), + FUNC_NAME(vbus1), + FUNC_NAME(vbus2), + FUNC_NAME(vbus3), +#undef FUNC_NAME +}; + +static const struct rp1_pin_funcs rp1_gpio_pin_funcs[] = +{ + PIN(0, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), + PIN(1, spi0, dpi, uart1, i2c0, _, gpio, proc_rio, pio, spi2), + PIN(2, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), + PIN(3, spi0, dpi, uart1, i2c1, ir, gpio, proc_rio, pio, spi2), + PIN(4, gpclk0, dpi, uart2, i2c2, ri0, gpio, proc_rio, pio, spi3), + PIN(5, gpclk1, dpi, uart2, i2c2, dtr0, gpio, proc_rio, pio, spi3), + PIN(6, gpclk2, dpi, uart2, i2c3, dcd0, gpio, proc_rio, pio, spi3), + PIN(7, spi0, dpi, uart2, i2c3, dsr0, gpio, proc_rio, pio, spi3), + PIN(8, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), + PIN(9, spi0, dpi, uart3, i2c0, _, gpio, proc_rio, pio, spi4), + PIN(10, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), + PIN(11, spi0, dpi, uart3, i2c1, _, gpio, proc_rio, pio, spi4), + PIN(12, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), + PIN(13, pwm0, dpi, uart4, i2c2, aaud, gpio, proc_rio, pio, spi5), + PIN(14, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), + PIN(15, pwm0, dpi, uart4, i2c3, uart0, gpio, proc_rio, pio, spi5), + PIN(16, spi1, dpi, dsi0_te_ext, _, uart0, gpio, proc_rio, pio, _), + PIN(17, spi1, dpi, dsi1_te_ext, _, uart0, gpio, proc_rio, pio, _), + PIN(18, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, gpclk1), + PIN(19, spi1, dpi, i2s0, pwm0, i2s1, gpio, proc_rio, pio, _), + PIN(20, spi1, dpi, i2s0, gpclk0, i2s1, gpio, proc_rio, pio, _), + PIN(21, spi1, dpi, i2s0, gpclk1, i2s1, gpio, proc_rio, pio, _), + PIN(22, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), + PIN(23, sd0, dpi, i2s0, i2c3, i2s1, gpio, proc_rio, pio, _), + PIN(24, sd0, dpi, i2s0, _, i2s1, gpio, proc_rio, pio, spi2), + PIN(25, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi3), + PIN(26, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi5), + PIN(27, sd0, dpi, i2s0, mic, i2s1, gpio, proc_rio, pio, spi1), + PIN(28, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), + PIN(29, sd1, i2c4, i2s2, spi6, vbus0, gpio, proc_rio, _, _), + PIN(30, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), + PIN(31, sd1, i2c5, i2s2, spi6, uart5, gpio, proc_rio, _, _), + PIN(32, sd1, gpclk3, i2s2, spi6, uart5, gpio, proc_rio, _, _), + PIN(33, sd1, gpclk4, i2s2, spi6, uart5, gpio, proc_rio, _, _), + PIN(34, pwm1, gpclk3, vbus0, i2c4, mic, gpio, proc_rio, _, _), + PIN(35, spi8, pwm1, vbus0, i2c4, mic, gpio, proc_rio, _, _), + PIN(36, spi8, uart5, pcie_clkreq_n, i2c5, mic, gpio, proc_rio, _, _), + PIN(37, spi8, uart5, mic, i2c5, pcie_clkreq_n, gpio, proc_rio, _, _), + PIN(38, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi0_te_ext, _), + PIN(39, spi8, uart5, mic, i2c6, aaud, gpio, proc_rio, dsi1_te_ext, _), + PIN(40, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), + PIN(41, pwm1, uart5, i2c4, spi6, aaud, gpio, proc_rio, _, _), + PIN(42, gpclk5, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), + PIN(43, gpclk4, uart5, vbus1, spi6, i2s2, gpio, proc_rio, _, _), + PIN(44, gpclk5, i2c5, pwm1, spi6, i2s2, gpio, proc_rio, _, _), + PIN(45, pwm1, i2c5, spi7, spi6, i2s2, gpio, proc_rio, _, _), + PIN(46, gpclk3, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi0_te_ext, _), + PIN(47, gpclk5, i2c4, spi7, mic, i2s2, gpio, proc_rio, dsi1_te_ext, _), + PIN(48, pwm1, pcie_clkreq_n, spi7, mic, uart5, gpio, proc_rio, _, _), + PIN(49, spi8, spi7, i2c5, aaud, uart5, gpio, proc_rio, _, _), + PIN(50, spi8, spi7, i2c5, aaud, vbus2, gpio, proc_rio, _, _), + PIN(51, spi8, spi7, i2c6, aaud, vbus2, gpio, proc_rio, _, _), + PIN(52, spi8, _, i2c6, aaud, vbus3, gpio, proc_rio, _, _), + PIN(53, spi8, spi7, _, pcie_clkreq_n, vbus3, gpio, proc_rio, _, _), +}; + +static const struct rp1_iobank_desc rp1_iobanks[RP1_NUM_BANKS] = +{ + /* gpio inte ints rio pads */ + { 0, 28, 0x0000, 0x011c, 0x0124, 0x0000, 0x0004 }, + { 28, 6, 0x4000, 0x411c, 0x4124, 0x4000, 0x4004 }, + { 34, 20, 0x8000, 0x811c, 0x8124, 0x8000, 0x8004 }, +}; + +static void rp1_pad_update(struct rp1_pin_info *pin, rt_uint32_t clr, rt_uint32_t set) +{ + rt_uint32_t padctrl = HWREG32(pin->pad); + + padctrl &= ~clr; + padctrl |= set; + + HWREG32(pin->pad) = padctrl; +} + +static void rp1_input_enable(struct rp1_pin_info *pin, int value) +{ + rp1_pad_update(pin, RP1_PAD_IN_ENABLE_MASK, value ? RP1_PAD_IN_ENABLE_MASK : 0); +} + +static void rp1_output_enable(struct rp1_pin_info *pin, int value) +{ + rp1_pad_update(pin, RP1_PAD_OUT_DISABLE_MASK, value ? 0 : RP1_PAD_OUT_DISABLE_MASK); +} + +static void rp1_set_fsel(struct rp1_pin_info *pin, rt_uint32_t fsel) +{ + rt_uint32_t ctrl = HWREG32(pin->gpio + RP1_GPIO_CTRL); + + if (fsel >= RP1_FSEL_COUNT) + { + fsel = RP1_FSEL_NONE_HW; + } + + rp1_input_enable(pin, 1); + rp1_output_enable(pin, 1); + + if (fsel == RP1_FSEL_NONE) + { + FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_DISABLE); + } + else + { + FLD_SET(ctrl, RP1_GPIO_CTRL_OUTOVER, RP1_OUTOVER_PERI); + FLD_SET(ctrl, RP1_GPIO_CTRL_OEOVER, RP1_OEOVER_PERI); + } + + FLD_SET(ctrl, RP1_GPIO_CTRL_FUNCSEL, fsel); + HWREG32(pin->gpio + RP1_GPIO_CTRL) = ctrl; +} + +static void rp1_pull_config_set(struct rp1_pin_info *pin, unsigned int arg) +{ + rt_uint32_t padctrl = HWREG32(pin->pad); + + FLD_SET(padctrl, RP1_PAD_PULL, arg & 0x3); + + HWREG32(pin->pad) = padctrl; +} + +static const struct rt_pin_ctrl_conf_params rp1_conf_params[] = +{ + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, +}; + +static rt_err_t rp1_pinctrl_confs_apply_once(struct rp1_pinctrl *pc, struct rt_ofw_node *np) +{ + rt_err_t err = RT_EOK; + const char *string; + rt_uint32_t pin, fsel, strength, slew; + struct rt_ofw_prop *prop; + struct rp1_pin_info *pini; + enum rp1_funcs func = func_count; + const struct rt_pin_ctrl_conf_params *conf = RT_NULL; + + if (rt_ofw_prop_read_string(np, "function", &string)) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rp1_func_names); ++i) + { + if (!rt_strcmp(string, rp1_func_names[i])) + { + func = (enum rp1_funcs)i; + break; + } + } + + if (func == func_count) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rp1_conf_params); ++i) + { + if (rt_ofw_prop_read_bool(np, rp1_conf_params[i].propname)) + { + conf = &rp1_conf_params[i]; + break; + } + } + + strength = RT_UINT32_MAX; + if (!rt_ofw_prop_read_u32(np, "drive-strength", &strength)) + { + switch (strength) + { + case 2: strength = RP1_PAD_DRIVE_2MA; break; + case 4: strength = RP1_PAD_DRIVE_4MA; break; + case 8: strength = RP1_PAD_DRIVE_8MA; break; + case 12: strength = RP1_PAD_DRIVE_12MA; break; + default: + return -RT_ENOSYS; + } + } + + slew = RT_UINT32_MAX; + rt_ofw_prop_read_u32(np, "slew-rate", &slew); + + rt_ofw_foreach_prop_string(np, "pins", prop, string) + { + pini = RT_NULL; + + for (int i = 0; i < RT_ARRAY_SIZE(rp1_gpio_pins); ++i) + { + if (!rt_strcmp(rp1_gpio_pins[i].name, string)) + { + pin = rp1_gpio_pins[i].number; + pini = &pc->pins[pin]; + break; + } + } + + if (!pini) + { + err = -RT_EINVAL; + break; + } + + /* IOMUX */ + for (fsel = 0; fsel < RP1_FSEL_COUNT; ++fsel) + { + if (func == rp1_gpio_pin_funcs[pin].funcs[fsel]) + { + break; + } + } + + if (fsel == RP1_FSEL_COUNT) + { + err = -RT_EINVAL; + break; + } + + rp1_set_fsel(pini, fsel); + + /* PULL */ + if (conf) + { + switch (conf->param) + { + case PIN_CONFIG_BIAS_DISABLE: + rp1_pull_config_set(pini, RP1_PUD_OFF); + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + rp1_pull_config_set(pini, RP1_PUD_DOWN); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + rp1_pull_config_set(pini, RP1_PUD_UP); + break; + + default: + err = -RT_ENOSYS; + break; + } + } + + if (strength != RT_UINT32_MAX) + { + rp1_pad_update(pini, RP1_PAD_DRIVE_MASK, strength); + } + + if (slew != RT_UINT32_MAX) + { + rp1_pad_update(pini, RP1_PAD_SLEWFAST_MASK, slew ? RP1_PAD_SLEWFAST_MASK : 0); + } + } + + return err; +} + +static void rp1_pinctrl_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + struct rp1_pin_info *pini = &pc->pins[pin]; + + switch (mode) + { + case PIN_MODE_OUTPUT: + HWREG32(pini->rio + RP1_RIO_OE + RP1_SET_OFFSET) = 1 << pini->offset; + rp1_set_fsel(pini, RP1_FSEL_GPIO); + break; + + case PIN_MODE_INPUT: + HWREG32(pini->rio + RP1_RIO_OE + RP1_CLR_OFFSET) = 1 << pini->offset; + rp1_set_fsel(pini, RP1_FSEL_GPIO); + break; + + default: + break; + } +} + +static void rp1_pinctrl_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + struct rp1_pin_info *pini = &pc->pins[pin]; + + /* Assume the pin is already an output */ + HWREG32(pini->rio + RP1_RIO_OUT + (value ? RP1_SET_OFFSET : RP1_CLR_OFFSET)) = + 1 << pini->offset; +} + +static rt_ssize_t rp1_pinctrl_read(struct rt_device *device, rt_base_t pin) +{ + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + struct rp1_pin_info *pini = &pc->pins[pin]; + + return !!(HWREG32(pini->rio + RP1_RIO_IN) & (1 << pini->offset)); +} + +static rt_err_t rp1_pinctrl_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + struct rp1_pin_info *pini = &pc->pins[pin]; + + HWREG32(pini->inte + (enabled ? RP1_SET_OFFSET : RP1_CLR_OFFSET)) = 1 << pini->offset; + + if (!enabled) + { + /* Clear any latched events */ + HWREG32(pini->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL) = RP1_GPIO_CTRL_IRQRESET; + } + + return RT_EOK; +} + +static rt_err_t rp1_pinctrl_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_ubase_t level; + rt_uint32_t irq_flags; + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + struct rp1_pin_info *pini = &pc->pins[pin]; + + level = rt_spin_lock_irqsave(&pc->irq_lock[pini->bank]); + + switch (mode) + { + case PIN_IRQ_MODE_RISING: + irq_flags = RP1_INT_EDGE_RISING; + break; + + case PIN_IRQ_MODE_FALLING: + irq_flags = RP1_INT_EDGE_FALLING; + break; + + case PIN_IRQ_MODE_RISING_FALLING: + irq_flags = RP1_INT_EDGE_RISING | RP1_INT_EDGE_FALLING; + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + irq_flags = RP1_INT_LEVEL_HIGH; + break; + + case PIN_IRQ_MODE_LOW_LEVEL: + irq_flags = RP1_INT_LEVEL_LOW; + break; + + default: + rt_spin_unlock_irqrestore(&pc->irq_lock[pini->bank], level); + return -RT_EINVAL; + } + + /* Clear them all */ + HWREG32(pini->gpio + RP1_CLR_OFFSET + RP1_GPIO_CTRL) = + RP1_INT_MASK << RP1_GPIO_EVENTS_SHIFT_RAW; + + /* Set those that are needed */ + HWREG32(pini->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL) = + irq_flags << RP1_GPIO_EVENTS_SHIFT_RAW; + + pini->irq_type = mode; + + rt_spin_unlock_irqrestore(&pc->irq_lock[pini->bank], level); + + return RT_EOK; +} + +static rt_err_t rp1_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + rt_err_t err; + rt_bool_t stage2 = RT_FALSE; + struct rt_ofw_node *conf_np = fw_conf_np, *child; + struct rp1_pinctrl *pc = raw_to_rp1_pinctrl(device); + + rt_ofw_foreach_child_node(conf_np, child) + { + stage2 = RT_TRUE; + + if ((err = rp1_pinctrl_confs_apply_once(pc, child))) + { + return err; + } + } + + if (!stage2) + { + err = rp1_pinctrl_confs_apply_once(pc, conf_np); + } + + return err; +} + +static const struct rt_pin_ops rp1_pinctrl_ops = +{ + .pin_mode = rp1_pinctrl_mode, + .pin_write = rp1_pinctrl_write, + .pin_read = rp1_pinctrl_read, + .pin_irq_enable = rp1_pinctrl_irq_enable, + .pin_irq_mode = rp1_pinctrl_irq_mode, + .pin_ctrl_confs_apply = rp1_pinctrl_confs_apply, +}; + +static void rp1_pinctrl_isr(int irq, void *param) +{ + rt_ubase_t pin; + rt_bitmap_t ints; + struct rp1_pin_info *pini; + struct rp1_pinctrl *pc = param; + const struct rp1_iobank_desc *bank; + + if (pc->irqs[0] == irq) + { + bank = &rp1_iobanks[0]; + } + else if (pc->irqs[1] == irq) + { + bank = &rp1_iobanks[1]; + } + else + { + bank = &rp1_iobanks[2]; + } + + ints = HWREG32(pc->gpio_base + bank->ints_offset); + + rt_bitmap_for_each_set_bit(&ints, pin, 32) + { + pini = &pc->pins[pin]; + + /* Clear any latched events */ + HWREG32(pini->gpio + RP1_SET_OFFSET + RP1_GPIO_CTRL) = RP1_GPIO_CTRL_IRQRESET; + + pin_pic_handle_isr(&pc->parent, pin); + } +} + +static rt_err_t rp1_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rp1_pinctrl *pc = rt_calloc(1, sizeof(*pc)); + + if (!pc) + { + return -RT_ENOMEM; + } + + if (!(pc->gpio_base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(pc->rio_base = rt_dm_dev_iomap(dev, 1))) + { + err = -RT_EIO; + goto _fail; + } + + if (!(pc->pads_base = rt_dm_dev_iomap(dev, 2))) + { + err = -RT_EIO; + goto _fail; + } + + for (int i = 0; i < RP1_NUM_BANKS; ++i) + { + const struct rp1_iobank_desc *bank = &rp1_iobanks[i]; + + for (int j = 0; j < bank->num_gpios; ++j) + { + struct rp1_pin_info *pini = &pc->pins[bank->min_gpio + j]; + + pini->num = bank->min_gpio + j; + pini->bank = i; + pini->offset = j; + + pini->gpio = pc->gpio_base + bank->gpio_offset + j * sizeof(rt_uint32_t) * 2; + pini->inte = pc->gpio_base + bank->inte_offset; + pini->ints = pc->gpio_base + bank->ints_offset; + pini->rio = pc->rio_base + bank->rio_offset; + pini->pad = pc->pads_base + bank->pads_offset + j * sizeof(rt_uint32_t); + } + + rt_spin_lock_init(&pc->irq_lock[i]); + } + + for (int i = 0; i < RP1_NUM_BANKS; ++i) + { + int irq = rt_dm_dev_get_irq(dev, i); + + pc->irqs[i] = irq; + + if (irq < 0) + { + break; + } + + rt_hw_interrupt_install(irq, rp1_pinctrl_isr, pc, "rp1-pinctrl"); + rt_hw_interrupt_umask(irq); + } + + pc->parent.ops = pdev->id->data; + pin_api_init(&pc->parent, RP1_NUM_GPIOS); + pin_pic_init(&pc->parent, pc->irqs[0]); + + rt_ofw_data(dev->ofw_node) = &pc->parent; + + return RT_EOK; + +_fail: + rt_free(pc); + + return err; +} + +static const struct rt_ofw_node_id rp1_pinctrl_ofw_ids[] = +{ + { .compatible = "raspberrypi,rp1-gpio", .data = &rp1_pinctrl_ops }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rp1_pinctrl_driver = +{ + .name = "pinctrl-rp1", + .ids = rp1_pinctrl_ofw_ids, + + .probe = rp1_pinctrl_probe, +}; + +static int rp1_pinctrl_register(void) +{ + rt_platform_driver_register(&rp1_pinctrl_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rp1_pinctrl_register); diff --git a/bsp/raspberry-pi/dm/pmdomain/Kconfig b/bsp/raspberry-pi/dm/pmdomain/Kconfig new file mode 100755 index 0000000000..84a3539851 --- /dev/null +++ b/bsp/raspberry-pi/dm/pmdomain/Kconfig @@ -0,0 +1,8 @@ +config RT_PMDOMAIN_BCM2835 + bool "BCM2835" + depends on RT_USING_RESET + default n + +config RT_PMDOMAIN_RASPBERRYPI + bool "Raspberrypi" + default n diff --git a/bsp/raspberry-pi/dm/pmdomain/SConscript b/bsp/raspberry-pi/dm/pmdomain/SConscript new file mode 100755 index 0000000000..fdfe8e0739 --- /dev/null +++ b/bsp/raspberry-pi/dm/pmdomain/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PMDOMAIN_BCM2835']): + src += ['pm-domain-bcm2835.c'] + +if GetDepend(['RT_PMDOMAIN_RASPBERRYPI']): + src += ['pm-domain-raspberrypi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pmdomain/pm-domain-bcm2835.c b/bsp/raspberry-pi/dm/pmdomain/pm-domain-bcm2835.c new file mode 100755 index 0000000000..a4c821b963 --- /dev/null +++ b/bsp/raspberry-pi/dm/pmdomain/pm-domain-bcm2835.c @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pm-domain.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +#define PM_GNRIC 0x00 +#define PM_AUDIO 0x04 +#define PM_STATUS 0x18 +#define PM_RSTC 0x1c +#define PM_RSTS 0x20 +#define PM_WDOG 0x24 +#define PM_PADS0 0x28 +#define PM_PADS2 0x2c +#define PM_PADS3 0x30 +#define PM_PADS4 0x34 +#define PM_PADS5 0x38 +#define PM_PADS6 0x3c +#define PM_CAM0 0x44 +#define PM_CAM0_LDOHPEN RT_BIT(2) +#define PM_CAM0_LDOLPEN RT_BIT(1) +#define PM_CAM0_CTRLEN RT_BIT(0) + +#define PM_CAM1 0x48 +#define PM_CAM1_LDOHPEN RT_BIT(2) +#define PM_CAM1_LDOLPEN RT_BIT(1) +#define PM_CAM1_CTRLEN RT_BIT(0) + +#define PM_CCP2TX 0x4c +#define PM_CCP2TX_LDOEN RT_BIT(1) +#define PM_CCP2TX_CTRLEN RT_BIT(0) + +#define PM_DSI0 0x50 +#define PM_DSI0_LDOHPEN RT_BIT(2) +#define PM_DSI0_LDOLPEN RT_BIT(1) +#define PM_DSI0_CTRLEN RT_BIT(0) + +#define PM_DSI1 0x54 +#define PM_DSI1_LDOHPEN RT_BIT(2) +#define PM_DSI1_LDOLPEN RT_BIT(1) +#define PM_DSI1_CTRLEN RT_BIT(0) + +#define PM_HDMI 0x58 +#define PM_HDMI_RSTDR RT_BIT(19) +#define PM_HDMI_LDOPD RT_BIT(1) +#define PM_HDMI_CTRLEN RT_BIT(0) + +#define PM_USB 0x5c +/* + * The power gates must be enabled with this bit before enabling the LDO in the + * USB block. + */ +#define PM_USB_CTRLEN RT_BIT(0) + +#define PM_PXLDO 0x60 +#define PM_PXBG 0x64 +#define PM_DFT 0x68 +#define PM_SMPS 0x6c +#define PM_XOSC 0x70 +#define PM_SPAREW 0x74 +#define PM_SPARER 0x78 +#define PM_AVS_RSTDR 0x7c +#define PM_AVS_STAT 0x80 +#define PM_AVS_EVENT 0x84 +#define PM_AVS_INTEN 0x88 +#define PM_DUMMY 0xfc + +#define PM_IMAGE 0x108 +#define PM_GRAFX 0x10c +#define PM_PROC 0x110 +#define PM_GRAFX_2712 0x304 +#define PM_ENAB RT_BIT(12) +#define PM_ISPRSTN RT_BIT(8) +#define PM_H264RSTN RT_BIT(7) +#define PM_PERIRSTN RT_BIT(6) +#define PM_V3DRSTN RT_BIT(6) +#define PM_ISFUNC RT_BIT(5) +#define PM_MRDONE RT_BIT(4) +#define PM_MEMREP RT_BIT(3) +#define PM_ISPOW RT_BIT(2) +#define PM_POWOK RT_BIT(1) +#define PM_POWUP RT_BIT(0) +#define PM_INRUSH_SHIFT 13 +#define PM_INRUSH_3_5_MA 0 +#define PM_INRUSH_5_MA 1 +#define PM_INRUSH_10_MA 2 +#define PM_INRUSH_20_MA 3 +#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT) + +#define PM_PASSWORD 0x5a000000 + +#define PM_WDOG_TIME_SET 0x000fffff +#define PM_RSTC_WRCFG_CLR 0xffffffcf +#define PM_RSTS_HADWRH_SET 0x00000040 +#define PM_RSTC_WRCFG_SET 0x00000030 +#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTC_RESET 0x00000102 + +#define PM_READ(reg) HWREG32(power->base + (reg)) +#define PM_WRITE(reg, val) HWREG32(power->base + (reg)) = PM_PASSWORD | (val) + +#define ASB_BRDG_VERSION 0x00 +#define ASB_CPR_CTRL 0x04 + +#define ASB_V3D_S_CTRL 0x08 +#define ASB_V3D_M_CTRL 0x0c +#define ASB_ISP_S_CTRL 0x10 +#define ASB_ISP_M_CTRL 0x14 +#define ASB_H264_S_CTRL 0x18 +#define ASB_H264_M_CTRL 0x1c + +#define ASB_REQ_STOP RT_BIT(0) +#define ASB_ACK RT_BIT(1) +#define ASB_EMPTY RT_BIT(2) +#define ASB_FULL RT_BIT(3) + +#define ASB_AXI_BRDG_ID 0x20 + +#define BCM2835_BRDG_ID 0x62726467 + +struct bcm2835_power; + +struct bcm2835_power_domain +{ + struct rt_dm_power_domain parent; + const char *name; + + rt_uint32_t domain; + struct rt_clk *clk; + struct bcm2835_power *power; +}; + +#define raw_to_rpi_bcm2835_power_domain(raw) rt_container_of(raw, struct bcm2835_power_domain, parent) + +struct bcm2835_power +{ + struct rt_dm_power_domain_proxy proxy_parent; + struct rt_reset_controller rstc_parent; + + void *base; /* PM registers. */ + void *asb; /* AXI Async bridge registers. */ + void *rpivid_asb; /* RPiVid bridge registers. */ + + struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; +}; + +#define raw_to_bcm2835_power(raw) rt_container_of(raw, struct bcm2835_power, proxy_parent) + +static rt_err_t bcm2835_asb_control(struct bcm2835_power *power, int reg, rt_bool_t enable) +{ + rt_uint32_t val; + rt_bool_t timeout; + void *base = power->asb; + + switch (reg) + { + case 0: + return RT_EOK; + + case ASB_V3D_S_CTRL: + case ASB_V3D_M_CTRL: + if (power->rpivid_asb) + { + base = power->rpivid_asb; + } + break; + + default: + return -RT_EINVAL; + } + + timeout = RT_FALSE; + + /* Enable the module's async AXI bridges. */ + if (enable) + { + val = HWREG32(base + reg) & ~ASB_REQ_STOP; + } + else + { + val = HWREG32(base + reg) | ASB_REQ_STOP; + } + + HWREG32(base + reg) = PM_PASSWORD | val; + + while (!!(HWREG32(base + reg) & ASB_ACK) == enable) + { + if (timeout) + { + return -RT_ETIMEOUT; + } + + rt_hw_us_delay(1); + timeout = RT_TRUE; + + rt_hw_cpu_relax(); + } + + return RT_EOK; +} + +static rt_err_t bcm2835_asb_enable(struct bcm2835_power *power, int reg) +{ + return bcm2835_asb_control(power, reg, RT_TRUE); +} + +static rt_err_t bcm2835_asb_disable(struct bcm2835_power *power, int reg) +{ + return bcm2835_asb_control(power, reg, RT_FALSE); +} + +static rt_err_t bcm2835_power_power_off(struct bcm2835_power_domain *pd, int pm_reg) +{ + struct bcm2835_power *power = pd->power; + + /* We don't run this on BCM2711 */ + if (power->rpivid_asb) + { + return RT_EOK; + } + + /* Enable functional isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); + + /* Enable electrical isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); + + /* Open the power switches. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP); + + return RT_EOK; +} + +static rt_err_t bcm2835_power_power_on(struct bcm2835_power_domain *pd, rt_uint32_t pm_reg) +{ + rt_err_t err; + int inrush; + rt_bool_t powok, timeout; + struct bcm2835_power *power = pd->power; + + /* We don't run this on BCM2711 */ + if (power->rpivid_asb) + { + return RT_EOK; + } + + /* If it was already powered on by the fw, leave it that way. */ + if (PM_READ(pm_reg) & PM_POWUP) + { + return RT_EOK; + } + + /* + * Enable power. Allowing too much current at once may result + * in POWOK never getting set, so start low and ramp it up as + * necessary to succeed. + */ + powok = RT_FALSE; + for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; ++inrush) + { + PM_WRITE(pm_reg, (PM_READ(pm_reg) & ~PM_INRUSH_MASK) | + (inrush << PM_INRUSH_SHIFT) | PM_POWUP); + + for (int i = 0; i < 3; ++i) + { + if ((powok = !!(PM_READ(pm_reg) & PM_POWOK))) + { + break; + } + + rt_hw_us_delay(1); + rt_hw_cpu_relax(); + } + } + + if (!powok) + { + LOG_E("Timeout waiting for %s power OK", pd->name); + + err = -RT_ETIMEOUT; + goto _err_disable_powup; + } + + /* Disable electrical isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW); + + /* Repair memory */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP); + + timeout = RT_FALSE; + while (!(PM_READ(pm_reg) & PM_MRDONE)) + { + if (timeout) + { + LOG_E("Timeout waiting for %s memory repair", pd->name); + + err = -RT_ETIMEOUT; + goto _err_disable_ispow; + } + + rt_hw_us_delay(1); + timeout = RT_TRUE; + + rt_hw_cpu_relax(); + } + + /* Disable functional isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC); + + return RT_EOK; + +_err_disable_ispow: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); + +_err_disable_powup: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK)); + + return err; +} + +static rt_err_t bcm2835_asb_power_on(struct bcm2835_power_domain *pd, + rt_uint32_t pm_reg, rt_uint32_t asb_m_reg, + rt_uint32_t asb_s_reg, rt_uint32_t reset_flags) +{ + rt_err_t err; + struct bcm2835_power *power = pd->power; + + if ((err = rt_clk_prepare_enable(pd->clk))) + { + LOG_E("Failed to enable clock for %s", pd->name); + return err; + } + + /* Wait 32 clocks for reset to propagate, 1 us will be enough */ + rt_hw_us_delay(1); + + rt_clk_disable_unprepare(pd->clk); + + /* Deassert the resets. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags); + + if ((err = rt_clk_prepare_enable(pd->clk))) + { + LOG_E("Failed to enable clock for %s", pd->name); + goto _err_enable_resets; + } + + if ((err = bcm2835_asb_enable(power, asb_m_reg))) + { + LOG_E("Failed to enable ASB master for %s", pd->name); + goto _err_disable_clk; + } + + if ((err = bcm2835_asb_enable(power, asb_s_reg))) + { + LOG_E("Failed to enable ASB slave for %s", pd->name); + goto _err_disable_asb_master; + } + + return RT_EOK; + +_err_disable_asb_master: + bcm2835_asb_disable(power, asb_m_reg); + +_err_disable_clk: + rt_clk_disable_unprepare(pd->clk); + +_err_enable_resets: + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); + + return err; +} + +static rt_err_t bcm2835_asb_power_off(struct bcm2835_power_domain *pd, + rt_uint32_t pm_reg, rt_uint32_t asb_m_reg, + rt_uint32_t asb_s_reg, rt_uint32_t reset_flags) +{ + rt_err_t err; + struct bcm2835_power *power = pd->power; + + if ((err = bcm2835_asb_disable(power, asb_s_reg))) + { + LOG_W("Failed to disable ASB slave for %s", pd->name); + + return err; + } + + if ((err = bcm2835_asb_disable(power, asb_m_reg))) + { + LOG_W("Failed to disable ASB master for %s", pd->name); + bcm2835_asb_enable(power, asb_s_reg); + + return err; + } + + rt_clk_disable_unprepare(pd->clk); + + /* Assert the resets. */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); + + return 0; +} + +static rt_err_t bcm2835_power_pd_power_on(struct rt_dm_power_domain *domain) +{ + struct bcm2835_power_domain *pd = raw_to_rpi_bcm2835_power_domain(domain); + struct bcm2835_power *power = pd->power; + + switch (pd->domain) + { + case BCM2835_POWER_DOMAIN_GRAFX: + return bcm2835_power_power_on(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: + if (!power->asb) + { + return bcm2835_asb_power_on(pd, PM_GRAFX_2712, 0, 0, PM_V3DRSTN); + } + return bcm2835_asb_power_on(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, PM_V3DRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE: + return bcm2835_power_power_on(pd, PM_IMAGE); + + case BCM2835_POWER_DOMAIN_IMAGE_PERI: + return bcm2835_asb_power_on(pd, PM_IMAGE, 0, 0, PM_PERIRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_ISP: + return bcm2835_asb_power_on(pd, PM_IMAGE, + ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, PM_ISPRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_H264: + return bcm2835_asb_power_on(pd, PM_IMAGE, + ASB_H264_M_CTRL, ASB_H264_S_CTRL, PM_H264RSTN); + + case BCM2835_POWER_DOMAIN_USB: + PM_WRITE(PM_USB, PM_USB_CTRLEN); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_DSI0: + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_DSI1: + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_CCP2TX: + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_HDMI: + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD); + + rt_hw_us_delay(150); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR); + return RT_EOK; + + default: + LOG_E("Invalid domain %d", pd->domain); + + return -RT_EINVAL; + } +} + +static rt_err_t bcm2835_power_pd_power_off(struct rt_dm_power_domain *domain) +{ + struct bcm2835_power_domain *pd = raw_to_rpi_bcm2835_power_domain(domain); + struct bcm2835_power *power = pd->power; + + switch (pd->domain) + { + case BCM2835_POWER_DOMAIN_GRAFX: + return bcm2835_power_power_off(pd, PM_GRAFX); + + case BCM2835_POWER_DOMAIN_GRAFX_V3D: + if (!power->asb) + { + return bcm2835_asb_power_off(pd, PM_GRAFX_2712, 0, 0, PM_V3DRSTN); + } + return bcm2835_asb_power_off(pd, PM_GRAFX, + ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, PM_V3DRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE: + return bcm2835_power_power_off(pd, PM_IMAGE); + + case BCM2835_POWER_DOMAIN_IMAGE_PERI: + return bcm2835_asb_power_off(pd, PM_IMAGE, 0, 0, PM_PERIRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_ISP: + return bcm2835_asb_power_off(pd, PM_IMAGE, + ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, PM_ISPRSTN); + + case BCM2835_POWER_DOMAIN_IMAGE_H264: + return bcm2835_asb_power_off(pd, PM_IMAGE, + ASB_H264_M_CTRL, ASB_H264_S_CTRL, PM_H264RSTN); + + case BCM2835_POWER_DOMAIN_USB: + PM_WRITE(PM_USB, 0); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_DSI0: + PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); + PM_WRITE(PM_DSI0, 0); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_DSI1: + PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); + PM_WRITE(PM_DSI1, 0); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_CCP2TX: + PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); + PM_WRITE(PM_CCP2TX, 0); + return RT_EOK; + + case BCM2835_POWER_DOMAIN_HDMI: + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD); + PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN); + return RT_EOK; + + default: + LOG_E("Invalid domain %d", pd->domain); + + return -RT_EINVAL; + } +} + +static struct rt_dm_power_domain *bcm2835_power_domains_ofw_parse( + struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args) +{ + struct bcm2835_power *power = raw_to_bcm2835_power(proxy); + + return &power->domains[args->args[0]].parent; +} + +static rt_err_t bcm2835_reset_reset(struct rt_reset_control *rstc) +{ + rt_err_t err; + struct bcm2835_power_domain *pd; + struct bcm2835_power *power = rstc->rstcer->priv; + + switch (rstc->id) + { + case BCM2835_RESET_V3D: + pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D]; + break; + + case BCM2835_RESET_H264: + pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264]; + break; + + case BCM2835_RESET_ISP: + pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP]; + break; + + default: + LOG_E("Invalid reset id %u", rstc->id); + return -RT_EINVAL; + } + + if ((err = bcm2835_power_pd_power_off(&pd->parent))) + { + return err; + } + + return bcm2835_power_pd_power_on(&pd->parent); +} + +static int bcm2835_reset_status(struct rt_reset_control *rstc) +{ + struct bcm2835_power *power = rstc->rstcer->priv; + + switch (rstc->id) + { + case BCM2835_RESET_V3D: + return !PM_READ(PM_GRAFX & PM_V3DRSTN); + + case BCM2835_RESET_H264: + return !PM_READ(PM_IMAGE & PM_H264RSTN); + + case BCM2835_RESET_ISP: + return !PM_READ(PM_IMAGE & PM_ISPRSTN); + + default: + return -RT_EINVAL; + } +} + +static const struct rt_reset_control_ops bcm2835_reset_ops = +{ + .reset = bcm2835_reset_reset, + .status = bcm2835_reset_status, +}; + +static const char *const power_domain_names[] = +{ + [BCM2835_POWER_DOMAIN_GRAFX] = "grafx", + [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d", + + [BCM2835_POWER_DOMAIN_IMAGE] = "image", + [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image", + [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264", + [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp", + + [BCM2835_POWER_DOMAIN_USB] = "usb", + [BCM2835_POWER_DOMAIN_DSI0] = "dsi0", + [BCM2835_POWER_DOMAIN_DSI1] = "dsi1", + [BCM2835_POWER_DOMAIN_CAM0] = "cam0", + [BCM2835_POWER_DOMAIN_CAM1] = "cam1", + [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx", + [BCM2835_POWER_DOMAIN_HDMI] = "hdmi", +}; + +static rt_err_t bcm2835_init_power_domain(struct bcm2835_power *power, + struct bcm2835_pm *pm, int id) +{ + const char *name = power_domain_names[id]; + struct bcm2835_power_domain *dom = &power->domains[id]; + + dom->clk = rt_ofw_get_clk_by_name(pm->ofw_node, name); + + if (rt_is_err(dom->clk)) + { + return rt_ptr_err(dom->clk); + } + + dom->power = power; + dom->parent.power_on = bcm2835_power_pd_power_on; + dom->parent.power_off = bcm2835_power_pd_power_off; + + rt_dm_power_domain_register(&dom->parent); + + return RT_EOK; +} + +static rt_err_t bcm2835_power_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_reset_controller *rstcer; + struct bcm2835_pm *pm = pdev->priv; + struct bcm2835_power *power = rt_calloc(1, sizeof(*power)); + + if (!power) + { + return -RT_ENOMEM; + } + + power->base = pm->base; + power->asb = pm->asb; + power->rpivid_asb = pm->rpivid_asb; + + if (power->asb) + { + rt_uint32_t id = HWREG32(power->asb + ASB_AXI_BRDG_ID); + + /* "BRDG" */ + if (id != BCM2835_BRDG_ID) + { + LOG_E("ASB register ID returned 0x%08x", id); + + err = -RT_EINVAL; + goto _fail; + } + + if (power->rpivid_asb) + { + id = HWREG32(power->rpivid_asb + ASB_AXI_BRDG_ID); + /* "BRDG" */ + if (id != BCM2835_BRDG_ID) + { + LOG_E("RPiVid ASB register ID returned 0x%08x", id); + + err = -RT_EINVAL; + goto _fail; + } + } + } + + for (int i = 0; i < RT_ARRAY_SIZE(power_domain_names); ++i) + { + if ((err = bcm2835_init_power_domain(power, pm, i))) + { + goto _free_power_domain; + } + } + + power->proxy_parent.ofw_parse = bcm2835_power_domains_ofw_parse; + rt_dm_power_domain_proxy_ofw_bind(&power->proxy_parent, pm->ofw_node); + + rstcer = &power->rstc_parent; + rstcer->priv = power; + rstcer->ofw_node = pm->ofw_node; + rstcer->ops = &bcm2835_reset_ops; + + rt_reset_controller_register(rstcer); + + return RT_EOK; + +_free_power_domain: + for (int i = 0; i < RT_ARRAY_SIZE(power_domain_names); ++i) + { + struct bcm2835_power_domain *dom = &power->domains[i]; + + if (!dom->power) + { + break; + } + + rt_dm_power_domain_unregister(&dom->parent); + } + +_fail: + rt_free(power); + + return err; +} + +static struct rt_platform_driver bcm2835_power_driver = +{ + .name = "bcm2835-power", + .probe = bcm2835_power_probe, +}; + +static int bcm2835_power_drv_register(void) +{ + rt_platform_driver_register(&bcm2835_power_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(bcm2835_power_drv_register); diff --git a/bsp/raspberry-pi/dm/pmdomain/pm-domain-raspberrypi.c b/bsp/raspberry-pi/dm/pmdomain/pm-domain-raspberrypi.c new file mode 100755 index 0000000000..435185a215 --- /dev/null +++ b/bsp/raspberry-pi/dm/pmdomain/pm-domain-raspberrypi.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-21 GuEe-GUI first version + */ + +#include +#include + +#include +#include + +/* + * Firmware indices for the old power domains interface. + * Only a few of them were actually implemented. + */ +#define RPI_OLD_POWER_DOMAIN_USB 3 +#define RPI_OLD_POWER_DOMAIN_V3D 10 + +/* + * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and + * RPI_FIRMWARE_SET_DOMAIN_STATE. + */ +struct rpi_power_domain_packet +{ + rt_uint32_t domain; + rt_uint32_t state; +}; + +struct rpi_power_domain +{ + struct rt_dm_power_domain parent; + + rt_uint32_t domain; + rt_bool_t old_interface; + struct rpi_firmware *rpi_fw; +}; + +#define raw_to_rpi_power_domain(raw) rt_container_of(raw, struct rpi_power_domain, parent) + +struct rpi_power_domains +{ + struct rt_dm_power_domain_proxy parent; + + rt_bool_t has_new_interface; + struct rpi_firmware *rpi_fw; + struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT]; +}; + +#define raw_to_rpi_power_domains(raw) rt_container_of(raw, struct rpi_power_domains, parent) + +static rt_err_t rpi_firmware_set_power(struct rt_dm_power_domain *domain, rt_bool_t on) +{ + struct rpi_power_domain *rpi_domain = raw_to_rpi_power_domain(domain); + struct rpi_power_domain_packet packet; + + packet.domain = rpi_domain->domain; + packet.state = on; + + return rpi_firmware_property(rpi_domain->rpi_fw, + rpi_domain->old_interface ? + RPI_FIRMWARE_SET_POWER_STATE : RPI_FIRMWARE_SET_DOMAIN_STATE, + &packet, sizeof(packet)); +} + +static rt_err_t rpi_domain_off(struct rt_dm_power_domain *domain) +{ + return rpi_firmware_set_power(domain, RT_FALSE); +} + +static rt_err_t rpi_domain_on(struct rt_dm_power_domain *domain) +{ + return rpi_firmware_set_power(domain, RT_TRUE); +} + +static struct rt_dm_power_domain *rpi_power_domains_ofw_parse( + struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args) +{ + struct rpi_power_domains *rpi_domains = raw_to_rpi_power_domains(proxy); + + return &rpi_domains->domains[args->args[0]].parent; +} + +static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains, int id) +{ + struct rpi_power_domain *dom = &rpi_domains->domains[id]; + + dom->rpi_fw = rpi_domains->rpi_fw; + + dom->parent.power_on = rpi_domain_on; + dom->parent.power_off = rpi_domain_off; + + rt_dm_power_domain_register(&dom->parent); +} + +static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains, + int id, const char *name) +{ + struct rpi_power_domain *dom = &rpi_domains->domains[id]; + + if (!rpi_domains->has_new_interface) + { + return; + } + + /* The DT binding index is the firmware's domain index minus one. */ + dom->domain = id + 1; + + rpi_common_init_power_domain(rpi_domains, id); + (void)name; +} + +static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains, + int id, int domain, const char *name) +{ + struct rpi_power_domain *dom = &rpi_domains->domains[id]; + + dom->old_interface = RT_TRUE; + dom->domain = domain; + + rpi_common_init_power_domain(rpi_domains, id); + (void)name; +} + +/* + * Detect whether the firmware supports the new power domains interface. + * + * The firmware does not return an error on an unknown tag and just skips + * over it, so probe by putting an unexpected value in the return field + * and checking if it was unchanged. + */ +static rt_bool_t rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains) +{ + struct rpi_power_domain_packet packet; + + packet.domain = RPI_POWER_DOMAIN_ARM; + packet.state = ~0; + + return !rpi_firmware_property(rpi_domains->rpi_fw, + RPI_FIRMWARE_GET_DOMAIN_STATE, &packet, sizeof(packet)) && + packet.state != ~0; +} + +static rt_err_t rpi_power_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node; + struct rt_ofw_node *fw_np; + struct rpi_power_domains *rpi_domains = rt_calloc(1, sizeof(*rpi_domains)); + + if (!rpi_domains) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_domains->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_domains->rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_domains->has_new_interface = rpi_has_new_domain_support(rpi_domains); + + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER, "VIDEO_SCALER"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI"); + + /* + * Use the old firmware interface for USB power, so that we + * can turn it on even if the firmware hasn't been updated. + */ + rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB, + RPI_OLD_POWER_DOMAIN_USB, "USB"); + + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER, "TRANSPOSER"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP"); + rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM"); + + rpi_domains->parent.ofw_parse = rpi_power_domains_ofw_parse; + rt_dm_power_domain_proxy_ofw_bind(&rpi_domains->parent, pdev->parent.ofw_node); + + return RT_EOK; + +_fail: + rt_free(rpi_domains); + + return err; +} + +static const struct rt_ofw_node_id rpi_power_ofw_ids[] = +{ + { .compatible = "raspberrypi,bcm2835-power" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_power_driver = +{ + .name = "raspberrypi-power", + .ids = rpi_power_ofw_ids, + + .probe = rpi_power_probe, +}; + +static int rpi_power_drv_register(void) +{ + rt_platform_driver_register(&rpi_power_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rpi_power_drv_register); diff --git a/bsp/raspberry-pi/dm/pwm/Kconfig b/bsp/raspberry-pi/dm/pwm/Kconfig new file mode 100755 index 0000000000..1400eb66d2 --- /dev/null +++ b/bsp/raspberry-pi/dm/pwm/Kconfig @@ -0,0 +1,20 @@ +config RT_PWM_BCM2835 + bool "BCM2835 PWM support" + depends on RT_USING_PINCTRL + depends on RT_USING_DM + depends on RT_USING_PWM + default n + +config RT_PWM_BRCMSTB + bool "Broadcom STB PWM support" + depends on RT_USING_PINCTRL + depends on RT_USING_DM + depends on RT_USING_PWM + default n + +config RT_PWM_RP1 + bool "RP1 PWM support" + depends on RT_USING_PINCTRL + depends on RT_USING_DM + depends on RT_USING_PWM + default n diff --git a/bsp/raspberry-pi/dm/pwm/SConscript b/bsp/raspberry-pi/dm/pwm/SConscript new file mode 100755 index 0000000000..4d5c0d4c5f --- /dev/null +++ b/bsp/raspberry-pi/dm/pwm/SConscript @@ -0,0 +1,19 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_PWM_BCM2835']): + src += ['pwm-bcm2835.c'] + +if GetDepend(['RT_PWM_BRCMSTB']): + src += ['pwm-brcmstb.c'] + +if GetDepend(['RT_PWM_RP1']): + src += ['pwm-rp1.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/pwm/pwm-bcm2835.c b/bsp/raspberry-pi/dm/pwm/pwm-bcm2835.c new file mode 100755 index 0000000000..45a7693e36 --- /dev/null +++ b/bsp/raspberry-pi/dm/pwm/pwm-bcm2835.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pwm.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#define PWM_CONTROL 0x000 +#define PWM_CONTROL_SHIFT(x) ((x) * 8) +#define PWM_CONTROL_MASK 0xff +#define PWM_MODE 0x80 /* Set timer in PWM mode */ +#define PWM_ENABLE (1 << 0) +#define PWM_POLARITY (1 << 4) + +#define PERIOD(x) (((x) * 0x10) + 0x10) +#define DUTY(x) (((x) * 0x10) + 0x14) + +#define PERIOD_MIN 0x2 +#define PWM_NUMBER 2 + +#define NSEC_PER_SEC 1000000000L + +struct bcm2835_pwm +{ + struct rt_device_pwm parent; + + void *base; + struct rt_clk *clk; +}; + +#define raw_to_bcm2835_pwm(raw) rt_container_of(raw, struct bcm2835_pwm, parent) + +static rt_err_t bcm2835_pwm_enable(struct bcm2835_pwm *bpwm, int channel, rt_bool_t enable) +{ + rt_uint32_t value; + + if (channel >= PWM_NUMBER) + { + return -RT_EINVAL; + } + + if (enable) + { + value = HWREG32(bpwm->base + PWM_CONTROL); + value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(channel)); + value |= ((PWM_MODE | PWM_ENABLE) << PWM_CONTROL_SHIFT(channel)); + HWREG32(bpwm->base + PWM_CONTROL) = value; + } + else + { + value = HWREG32(bpwm->base + PWM_CONTROL); + value &= ~((PWM_CONTROL_MASK | PWM_ENABLE) << PWM_CONTROL_SHIFT(channel)); + HWREG32(bpwm->base + PWM_CONTROL) = value; + } + + return RT_EOK; +} + +static rt_err_t bcm2835_pwm_config(struct bcm2835_pwm *bpwm, + struct rt_pwm_configuration *pwm_cfg) +{ + int channel; + rt_uint32_t val; + rt_uint64_t period_cycles, max_period; + rt_ubase_t rate = rt_clk_get_rate(bpwm->clk); + + if (!rate) + { + LOG_E("Failed to get clock rate"); + + return -RT_EINVAL; + } + + channel = pwm_cfg->channel; + + /* + * period_cycles must be a 32 bit value, so period * rate / NSEC_PER_SEC + * must be <= RT_UINT32_MAX. As RT_UINT32_MAX * NSEC_PER_SEC < U64_MAX the + * multiplication period * rate doesn't overflow. + * To calculate the maximal possible period that guarantees the + * above inequality: + * + * round(period * rate / NSEC_PER_SEC) <= RT_UINT32_MAX + * <=> period * rate / NSEC_PER_SEC < RT_UINT32_MAX + 0.5 + * <=> period * rate < (RT_UINT32_MAX + 0.5) * NSEC_PER_SEC + * <=> period < ((RT_UINT32_MAX + 0.5) * NSEC_PER_SEC) / rate + * <=> period < ((RT_UINT32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate + * <=> period <= ceil((RT_UINT32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate) - 1 + */ + max_period = RT_DIV_ROUND_UP_ULL( + (rt_uint64_t)RT_UINT32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, rate) - 1; + + if (pwm_cfg->period > max_period) + { + return -RT_EINVAL; + } + + /* Set period */ + period_cycles = RT_DIV_ROUND_CLOSEST_ULL(pwm_cfg->period * rate, NSEC_PER_SEC); + + /* Don't accept a period that is too small */ + if (period_cycles < PERIOD_MIN) + { + return -RT_EINVAL; + } + + HWREG32(bpwm->base + PERIOD(channel)) = period_cycles; + + /* Set duty cycle */ + val = RT_DIV_ROUND_CLOSEST_ULL(pwm_cfg->pulse * rate, NSEC_PER_SEC); + HWREG32(bpwm->base + DUTY(channel)) = val; + + /* Set polarity */ + val = HWREG32(bpwm->base + PWM_CONTROL); + + if (!pwm_cfg->complementary) + { + val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(channel)); + } + else + { + val |= PWM_POLARITY << PWM_CONTROL_SHIFT(channel); + } + + HWREG32(bpwm->base + PWM_CONTROL) = val; + + return RT_EOK; +} + +static rt_err_t bcm2835_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct bcm2835_pwm *bpwm = raw_to_bcm2835_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + switch (cmd) + { + case PWM_CMD_ENABLE: + err = bcm2835_pwm_enable(bpwm, pwm_cfg->channel, RT_TRUE); + break; + + case PWM_CMD_DISABLE: + err = bcm2835_pwm_enable(bpwm, pwm_cfg->channel, RT_FALSE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + err = bcm2835_pwm_config(bpwm, pwm_cfg); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_pwm_ops bcm2835_pwm_ops = +{ + .control = bcm2835_pwm_control, +}; + +static rt_err_t bcm2835_pwm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct bcm2835_pwm *bpwm = rt_calloc(1, sizeof(*bpwm)); + + if (!bpwm) + { + return -RT_ENOMEM; + } + + bpwm->base = rt_dm_dev_iomap(dev, 0); + + if (!bpwm->base) + { + err = -RT_EIO; + goto _fail; + } + + bpwm->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(bpwm->clk)) + { + err = rt_ptr_err(bpwm->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(bpwm->clk))) + { + goto _fail; + } + + dev->user_data = bpwm; + + bpwm->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name_auto(&bpwm->parent.parent, "pwm"); + rt_device_pwm_register(&bpwm->parent, rt_dm_dev_get_name(&bpwm->parent.parent), &bcm2835_pwm_ops, bpwm); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, bpwm); + + return RT_EOK; + +_fail: + if (bpwm->base) + { + rt_iounmap(bpwm->base); + } + + if (!rt_is_err_or_null(bpwm->clk)) + { + rt_clk_disable_unprepare(bpwm->clk); + rt_clk_put(bpwm->clk); + } + + rt_free(bpwm); + + return err; +} + +static rt_err_t bcm2835_pwm_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct bcm2835_pwm *bpwm = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + for (int channel = 0; channel < PWM_NUMBER; ++channel) + { + bcm2835_pwm_enable(bpwm, channel, RT_FALSE); + } + + rt_device_unregister(&bpwm->parent.parent); + + rt_clk_disable_unprepare(bpwm->clk); + rt_clk_put(bpwm->clk); + + rt_free(bpwm); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_pwm_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-pwm", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_pwm_driver = +{ + .name = "bcm2835-pwm", + .ids = bcm2835_pwm_ofw_ids, + + .probe = bcm2835_pwm_probe, + .remove = bcm2835_pwm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_pwm_driver); diff --git a/bsp/raspberry-pi/dm/pwm/pwm-brcmstb.c b/bsp/raspberry-pi/dm/pwm/pwm-brcmstb.c new file mode 100755 index 0000000000..d90d92f668 --- /dev/null +++ b/bsp/raspberry-pi/dm/pwm/pwm-brcmstb.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pwm.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#define PWM_CTRL 0x00 +#define CTRL_START RT_BIT(0) +#define CTRL_OEB RT_BIT(1) +#define CTRL_FORCE_HIGH RT_BIT(2) +#define CTRL_OPENDRAIN RT_BIT(3) +#define CTRL_CHAN_OFFS 4 + +#define PWM_CTRL2 0x04 +#define CTRL2_OUT_SELECT RT_BIT(0) + +#define PWM_CH_SIZE 0x8 + +#define PWM_CWORD_MSB(ch) (0x08 + ((ch) * PWM_CH_SIZE)) +#define PWM_CWORD_LSB(ch) (0x0c + ((ch) * PWM_CH_SIZE)) + +/* Number of bits for the CWORD value */ +#define CWORD_BIT_SIZE 16 + +/* + * Maximum control word value allowed when variable-frequency PWM is used as a + * clock for the constant-frequency PMW. + */ +#define CONST_VAR_F_MAX 32768 +#define CONST_VAR_F_MIN 1 + +#define PWM_ON(ch) (0x18 + ((ch) * PWM_CH_SIZE)) +#define PWM_ON_MIN 1 +#define PWM_PERIOD(ch) (0x1c + ((ch) * PWM_CH_SIZE)) +#define PWM_PERIOD_MIN 0 + +#define PWM_ON_PERIOD_MAX 0xff + +#define PWM_NUMBER 2 + +#define NSEC_PER_SEC 1000000000L + +struct brcmstb_pwm +{ + struct rt_device_pwm parent; + + void *base; + struct rt_clk *clk; +}; + +#define raw_to_brcmstb_pwm(raw) rt_container_of(raw, struct brcmstb_pwm, parent) + +#ifndef mul_u64_u64_div_u64 +static rt_uint64_t mul_u64_u64_div_u64(rt_uint64_t a, rt_uint64_t b, rt_uint64_t c) +{ + /* overflow in rt-thread is unlikely */ + return a * b / c; +} +#endif /* mul_u64_u64_div_u64 */ + +static rt_err_t brcmstb_pwm_enable(struct brcmstb_pwm *bpwm, int channel, rt_bool_t enable) +{ + rt_uint32_t shift, value; + + if (channel >= PWM_NUMBER) + { + return -RT_EINVAL; + } + + shift = channel * CTRL_CHAN_OFFS; + value = HWREG32(bpwm->base + PWM_CTRL); + + if (enable) + { + value &= ~(CTRL_OEB << shift); + value |= (CTRL_START | CTRL_OPENDRAIN) << shift; + } + else + { + value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift); + value |= CTRL_OEB << shift; + } + + HWREG32(bpwm->base + PWM_CTRL) = value; + + return RT_EOK; +} + +/* + * Fv is derived from the variable frequency output. The variable frequency + * output is configured using this formula: + * + * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword + * + * Fv = W x 2 ^ -16 x 27Mhz (reference clock) + * + * The period is: (period + 1) / Fv and "on" time is on / (period + 1) + * + * The PWM core framework specifies that the "duty_ns" parameter is in fact the + * "on" time, so this translates directly into our HW programming here. + */ +static rt_err_t brcmstb_pwm_config(struct brcmstb_pwm *bpwm, + struct rt_pwm_configuration *pwm_cfg) +{ + rt_ubase_t pc, dc, cword = CONST_VAR_F_MAX; + rt_uint32_t value, channel, period_ns, duty_ns; + + channel = pwm_cfg->channel; + period_ns = pwm_cfg->period; + duty_ns = pwm_cfg->pulse; + + /* + * If asking for a duty_ns equal to period_ns, we need to substract + * the period value by 1 to make it shorter than the "on" time and + * produce a flat 100% duty cycle signal, and max out the "on" time + */ + if (duty_ns == period_ns) + { + dc = PWM_ON_PERIOD_MAX; + pc = PWM_ON_PERIOD_MAX - 1; + goto _done; + } + + while (RT_TRUE) + { + rt_uint64_t rate; + + /* Calculate the base rate from base frequency and current cword */ + rate = (rt_uint64_t)rt_clk_get_rate(bpwm->clk) * (rt_uint64_t)cword; + rate >>= CWORD_BIT_SIZE; + + pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC); + dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC); + + /* + * We can be called with separate duty and period updates, + * so do not reject dc == 0 right away + */ + if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns)) + { + return -RT_EINVAL; + } + + /* We converged on a calculation */ + if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX) + { + break; + } + + /* + * The cword needs to be a power of 2 for the variable + * frequency generator to output a 50% duty cycle variable + * frequency which is used as input clock to the fixed + * frequency generator. + */ + cword >>= 1; + + /* Desired periods are too large, we do not have a divider for them */ + if (cword < CONST_VAR_F_MIN) + { + return -RT_EINVAL; + } + } + +_done: + /* + * Configure the defined "cword" value to have the variable frequency + * generator output a base frequency for the constant frequency + * generator to derive from. + */ + HWREG32(bpwm->base + PWM_CWORD_MSB(channel)) = cword >> 8; + HWREG32(bpwm->base + PWM_CWORD_LSB(channel)) = cword & 0xff; + + /* Select constant frequency signal output */ + value = HWREG32(bpwm->base + PWM_CTRL2); + value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS); + HWREG32(bpwm->base + PWM_CTRL2) = value; + + /* Configure on and period value */ + HWREG32(bpwm->base + PWM_PERIOD(channel)) = pc; + HWREG32(bpwm->base + PWM_ON(channel)) = dc; + + return 0; +} + +static rt_err_t brcmstb_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct brcmstb_pwm *bpwm = raw_to_brcmstb_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + switch (cmd) + { + case PWM_CMD_ENABLE: + err = brcmstb_pwm_enable(bpwm, pwm_cfg->channel, RT_TRUE); + break; + + case PWM_CMD_DISABLE: + err = brcmstb_pwm_enable(bpwm, pwm_cfg->channel, RT_FALSE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + err = brcmstb_pwm_config(bpwm, pwm_cfg); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_pwm_ops brcmstb_pwm_ops = +{ + .control = brcmstb_pwm_control, +}; + +static rt_err_t brcmstb_pwm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct brcmstb_pwm *bpwm = rt_calloc(1, sizeof(*bpwm)); + + if (!bpwm) + { + return -RT_ENOMEM; + } + + bpwm->base = rt_dm_dev_iomap(dev, 0); + + if (!bpwm->base) + { + err = -RT_EIO; + goto _fail; + } + + bpwm->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(bpwm->clk)) + { + err = rt_ptr_err(bpwm->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(bpwm->clk))) + { + goto _fail; + } + + dev->user_data = bpwm; + + bpwm->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name_auto(&bpwm->parent.parent, "pwm"); + rt_device_pwm_register(&bpwm->parent, rt_dm_dev_get_name(&bpwm->parent.parent), &brcmstb_pwm_ops, bpwm); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, bpwm); + + return RT_EOK; + +_fail: + if (bpwm->base) + { + rt_iounmap(bpwm->base); + } + + if (!rt_is_err_or_null(bpwm->clk)) + { + rt_clk_disable_unprepare(bpwm->clk); + rt_clk_put(bpwm->clk); + } + + rt_free(bpwm); + + return err; +} + +static rt_err_t brcmstb_pwm_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct brcmstb_pwm *bpwm = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + for (int channel = 0; channel < PWM_NUMBER; ++channel) + { + brcmstb_pwm_enable(bpwm, channel, RT_FALSE); + } + + rt_device_unregister(&bpwm->parent.parent); + + rt_clk_disable_unprepare(bpwm->clk); + rt_clk_put(bpwm->clk); + + rt_free(bpwm); + + return RT_EOK; +} + +static const struct rt_ofw_node_id brcmstb_pwm_ofw_ids[] = +{ + { .compatible = "brcm,bcm7038-pwm", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmstb_pwm_driver = +{ + .name = "brcmstb-pwm", + .ids = brcmstb_pwm_ofw_ids, + + .probe = brcmstb_pwm_probe, + .remove = brcmstb_pwm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(brcmstb_pwm_driver); diff --git a/bsp/raspberry-pi/dm/pwm/pwm-rp1.c b/bsp/raspberry-pi/dm/pwm/pwm-rp1.c new file mode 100755 index 0000000000..27553c1b4e --- /dev/null +++ b/bsp/raspberry-pi/dm/pwm/pwm-rp1.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "pwm.rp1" +#define DBG_LVL DBG_INFO +#include + +#define PWM_GLOBAL_CTRL 0x000 +#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 16)) +#define PWM_RANGE(x) (0x018 + ((x) * 16)) +#define PWM_DUTY(x) (0x020 + ((x) * 16)) + +/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */ +#define PWM_CHANNEL_DEFAULT (RT_BIT(8) + RT_BIT(0)) +#define PWM_CHANNEL_ENABLE(x) RT_BIT(x) +#define PWM_POLARITY RT_BIT(3) +#define SET_UPDATE RT_BIT(31) +#define PWM_MODE_MASK RT_GENMASK(1, 0) +#define PWM_POLARITY_INVERTED RT_BIT(0) + +#define PWM_NUMBER 4 + +#define NSEC_PER_SEC 1000000000L + +struct rp1_pwm +{ + struct rt_device_pwm parent; + + void *base; + struct rt_clk *clk; + + rt_bool_t inverted[PWM_NUMBER]; + struct rt_pwm_configuration config[PWM_NUMBER]; +}; + +#define raw_to_rp1_pwm(raw) rt_container_of(raw, struct rp1_pwm, parent) + +static void rp1_pwm_apply_config(struct rp1_pwm *rpwm) +{ + rt_uint32_t value; + + value = HWREG32(rpwm->base + PWM_GLOBAL_CTRL); + value |= SET_UPDATE; + HWREG32(rpwm->base + PWM_GLOBAL_CTRL) = value; +} + +static rt_err_t rp1_pwm_enable(struct rp1_pwm *rpwm, int channel, rt_bool_t enable) +{ + rt_uint32_t value; + + if (channel >= PWM_NUMBER) + { + return -RT_EINVAL; + } + + if (enable) + { + value = PWM_CHANNEL_DEFAULT; + + if (rpwm->config[channel].complementary || rpwm->inverted[channel]) + { + value |= PWM_POLARITY; + } + + HWREG32(rpwm->base + PWM_CHANNEL_CTRL(channel)) = value; + + value = HWREG32(rpwm->base + PWM_GLOBAL_CTRL); + value |= PWM_CHANNEL_ENABLE(channel); + HWREG32(rpwm->base + PWM_GLOBAL_CTRL) = value; + } + else + { + value = HWREG32(rpwm->base + PWM_GLOBAL_CTRL); + value &= ~PWM_CHANNEL_ENABLE(channel); + HWREG32(rpwm->base + PWM_GLOBAL_CTRL) = value; + } + + rp1_pwm_apply_config(rpwm); + + return RT_EOK; +} + +static rt_err_t rp1_pwm_config(struct rp1_pwm *rpwm, + struct rt_pwm_configuration *pwm_cfg) +{ + int channel; + rt_uint32_t value; + rt_ubase_t clk_period, clk_rate = rt_clk_get_rate(rpwm->clk); + + if (!clk_rate) + { + LOG_E("Failed to get clock rate"); + + return -RT_EINVAL; + } + + channel = pwm_cfg->channel; + + if (channel >= PWM_NUMBER) + { + return -RT_EINVAL; + } + + /* Period */ + clk_period = RT_DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate); + + HWREG32(rpwm->base + PWM_DUTY(channel)) = + RT_DIV_ROUND_CLOSEST(pwm_cfg->pulse, clk_period); + + /* Duty cycle */ + HWREG32(rpwm->base + PWM_RANGE(channel)) = + RT_DIV_ROUND_CLOSEST(pwm_cfg->period, clk_period); + + /* Polarity */ + value = HWREG32(rpwm->base + PWM_CHANNEL_CTRL(channel)); + if (!pwm_cfg->complementary && !rpwm->inverted[channel]) + { + value &= ~PWM_POLARITY; + } + else + { + value |= PWM_POLARITY; + } + HWREG32(rpwm->base + PWM_CHANNEL_CTRL(channel)) = value; + + rp1_pwm_apply_config(rpwm); + + rpwm->config[channel] = *pwm_cfg; + rpwm->config[channel].complementary = + pwm_cfg->complementary || rpwm->inverted[channel]; + + return RT_EOK; +} + +static rt_err_t rp1_pwm_get(struct rp1_pwm *rpwm, + struct rt_pwm_configuration *pwm_cfg) +{ + int channel = pwm_cfg->channel; + + if (channel >= PWM_NUMBER) + { + return -RT_EINVAL; + } + + *pwm_cfg = rpwm->config[channel]; + + return RT_EOK; +} + +static rt_err_t rp1_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rp1_pwm *rpwm = raw_to_rp1_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + switch (cmd) + { + case PWM_CMD_ENABLE: + err = rp1_pwm_enable(rpwm, pwm_cfg->channel, RT_TRUE); + break; + + case PWM_CMD_DISABLE: + err = rp1_pwm_enable(rpwm, pwm_cfg->channel, RT_FALSE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + err = rp1_pwm_config(rpwm, pwm_cfg); + break; + + case PWM_CMD_GET: + err = rp1_pwm_get(rpwm, pwm_cfg); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_pwm_ops rp1_pwm_ops = +{ + .control = rp1_pwm_control, +}; + +static void rp1_pwm_parse_dt_flags(struct rp1_pwm *rpwm, + struct rt_ofw_node *pwm_np) +{ + struct rt_ofw_node *np; + + rt_ofw_foreach_allnodes(np) + { + int index = 0; + struct rt_ofw_cell_args args; + + while (!rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", + index++, &args)) + { + if (args.data == pwm_np && args.args_count >= 3 && + args.args[0] < PWM_NUMBER) + { + rpwm->inverted[args.args[0]] = + !!(args.args[2] & PWM_POLARITY_INVERTED); + } + + if (args.data) + { + rt_ofw_node_put(args.data); + } + } + } +} + +static rt_err_t rp1_pwm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rp1_pwm *rpwm = rt_calloc(1, sizeof(*rpwm)); + + if (!rpwm) + { + return -RT_ENOMEM; + } + + rpwm->base = rt_dm_dev_iomap(dev, 0); + + if (!rpwm->base) + { + err = -RT_EIO; + goto _fail; + } + + rpwm->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(rpwm->clk)) + { + err = rt_ptr_err(rpwm->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rpwm->clk))) + { + goto _fail; + } + + dev->user_data = rpwm; + + rpwm->parent.parent.ofw_node = dev->ofw_node; + + rp1_pwm_parse_dt_flags(rpwm, dev->ofw_node); + + for (int channel = 0; channel < PWM_NUMBER; ++channel) + { + rp1_pwm_enable(rpwm, channel, RT_FALSE); + + HWREG32(rpwm->base + PWM_CHANNEL_CTRL(channel)) = + PWM_CHANNEL_DEFAULT | + (rpwm->inverted[channel] ? PWM_POLARITY : 0); + rpwm->config[channel].channel = channel; + rpwm->config[channel].complementary = rpwm->inverted[channel]; + } + + rp1_pwm_apply_config(rpwm); + + rt_dm_dev_set_name_auto(&rpwm->parent.parent, "pwm"); + rt_device_pwm_register(&rpwm->parent, rt_dm_dev_get_name(&rpwm->parent.parent), &rp1_pwm_ops, rpwm); + + rt_dm_dev_bind_fwdata(dev, RT_NULL, rpwm); + + return RT_EOK; + +_fail: + if (rpwm->base) + { + rt_iounmap(rpwm->base); + } + + if (!rt_is_err_or_null(rpwm->clk)) + { + rt_clk_disable_unprepare(rpwm->clk); + rt_clk_put(rpwm->clk); + } + + rt_free(rpwm); + + return err; +} + +static rt_err_t rp1_pwm_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rp1_pwm *rpwm = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + for (int channel = 0; channel < PWM_NUMBER; ++channel) + { + rp1_pwm_enable(rpwm, channel, RT_FALSE); + } + + rt_device_unregister(&rpwm->parent.parent); + + rt_clk_disable_unprepare(rpwm->clk); + rt_clk_put(rpwm->clk); + + rt_free(rpwm); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rp1_pwm_ofw_ids[] = +{ + { .compatible = "raspberrypi,rp1-pwm" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rp1_pwm_driver = +{ + .name = "rp1-pwm", + .ids = rp1_pwm_ofw_ids, + + .probe = rp1_pwm_probe, + .remove = rp1_pwm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rp1_pwm_driver); diff --git a/bsp/raspberry-pi/dm/reset/Kconfig b/bsp/raspberry-pi/dm/reset/Kconfig new file mode 100755 index 0000000000..91acd93003 --- /dev/null +++ b/bsp/raspberry-pi/dm/reset/Kconfig @@ -0,0 +1,15 @@ +config RT_RESET_BRCMSTB_RESCAL + bool "Broadcom STB RESCAL reset controller" + depends on RT_USING_RESET + default n + +config RT_RESET_BRCMSTB + bool "Broadcom STB reset controller" + depends on RT_USING_RESET + default n + +config RT_RESET_RASPBERRYPI + bool "Raspberry Pi 4 Firmware Reset Driver" + depends on RT_USING_RESET + depends on RT_FIRMWARE_RASPBERRYPI + default n diff --git a/bsp/raspberry-pi/dm/reset/SConscript b/bsp/raspberry-pi/dm/reset/SConscript new file mode 100755 index 0000000000..8d8bccc20d --- /dev/null +++ b/bsp/raspberry-pi/dm/reset/SConscript @@ -0,0 +1,19 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_RESET_BRCMSTB_RESCAL']): + src += ['reset-brcmstb-rescal.c'] + +if GetDepend(['RT_RESET_BRCMSTB']): + src += ['reset-brcmstb.c'] + +if GetDepend(['RT_RESET_RASPBERRYPI']): + src += ['reset-raspberrypi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/reset/reset-brcmstb-rescal.c b/bsp/raspberry-pi/dm/reset/reset-brcmstb-rescal.c new file mode 100755 index 0000000000..9a2e8cb254 --- /dev/null +++ b/bsp/raspberry-pi/dm/reset/reset-brcmstb-rescal.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.brcmstb-rescal" +#define DBG_LVL DBG_INFO +#include + +#include + +#define BRCM_RESCAL_START 0x0 +#define BRCM_RESCAL_START_BIT RT_BIT(0) +#define BRCM_RESCAL_CTRL 0x4 +#define BRCM_RESCAL_STATUS 0x8 +#define BRCM_RESCAL_STATUS_BIT RT_BIT(0) + +struct brcm_rescal_reset +{ + struct rt_reset_controller parent; + + void *regs; +}; + +static rt_err_t brcm_rescal_reset_ofw_parse(struct rt_reset_control *rstc, struct rt_ofw_cell_args *args) +{ + args->args[0] = 0; + + return RT_EOK; +} + +static rt_err_t brcm_rescal_reset_reset(struct rt_reset_control *rstc) +{ + rt_uint32_t reg; + struct brcm_rescal_reset *brrst = rstc->rstcer->priv; + + reg = HWREG32(brrst->regs + BRCM_RESCAL_START); + HWREG32(brrst->regs + BRCM_RESCAL_START) = reg | BRCM_RESCAL_START_BIT; + reg = HWREG32(brrst->regs + BRCM_RESCAL_START); + + if (!(reg & BRCM_RESCAL_START_BIT)) + { + LOG_E("Failed to start SATA/PCIe rescal"); + + return -RT_EIO; + } + + for (rt_uint32_t time = 0; time < 1000; time += 100) + { + reg = HWREG32(brrst->regs + BRCM_RESCAL_STATUS); + + if (reg & BRCM_RESCAL_STATUS_BIT) + { + goto _status_ok; + } + + rt_hw_us_delay(100); + + rt_hw_cpu_relax(); + } + + LOG_E("Time out on SATA/PCIe rescal"); + + return -RT_ETIMEOUT; + +_status_ok: + reg = HWREG32(brrst->regs + BRCM_RESCAL_START); + HWREG32(brrst->regs + BRCM_RESCAL_START) = reg & ~BRCM_RESCAL_START_BIT; + + LOG_D("SATA/PCIe rescal success"); + + return RT_EOK; +} + +static rt_err_t brcm_rescal_reset_assert(struct rt_reset_control *rstc) +{ + return RT_EOK; +} + +static rt_err_t brcm_rescal_reset_deassert(struct rt_reset_control *rstc) +{ + return brcm_rescal_reset_reset(rstc); +} + +const static struct rt_reset_control_ops brcm_rescal_reset_ops = +{ + .ofw_parse = brcm_rescal_reset_ofw_parse, + .reset = brcm_rescal_reset_reset, + .assert = brcm_rescal_reset_assert, + .deassert = brcm_rescal_reset_deassert, +}; + +static rt_err_t brcm_rescal_reset_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_reset_controller *rstcer; + struct rt_device *dev = &pdev->parent; + struct brcm_rescal_reset *brrst = rt_calloc(1, sizeof(*brrst)); + + if (!brrst) + { + return -RT_ENOMEM; + } + + brrst->regs = rt_dm_dev_iomap(dev, 0); + + if (!brrst->regs) + { + err = -RT_EIO; + goto _fail; + } + + rstcer = &brrst->parent; + + rstcer->priv = brrst; + rstcer->ofw_node = dev->ofw_node; + rstcer->ops = &brcm_rescal_reset_ops; + + if ((err = rt_reset_controller_register(rstcer))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (brrst->regs) + { + rt_iounmap(brrst->regs); + } + + rt_free(brrst); + + return err; +} + +static const struct rt_ofw_node_id brcm_rescal_reset_ofw_ids[] = +{ + { .compatible = "brcm,bcm7216-pcie-sata-rescal" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcm_rescal_reset_driver = +{ + .name = "reset-brcm-rescal", + .ids = brcm_rescal_reset_ofw_ids, + + .probe = brcm_rescal_reset_probe, +}; + +static int brcm_rescal_reset_register(void) +{ + rt_platform_driver_register(&brcm_rescal_reset_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(brcm_rescal_reset_register); diff --git a/bsp/raspberry-pi/dm/reset/reset-brcmstb.c b/bsp/raspberry-pi/dm/reset/reset-brcmstb.c new file mode 100755 index 0000000000..1c71afb47d --- /dev/null +++ b/bsp/raspberry-pi/dm/reset/reset-brcmstb.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#define SW_INIT_SET 0x00 +#define SW_INIT_CLEAR 0x04 +#define SW_INIT_STATUS 0x08 + +#define SW_INIT_BIT(id) RT_BIT((id) & 0x1f) +#define SW_INIT_BANK(id) ((id) >> 5) + +/* + * A full bank contains extra registers that we are not utilizing but still + * qualify as a single bank. + */ +#define SW_INIT_BANK_SIZE 0x18 + +struct brcmstb_reset +{ + struct rt_reset_controller parent; + + void *regs; +}; + +static rt_err_t brcmstb_reset_assert(struct rt_reset_control *rstc) +{ + struct brcmstb_reset *brst = rstc->rstcer->priv; + rt_uint32_t off = SW_INIT_BANK(rstc->id) * SW_INIT_BANK_SIZE; + + HWREG32(brst->regs + off + SW_INIT_SET) = SW_INIT_BIT(rstc->id); + + return RT_EOK; +} + +static rt_err_t brcmstb_reset_deassert(struct rt_reset_control *rstc) +{ + struct brcmstb_reset *brst = rstc->rstcer->priv; + unsigned int off = SW_INIT_BANK(rstc->id) * SW_INIT_BANK_SIZE; + + HWREG32(brst->regs + off + SW_INIT_CLEAR) = SW_INIT_BIT(rstc->id); + + /* + * Maximum reset delay after de-asserting a line and seeing block + * operation is typically 14us for the worst case, build some slack here. + */ + rt_hw_us_delay(150); + + return RT_EOK; +} + +static int brcmstb_reset_status(struct rt_reset_control *rstc) +{ + struct brcmstb_reset *brst = rstc->rstcer->priv; + rt_uint32_t off = SW_INIT_BANK(rstc->id) * SW_INIT_BANK_SIZE; + + return HWREG32(brst->regs + off + SW_INIT_STATUS) & SW_INIT_BIT(rstc->id); +} + +const static struct rt_reset_control_ops brcmstb_reset_ops = +{ + .assert = brcmstb_reset_assert, + .deassert = brcmstb_reset_deassert, + .status = brcmstb_reset_status, +}; + +static rt_err_t brcmstb_reset_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_reset_controller *rstcer; + struct rt_device *dev = &pdev->parent; + struct brcmstb_reset *brst = rt_calloc(1, sizeof(*brst)); + + if (!brst) + { + return -RT_ENOMEM; + } + + brst->regs = rt_dm_dev_iomap(dev, 0); + + if (!brst->regs) + { + err = -RT_EIO; + goto _fail; + } + + rstcer = &brst->parent; + + rstcer->priv = brst; + rstcer->ofw_node = dev->ofw_node; + rstcer->ops = &brcmstb_reset_ops; + + if ((err = rt_reset_controller_register(rstcer))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (brst->regs) + { + rt_iounmap(brst->regs); + } + + rt_free(brst); + + return err; +} + +static const struct rt_ofw_node_id brcmstb_reset_ofw_ids[] = +{ + { .compatible = "brcm,brcmstb-reset" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmstb_reset_driver = +{ + .name = "reset-brcmstb", + .ids = brcmstb_reset_ofw_ids, + + .probe = brcmstb_reset_probe, +}; + +static int brcmstb_reset_register(void) +{ + rt_platform_driver_register(&brcmstb_reset_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(brcmstb_reset_register); diff --git a/bsp/raspberry-pi/dm/reset/reset-raspberrypi.c b/bsp/raspberry-pi/dm/reset/reset-raspberrypi.c new file mode 100755 index 0000000000..8b2708a921 --- /dev/null +++ b/bsp/raspberry-pi/dm/reset/reset-raspberrypi.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "reset.raspberrypi" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct rpi_reset +{ + struct rt_reset_controller parent; + + struct rpi_firmware *rpi_fw; +}; + +static rt_err_t rpi_reset_reset(struct rt_reset_control *rstc) +{ + rt_err_t err = RT_EOK; + rt_uint32_t dev_addr; + struct rpi_reset *rrst = rstc->rstcer->priv; + + switch (rstc->id) + { + case RASPBERRYPI_FIRMWARE_RESET_ID_USB: + /* + * The Raspberry Pi 4 gets its USB functionality from VL805, a + * PCIe chip that implements xHCI. After a PCI reset, VL805's + * firmware may either be loaded directly from an EEPROM or, if + * not present, by the SoC's co-processor, VideoCore. rpi's + * VideoCore OS contains both the non public firmware load + * logic and the VL805 firmware blob. This triggers the + * aforementioned process. + * + * VideoCore expects the PCI location encoded as: + * PCI_BUS << 20 | PCI_SLOT << 15 | PCI_FUNC << 12 + * + * Pi4 wires VL805 at bus 1, slot 0, function 0, so the address + * passed to NOTIFY_XHCI_RESET is 0x00100000. + */ + dev_addr = (1U << 20) | (0U << 15) | (0U << 12); + + err = rpi_firmware_property(rrst->rpi_fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, + &dev_addr, sizeof(dev_addr)); + if (err) + { + break; + } + + /* Wait for vl805 to startup */ + rt_hw_us_delay(500); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_reset_control_ops rpi_reset_ops = +{ + .reset = rpi_reset_reset, +}; + +static rt_err_t rpi_reset_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_reset_controller *rstcer; + struct rt_ofw_node *np = pdev->parent.ofw_node, *fw_np; + struct rpi_reset *rrst = rt_calloc(1, sizeof(*rrst)); + + if (!rrst) + { + return -RT_ENOMEM; + } + + if (!np) + { + err = -RT_EINVAL; + goto _fail; + } + + fw_np = rt_ofw_get_parent(np); + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rrst->rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rrst->rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + rstcer = &rrst->parent; + + rstcer->priv = rrst; + rstcer->ofw_node = np; + rstcer->ops = &rpi_reset_ops; + + if ((err = rt_reset_controller_register(rstcer))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(rrst); + + return err; +} + +static const struct rt_ofw_node_id rpi_reset_ofw_ids[] = +{ + { .compatible = "raspberrypi,firmware-reset" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_reset_driver = +{ + .name = "reset-raspberrypi", + .ids = rpi_reset_ofw_ids, + + .probe = rpi_reset_probe, +}; + +static int rpi_reset_register(void) +{ + rt_platform_driver_register(&rpi_reset_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rpi_reset_register); diff --git a/bsp/raspberry-pi/dm/rtc/Kconfig b/bsp/raspberry-pi/dm/rtc/Kconfig new file mode 100755 index 0000000000..ed22c9eb7b --- /dev/null +++ b/bsp/raspberry-pi/dm/rtc/Kconfig @@ -0,0 +1,5 @@ +config RT_RTC_RPI + bool "Raspberry Pi RTC" + depends on RT_FIRMWARE_RASPBERRYPI + select RT_USING_ALARM + default n diff --git a/bsp/raspberry-pi/dm/rtc/SConscript b/bsp/raspberry-pi/dm/rtc/SConscript new file mode 100755 index 0000000000..eff1275ba3 --- /dev/null +++ b/bsp/raspberry-pi/dm/rtc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/rtc'] + +if GetDepend(['RT_RTC_RPI']): + src += ['rtc-rpi.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/rtc/rtc-rpi.c b/bsp/raspberry-pi/dm/rtc/rtc-rpi.c new file mode 100755 index 0000000000..f64a605738 --- /dev/null +++ b/bsp/raspberry-pi/dm/rtc/rtc-rpi.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#define DBG_TAG "rtc.rpi" +#define DBG_LVL DBG_INFO +#include + +#include "rtc_dm.h" +#include + +enum +{ + RTC_TIME, + RTC_ALARM, + RTC_ALARM_PENDING, + RTC_ALARM_ENABLE, + RTC_BBAT_CHG_VOLTS, + RTC_BBAT_CHG_VOLTS_MIN, + RTC_BBAT_CHG_VOLTS_MAX, + RTC_BBAT_VOLTS +}; + +struct rpi_rtc +{ + struct rt_device parent; + + struct rpi_firmware *rpi_fw; + rt_uint32_t bbat_vchg_microvolts; + + struct rt_mutex lock; + struct rt_timer alarm_mon; + struct rt_rtc_wkalarm wkalarm; +}; + +#define raw_to_rpi_rtc(raw) rt_container_of(raw, struct rpi_rtc, parent) + +static rt_err_t rpi_rtc_alarm_clear_pending(struct rpi_rtc *rrtc) +{ + rt_uint32_t data[2] = { RTC_ALARM_PENDING, 1 }; + + return rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); +} + +static rt_err_t rpi_rtc_set_charge_voltage(struct rpi_rtc *rrtc) +{ + rt_err_t err; + rt_uint32_t data[2] = { RTC_BBAT_CHG_VOLTS, rrtc->bbat_vchg_microvolts }; + + err = rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); + + if (err) + { + LOG_E("Failed to set trickle charge voltage to %uuV error = %s", + rrtc->bbat_vchg_microvolts, rt_strerror(err)); + } + else if (rrtc->bbat_vchg_microvolts) + { + LOG_I("Trickle charging enabled at %uuV", rrtc->bbat_vchg_microvolts); + } + + return err; +} + +static rt_err_t rpi_rtc_alarm_irq_is_enabled(struct rpi_rtc *rrtc, + rt_bool_t *enabled) +{ + rt_err_t err; + rt_uint32_t data[2] = { RTC_ALARM_ENABLE }; + + err = rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + + *enabled = !!(data[1] & 0x1); + + return err; +} + +static rt_err_t rpi_rtc_alarm_irq_enable(struct rpi_rtc *rrtc, rt_bool_t enabled) +{ + rt_uint32_t data[2] = { RTC_ALARM_ENABLE, enabled }; + + return rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); +} + +static rt_err_t rpi_rtc_read_time(struct rpi_rtc *rrtc, time_t *sec) +{ + rt_err_t err; + rt_uint32_t data[2] = { RTC_TIME }; + + err = rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + + *sec = data[1]; + + return err; +} + +static rt_err_t rpi_rtc_set_time(struct rpi_rtc *rrtc, time_t *sec) +{ + rt_uint32_t data[2] = { RTC_TIME, (rt_uint32_t)*sec }; + + return rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); +} + +static rt_err_t rpi_rtc_read_alarm(struct rpi_rtc *rrtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_err_t err; + rt_uint32_t data[2] = { RTC_ALARM }; + + if (!(err = rpi_rtc_alarm_irq_is_enabled(rrtc, &alarm->enable))) + { + err = rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_GET_RTC_REG, + &data, sizeof(data)); + } + + rtc_timestamp_to_wkalarm(data[1], alarm); + + return err; +} + +static rt_err_t rpi_rtc_set_alarm(struct rpi_rtc *rrtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_err_t err; + struct rt_rtc_wkalarm *wkalarm = &rrtc->wkalarm; + rt_uint32_t data[2] = { RTC_ALARM, (rt_uint32_t)rtc_wkalarm_to_timestamp(alarm) }; + + err = rpi_firmware_property(rrtc->rpi_fw, RPI_FIRMWARE_SET_RTC_REG, + &data, sizeof(data)); + + if (!err && !(err = rpi_rtc_alarm_irq_enable(rrtc, alarm->enable))) + { + rt_mutex_take(&rrtc->lock, RT_WAITING_FOREVER); + + wkalarm->enable = alarm->enable; + wkalarm->tm_hour = alarm->tm_hour; + wkalarm->tm_min = alarm->tm_min; + wkalarm->tm_sec = alarm->tm_sec; + + if (wkalarm->enable) + { + /* + * raspberrypi firmware rtc have an IRQ pin that is not connected + * to a CPU interrupt but rather directly to a PMIC or power supply. + * So we should poll once per second. + */ + rt_tick_t tick = rt_tick_from_millisecond(1000); + + rt_timer_control(&rrtc->alarm_mon, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&rrtc->alarm_mon); + } + + rt_mutex_release(&rrtc->lock); + } + + return err; +} + +static rt_err_t rpi_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rpi_rtc *rrtc = raw_to_rpi_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + err = rpi_rtc_read_time(rrtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + err = rpi_rtc_set_time(rrtc, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + err = rpi_rtc_read_time(rrtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + err = rpi_rtc_set_time(rrtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + err = rpi_rtc_read_alarm(rrtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + err = rpi_rtc_set_alarm(rrtc, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops rpi_rtc_rtc_ops = +{ + .control = rpi_rtc_control, +}; +#endif + +static void rpi_rtc_alarm_mon(void *param) +{ + struct rpi_rtc *rrtc = param; + struct rt_rtc_wkalarm alarm; + time_t alarm_time, next_alarm_time; + + rt_mutex_take(&rrtc->lock, RT_WAITING_FOREVER); + + rpi_rtc_read_alarm(rrtc, &alarm); + alarm_time = rtc_wkalarm_to_timestamp(&alarm); + next_alarm_time = rtc_wkalarm_to_timestamp(&rrtc->wkalarm); + + if (alarm_time < next_alarm_time) + { + rrtc->wkalarm.enable = RT_FALSE; + rt_alarm_update(&rrtc->parent, 1); + } + + rt_mutex_release(&rrtc->lock); +} + +static rt_err_t rpi_rtc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + const char *dev_name; + struct rpi_firmware *rpi_fw; + struct rt_device *dev = &pdev->parent; + struct rt_ofw_node *np = dev->ofw_node, *fw_np; + struct rpi_rtc *rrtc = rt_calloc(1, sizeof(*rrtc)); + + if (!rrtc) + { + return -RT_ENOMEM; + } + + fw_np = rt_ofw_parse_phandle(np, "firmware", 0); + + if (!fw_np) + { + err = -RT_EINVAL; + goto _fail; + } + + rpi_fw = rpi_firmware_get(fw_np); + rt_ofw_node_put(fw_np); + + if (!rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + rrtc->rpi_fw = rpi_fw; + + rpi_rtc_alarm_clear_pending(rrtc); + + rt_ofw_prop_read_u32(np, "trickle-charge-microvolt", &rrtc->bbat_vchg_microvolts); + rpi_rtc_set_charge_voltage(rrtc); + + dev->user_data = rrtc; + + rrtc->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + rrtc->parent.ops = &rpi_rtc_rtc_ops; +#else + rrtc->parent.control = rpi_rtc_control; +#endif + + rtc_dev_set_name(&rrtc->parent); + dev_name = rt_dm_dev_get_name(&rrtc->parent); + + rt_mutex_init(&rrtc->lock, dev_name, RT_IPC_FLAG_FIFO); + rt_timer_init(&rrtc->alarm_mon, dev_name, rpi_rtc_alarm_mon, rrtc, + 0, RT_TIMER_FLAG_PERIODIC); + + rt_device_register(&rrtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + return RT_EOK; + +_fail: + rt_free(rrtc); + + return err; +} + +static rt_err_t rpi_rtc_remove(struct rt_platform_device *pdev) +{ + struct rpi_rtc *rrtc = pdev->parent.user_data; + + rt_timer_detach(&rrtc->alarm_mon); + rt_mutex_detach(&rrtc->lock); + rt_device_unregister(&rrtc->parent); + + rt_free(rrtc); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rpi_rtc_ofw_ids[] = +{ + { .compatible = "raspberrypi,rpi-rtc" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpi_rtc_driver = +{ + .name = "rtc-rpi", + .ids = rpi_rtc_ofw_ids, + + .probe = rpi_rtc_probe, + .remove = rpi_rtc_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpi_rtc_driver); diff --git a/bsp/raspberry-pi/dm/sdio/Kconfig b/bsp/raspberry-pi/dm/sdio/Kconfig new file mode 100755 index 0000000000..e484d3ec86 --- /dev/null +++ b/bsp/raspberry-pi/dm/sdio/Kconfig @@ -0,0 +1,9 @@ +config RT_SDIO_SDHCI_BRCMSTB + bool "Broadcom SDIO/SD/MMC" + depends on RT_USING_SDIO + select RT_USING_SDHCI + +config RT_SDIO_SDHCI_IPROC + bool "BCM2835 & iProc SD/MMC Controller" + depends on RT_USING_SDIO + select RT_USING_SDHCI diff --git a/bsp/raspberry-pi/dm/sdio/SConscript b/bsp/raspberry-pi/dm/sdio/SConscript new file mode 100755 index 0000000000..63915c15ae --- /dev/null +++ b/bsp/raspberry-pi/dm/sdio/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/sdio'] + +if GetDepend(['RT_SDIO_SDHCI_BRCMSTB']): + src += ['sdhci-brcmstb.c'] + +if GetDepend(['RT_SDIO_SDHCI_IPROC']): + src += ['sdhci-iproc.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/sdio/sdhci-brcmstb.c b/bsp/raspberry-pi/dm/sdio/sdhci-brcmstb.c new file mode 100755 index 0000000000..d77a3f781e --- /dev/null +++ b/bsp/raspberry-pi/dm/sdio/sdhci-brcmstb.c @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-01-01 GuEe-GUI The first version + */ + +#include +#include + +#define DBG_TAG "sdhci.brcmstb" +#define DBG_LVL DBG_INFO +#include + +#include "dev_sdio_dm.h" +#include "dev_sdhci_dm.h" + +#define SDHCI_VENDOR 0x78 +#define SDHCI_VENDOR_ENHANCED_STRB 0x1 +#define SDHCI_VENDOR_GATE_SDCLK_EN 0x2 + +#define BRCMSTB_MATCH_FLAGS_NO_64BIT RT_BIT(0) +#define BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT RT_BIT(1) +#define BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE RT_BIT(2) +#define BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY RT_BIT(3) + +#define BRCMSTB_PRIV_FLAGS_HAS_CQE RT_BIT(0) +#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK RT_BIT(1) +#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS RT_BIT(2) + +#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 + +#define SDIO_CFG_CTRL 0x0 +#define SDIO_CFG_CTRL_SDCD_N_TEST_EN RT_BIT(31) +#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV RT_BIT(30) + +#define SDIO_CFG_SD_PIN_SEL 0x44 +#define SDIO_CFG_SD_PIN_SEL_MASK 0x3 +#define SDIO_CFG_SD_PIN_SEL_MMC RT_BIT(0) +#define SDIO_CFG_SD_PIN_SEL_SD RT_BIT(1) + +#define SDIO_CFG_CQ_CAPABILITY 0x4c +#define SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT 12 + +#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac +#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE RT_BIT(31) +#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE RT_BIT(0) + +struct sdhci_brcmstb_priv +{ + void *cfg_regs; + + struct rt_clk *base_clk; + + rt_uint32_t flags; + rt_uint32_t base_freq_hz; +}; + +struct brcmstb_match_priv +{ + void (*hs400es)(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios); + void (*cfginit)(struct rt_sdhci_host *host); + struct rt_sdhci_ops *ops; + const rt_uint32_t flags; +}; + +rt_inline void enable_clock_gating(struct rt_sdhci_host *host) +{ + rt_uint32_t reg; + + reg = rt_sdhci_readl(host, SDHCI_VENDOR); + reg |= SDHCI_VENDOR_GATE_SDCLK_EN; + rt_sdhci_writel(host, reg, SDHCI_VENDOR); +} + +static void brcmstb_reset(struct rt_sdhci_host *host, rt_uint8_t mask) +{ + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = rt_sdhci_pltfm_priv(pltfm_host); + + /* Reset cqhci first if CQE supported */ + rt_sdhci_reset(host, mask); + + /* Reset will clear this, so re-enable it */ + if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK) + { + enable_clock_gating(host); + } +} + +static void sdhci_brcmstb_hs400es(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) +{ + rt_uint32_t reg; + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + reg = HWREG32(host->ioaddr + SDHCI_VENDOR); + + if (ios->enhanced_strobe) + { + reg |= SDHCI_VENDOR_ENHANCED_STRB; + } + else + { + reg &= ~SDHCI_VENDOR_ENHANCED_STRB; + } + + HWREG32(host->ioaddr + SDHCI_VENDOR) = reg; +} + +static void sdhci_brcmstb_set_clock(struct rt_sdhci_host *host, unsigned int clock) +{ + rt_uint16_t clk; + + host->mmc->actual_clock = 0; + + clk = rt_sdhci_clk_set(host, clock, &host->mmc->actual_clock); + rt_sdhci_writew(host, clk, RT_SDHCI_CLOCK_CONTROL); + + if (clock == 0) + { + return; + } + + rt_sdhci_clk_enable(host, clk); +} + +static void sdhci_brcmstb_set_power(struct rt_sdhci_host *host, unsigned char mode, + unsigned short vdd) +{ + if (!rt_is_err_or_null(host->mmc->rthost.supply.vmmc)) + { + sdio_regulator_set_ocr(&host->mmc->rthost, host->mmc->rthost.supply.vmmc, vdd); + } + + rt_sdhci_set_power_with_noreg(host, mode, vdd); +} + +static void sdhci_bcm2712_set_clock(struct rt_sdhci_host *host, unsigned int clock) +{ + rt_uint16_t clk; + rt_uint32_t reg; + rt_bool_t is_emmc_rate = RT_FALSE; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = rt_sdhci_pltfm_priv(pltfm_host); + + host->mmc->actual_clock = 0; + + rt_sdhci_writew(host, 0, RT_SDHCI_CLOCK_CONTROL); + + switch (host->mmc->ios.timing) + { + case MMC_TIMING_MMC_HS400: + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_MMC_DDR52: + case MMC_TIMING_MMC_HS: + is_emmc_rate = RT_TRUE; + break; + default: + break; + } + + reg = HWREG32(priv->cfg_regs + SDIO_CFG_SD_PIN_SEL); + reg &= ~SDIO_CFG_SD_PIN_SEL_MASK; + if (is_emmc_rate) + { + reg |= SDIO_CFG_SD_PIN_SEL_MMC; + } + else + { + reg |= SDIO_CFG_SD_PIN_SEL_SD; + } + HWREG32(priv->cfg_regs + SDIO_CFG_SD_PIN_SEL) = reg; + + if (clock == 0) + { + return; + } + + clk = rt_sdhci_clk_set(host, clock, &host->mmc->actual_clock); + rt_sdhci_clk_enable(host, clk); +} + +static void sdhci_bcm2712_hs400_downgrade(struct rt_mmc_host *mmc) +{ + struct rt_sdhci_host *host = rt_mmc_priv(mmc); + + /* + * The eMMC PHY refuses to update if HS timings are selected while + * the clock is above 52MHz, so lower it before mode transitions. + */ + sdhci_bcm2712_set_clock(host, 52000000); +} + +static void sdhci_brcmstb_set_uhs_signaling(struct rt_sdhci_host *host, + unsigned int timing) +{ + rt_uint16_t ctrl_2; + + ctrl_2 = rt_sdhci_readw(host, RT_SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~RT_SDHCI_CTRL_UHS_MASK; + + if (timing == MMC_TIMING_MMC_HS200 || timing == MMC_TIMING_UHS_SDR104) + { + ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR104; + } + else if (timing == MMC_TIMING_UHS_SDR12) + { + ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR12; + } + else if (timing == MMC_TIMING_SD_HS || timing == MMC_TIMING_MMC_HS || + timing == MMC_TIMING_UHS_SDR25) + { + ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR25; + } + else if (timing == MMC_TIMING_UHS_SDR50) + { + ctrl_2 |= RT_SDHCI_CTRL_UHS_SDR50; + } + else if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52) + { + ctrl_2 |= RT_SDHCI_CTRL_UHS_DDR50; + } + else if (timing == MMC_TIMING_MMC_HS400) + { + ctrl_2 |= RT_SDHCI_CTRL_HS400; /* Non-standard */ + } + + rt_sdhci_writew(host, ctrl_2, RT_SDHCI_HOST_CONTROL2); +} + +static void sdhci_brcmstb_cfginit_2712(struct rt_sdhci_host *host) +{ + rt_uint32_t uhs_mask, hsemmc_mask, reg, base_clk_mhz; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_brcmstb_priv *brcmstb_priv = rt_sdhci_pltfm_priv(pltfm_host); + + uhs_mask = (MMCSD_SUP_SDR50 | MMCSD_SUP_SDR104); + hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR | + MMCSD_SUP_HS400_1V8 | MMCSD_SUP_HS400_1V2); + + /* + * If we support a speed that requires tuning, + * then select the delay line PHY as the clock source. + */ + if ((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask)) + { + reg = HWREG32(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE); + reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE; + reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE; + HWREG32(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE) = reg; + + host->mmc_host_ops.hs400_downgrade = sdhci_bcm2712_hs400_downgrade; + } + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + (host->mmc->caps & MMC_CAP_NEEDS_POLL)) + { + /* Force presence */ + reg = HWREG32(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL); + reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; + reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN; + HWREG32(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL) = reg; + } + + /* Guesstimate the timer frequency (controller base clock) */ + base_clk_mhz = rt_clk_get_rate(pltfm_host->clk) / 1000000; + if (base_clk_mhz == 0) + { + base_clk_mhz = 1; + } + reg = (3 << SDIO_CFG_CQ_CAPABILITY_FMUL_SHIFT) | base_clk_mhz; + HWREG32(brcmstb_priv->cfg_regs + SDIO_CFG_CQ_CAPABILITY) = reg; +} + +static struct rt_sdhci_ops sdhci_brcmstb_ops = +{ + .set_clock = rt_sdhci_set_clock, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = rt_sdhci_reset, + .set_uhs_signaling = rt_sdhci_set_uhs, +}; + +static struct rt_sdhci_ops sdhci_brcmstb_ops_2712 = +{ + .set_clock = sdhci_bcm2712_set_clock, + .set_power = sdhci_brcmstb_set_power, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = brcmstb_reset, + .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling, +}; + +static struct rt_sdhci_ops sdhci_brcmstb_ops_7216 = +{ + .set_clock = sdhci_brcmstb_set_clock, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = brcmstb_reset, + .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling, +}; + +static struct brcmstb_match_priv match_priv_7425 = +{ + .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT | BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, + .ops = &sdhci_brcmstb_ops, +}; + +static struct brcmstb_match_priv match_priv_7445 = +{ + .flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT, + .ops = &sdhci_brcmstb_ops, +}; + +static const struct brcmstb_match_priv match_priv_7216 = +{ + .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE, + .hs400es = sdhci_brcmstb_hs400es, + .ops = &sdhci_brcmstb_ops_7216, +}; + +static const struct brcmstb_match_priv match_priv_2712 = +{ + .flags = BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY, + .hs400es = sdhci_brcmstb_hs400es, + .cfginit = sdhci_brcmstb_cfginit_2712, + .ops = &sdhci_brcmstb_ops_2712, +}; + +#ifdef RT_USING_PM +static rt_err_t sdhci_brcmstb_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + struct rt_sdhci_host *host = device->user_data; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = rt_sdhci_pltfm_priv(pltfm_host); + + rt_clk_disable_unprepare(priv->base_clk); + + return rt_sdhci_pltfm_suspend(device); +} + +static void sdhci_brcmstb_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + struct rt_sdhci_host *host = device->user_data; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_brcmstb_priv *priv = rt_sdhci_pltfm_priv(pltfm_host); + + if (!rt_sdhci_pltfm_resume(device) && priv->base_freq_hz) + { + if (!rt_clk_prepare_enable(priv->base_clk) && + rt_clk_get_rate(priv->base_clk) != priv->base_freq_hz) + { + rt_clk_set_rate(priv->base_clk, priv->base_freq_hz); + } + } +} + +static const struct rt_device_pm_ops sdhci_brcmstb_pm_ops = +{ + .suspend = sdhci_brcmstb_pm_suspend, + .resume = sdhci_brcmstb_pm_resume, +}; +#endif /* RT_USING_PM */ + +static rt_err_t sdhci_brcmstb_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t actual_clock_mhz; + struct rt_clk *clk, *base_clk = RT_NULL; + struct rt_device *dev = &pdev->parent; + struct rt_sdhci_host *host; + struct sdhci_brcmstb_priv *priv; + struct rt_sdhci_pltfm_host *pltfm_host; + struct rt_sdhci_pltfm_data brcmstb_pdata; + const struct brcmstb_match_priv *match_priv; + + match_priv = pdev->id->data; + + clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(clk)) + { + return rt_ptr_err(clk); + } + + if ((err = rt_clk_prepare_enable(clk))) + { + goto _free_clk; + } + + rt_memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata)); + brcmstb_pdata.ops = match_priv->ops; + + host = rt_sdhci_pltfm_init(pdev, &brcmstb_pdata, sizeof(struct sdhci_brcmstb_priv)); + if (!host) + { + err = -RT_ERROR; + goto _disable_free_clk; + } + + pltfm_host = rt_sdhci_priv(host); + priv = rt_sdhci_pltfm_priv(pltfm_host); + pltfm_host->clk = clk; + + /* Check property "supports-cqe" and set cqhci IRQ here */ + + /* + * Read ref node "sde-pcie". + * Init SDE regulator "sde-1v8", MMIO[1/2], pinctrl[default/sdex] + */ + + /* Map in the non-standard CFG registers */ + priv->cfg_regs = rt_dm_dev_iomap_by_name(dev, "cfg"); + if (!priv->cfg_regs) + { + priv->cfg_regs = rt_dm_dev_iomap(dev, 1); + } + + if (!priv->cfg_regs) + { + err = -RT_EIO; + goto _free_cfg; + } + + rt_sdhci_get_of_property(pdev); + + if ((err = rt_mmc_of_parse(host->mmc))) + { + goto _free_cfg; + } + + /* + * Automatic clock gating does not work for SD cards that may + * voltage switch so only enable it for non-removable devices. + */ + if ((match_priv->flags & BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE) && + (host->mmc->caps & MMC_CAP_NONREMOVABLE)) + { + priv->flags |= BRCMSTB_PRIV_FLAGS_GATE_CLOCK; + } + + /* + * If the chip has enhanced strobe and it's enabled, add + * callback + */ + if (match_priv->hs400es && (host->mmc->caps2 & MMC_CAP2_HS400_ES)) + { + host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es; + } + + if (match_priv->cfginit) + { + match_priv->cfginit(host); + } + + /* + * Supply the existing CAPS, but clear the UHS modes. This + * will allow these modes to be specified by device tree + * properties through rt_mmc_of_parse(). + */ + host->caps = rt_sdhci_readl(host, RT_SDHCI_CAPABILITIES); + if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT) + { + host->caps &= ~RT_SDHCI_CAN_64BIT; + } + host->caps1 = rt_sdhci_readl(host, RT_SDHCI_CAPABILITIES_1); + host->caps1 &= ~(RT_SDHCI_SUPPORT_SDR50 | RT_SDHCI_SUPPORT_SDR104 | RT_SDHCI_SUPPORT_DDR50); + + if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT) + { + host->quirks |= RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + } + + if (!(match_priv->flags & BRCMSTB_MATCH_FLAGS_USE_CARD_BUSY)) + { + host->mmc_host_ops.card_busy = RT_NULL; + } + + /* Change the base clock frequency if the DT property exists */ + if (rt_dm_dev_prop_read_u32(dev, "clock-frequency", &priv->base_freq_hz)) + { + goto _add_host; + } + + base_clk = rt_clk_get_by_name(dev, "sdio_freq"); + if (rt_is_err_or_null(base_clk)) + { + LOG_W("%s: Clock for \"sdio_freq\" not found", rt_dm_dev_get_name(dev)); + goto _add_host; + } + + if ((err = rt_clk_prepare_enable(base_clk))) + { + goto _free_base_clk; + } + + /* set improved clock rate */ + rt_clk_set_rate(base_clk, priv->base_freq_hz); + actual_clock_mhz = rt_clk_get_rate(base_clk) / 1000000; + + host->caps &= ~RT_SDHCI_CLOCK_V3_BASE_MASK; + host->caps |= (actual_clock_mhz << RT_SDHCI_CLOCK_BASE_SHIFT); + /* Disable presets because they are now incorrect */ + host->quirks2 |= RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + + LOG_D("%s: Base Clock Frequency changed to %dMHz", + rt_dm_dev_get_name(dev), actual_clock_mhz); + priv->base_clk = base_clk; + +_add_host: + /* The CQE should be enabled before here. */ + if ((err = rt_sdhci_set_and_add_host(host))) + { + goto _err; + } + +#ifdef RT_USING_PM + rt_pm_device_register(dev, &sdhci_brcmstb_pm_ops); +#endif + + return RT_EOK; + +_err: + goto _free_cfg; + +_free_base_clk: + if (base_clk && base_clk != clk) + { + rt_clk_disable_unprepare(base_clk); + rt_clk_put(base_clk); + } + +_free_cfg: + if (host) + { + rt_sdhci_pltfm_free(pdev); + } + +_disable_free_clk: + rt_clk_disable_unprepare(clk); + +_free_clk: + rt_clk_put(clk); + + return err; +} + +static rt_err_t sdhci_brcmstb_remove(struct rt_platform_device *pdev) +{ +#ifdef RT_USING_PM + rt_pm_device_unregister(&pdev->parent); +#endif + + return rt_sdhci_pltfm_remove(pdev); +} + +static rt_err_t sdhci_brcmstb_shutdown(struct rt_platform_device *pdev) +{ + return sdhci_brcmstb_remove(pdev); +} + +static const struct rt_ofw_node_id sdhci_brcm_ofw_ids[] = +{ + { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, + { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, + { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, + { .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdhci_brcmstb_driver = +{ + .name = "sdhci-brcmstb", + .ids = sdhci_brcm_ofw_ids, + + .probe = sdhci_brcmstb_probe, + .remove = sdhci_brcmstb_remove, + .shutdown = sdhci_brcmstb_shutdown, +}; +RT_PLATFORM_DRIVER_EXPORT(sdhci_brcmstb_driver); diff --git a/bsp/raspberry-pi/dm/sdio/sdhci-iproc.c b/bsp/raspberry-pi/dm/sdio/sdhci-iproc.c new file mode 100755 index 0000000000..2341bc2d25 --- /dev/null +++ b/bsp/raspberry-pi/dm/sdio/sdhci-iproc.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-10-28 zhujiale The first version + * 2025-01-01 GuEe-GUI Move to DM + */ + +#include "dev_sdio_dm.h" +#include "dev_sdhci_dm.h" + +struct sdhci_iproc_data +{ + const struct rt_sdhci_pltfm_data *pdata; + rt_uint32_t caps; + rt_uint32_t caps1; + rt_uint32_t mmc_caps; + rt_bool_t missing_caps; +}; + +struct sdhci_iproc_host +{ + const struct sdhci_iproc_data *data; + rt_uint32_t shadow_cmd; + rt_uint32_t shadow_blk; + rt_bool_t is_cmd_shadowed; + rt_bool_t is_blk_shadowed; +}; + +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + +rt_inline rt_uint32_t sdhci_iproc_readl(struct rt_sdhci_host *host, int reg) +{ + return HWREG32(host->ioaddr + reg); +} + +static rt_uint16_t sdhci_iproc_readw(struct rt_sdhci_host *host, int reg) +{ + rt_uint16_t word; + rt_uint32_t val; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_iproc_host *iproc_host = rt_sdhci_pltfm_priv(pltfm_host); + + if ((reg == RT_SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) + { + /* Get the saved transfer mode */ + val = iproc_host->shadow_cmd; + } + else if ((reg == RT_SDHCI_BLOCK_SIZE || reg == RT_SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) + { + /* Get the saved block info */ + val = iproc_host->shadow_blk; + } + else + { + val = sdhci_iproc_readl(host, (reg & ~3)); + } + + word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + + return word; +} + +static rt_uint8_t sdhci_iproc_readb(struct rt_sdhci_host *host, int reg) +{ + rt_uint32_t val = sdhci_iproc_readl(host, (reg & ~3)); + rt_uint8_t byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; + + return byte; +} + +rt_inline void sdhci_iproc_writel(struct rt_sdhci_host *host, rt_uint32_t val, int reg) +{ + HWREG32(host->ioaddr + reg) = val; + + if (host->clock <= 400000) + { + /* Round up to micro-second four SD clock delay */ + if (host->clock) + { + rt_hw_us_delay((4 * 1000000 + host->clock - 1) / host->clock); + } + else + { + rt_hw_us_delay(10); + } + } +} + +static void sdhci_iproc_writew(struct rt_sdhci_host *host, rt_uint16_t val, int reg) +{ + rt_uint32_t oldval, newval; + rt_uint32_t word_shift = REG_OFFSET_IN_BITS(reg); + rt_uint32_t mask = 0xffff << word_shift; + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + struct sdhci_iproc_host *iproc_host = rt_sdhci_pltfm_priv(pltfm_host); + + if (reg == RT_SDHCI_COMMAND) + { + /* Write the block now as we are issuing a command */ + if (iproc_host->is_blk_shadowed) + { + sdhci_iproc_writel(host, iproc_host->shadow_blk, RT_SDHCI_BLOCK_SIZE); + iproc_host->is_blk_shadowed = false; + } + oldval = iproc_host->shadow_cmd; + iproc_host->is_cmd_shadowed = false; + } + else if ((reg == RT_SDHCI_BLOCK_SIZE || reg == RT_SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) + { + /* Block size and count are stored in shadow reg */ + oldval = iproc_host->shadow_blk; + } + else + { + /* Read reg, all other registers are not shadowed */ + oldval = sdhci_iproc_readl(host, (reg & ~3)); + } + newval = (oldval & ~mask) | (val << word_shift); + + if (reg == RT_SDHCI_TRANSFER_MODE) + { + /* Save the transfer mode until the command is issued */ + iproc_host->shadow_cmd = newval; + iproc_host->is_cmd_shadowed = RT_TRUE; + } + else if (reg == RT_SDHCI_BLOCK_SIZE || reg == RT_SDHCI_BLOCK_COUNT) + { + /* Save the block info until the command is issued */ + iproc_host->shadow_blk = newval; + iproc_host->is_blk_shadowed = RT_TRUE; + } + else + { + /* Command or other regular 32-bit write */ + sdhci_iproc_writel(host, newval, reg & ~3); + } +} + +static void sdhci_iproc_writeb(struct rt_sdhci_host *host, rt_uint8_t val, int reg) +{ + rt_uint32_t oldval = sdhci_iproc_readl(host, (reg & ~3)); + rt_uint32_t byte_shift = REG_OFFSET_IN_BITS(reg); + rt_uint32_t mask = 0xff << byte_shift; + rt_uint32_t newval = (oldval & ~mask) | (val << byte_shift); + + sdhci_iproc_writel(host, newval, reg & ~3); +} + +static unsigned int sdhci_iproc_get_max_clock(struct rt_sdhci_host *host) +{ + struct rt_sdhci_pltfm_host *pltfm_host = rt_sdhci_priv(host); + + if (pltfm_host->clk) + { + return rt_sdhci_pltfm_clk_get_max_clock(host); + } + else + { + return pltfm_host->clock; + } +} + +static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct rt_sdhci_host *host) +{ + return 200000; +} + +static const struct rt_sdhci_ops sdhci_iproc_ops = +{ + .set_clock = rt_sdhci_set_clock, + .get_max_clock = sdhci_iproc_get_max_clock, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = rt_sdhci_reset, + .set_uhs_signaling = rt_sdhci_set_uhs, +}; + +static const struct rt_sdhci_ops sdhci_iproc_32only_ops = +{ + .read_l = sdhci_iproc_readl, + .read_w = sdhci_iproc_readw, + .read_b = sdhci_iproc_readb, + .write_l = sdhci_iproc_writel, + .write_w = sdhci_iproc_writew, + .write_b = sdhci_iproc_writeb, + .set_clock = rt_sdhci_set_clock, + .get_max_clock = sdhci_iproc_get_max_clock, + .set_power = rt_sdhci_set_power_and_bus_voltage, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = rt_sdhci_reset, + .set_uhs_signaling = rt_sdhci_set_uhs, +}; + +static const struct rt_sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = +{ + .quirks = RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | RT_SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = RT_SDHCI_QUIRK2_ACMD23_BROKEN | RT_SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .ops = &sdhci_iproc_32only_ops, +}; + +static const struct sdhci_iproc_data iproc_cygnus_data = +{ + .pdata = &sdhci_iproc_cygnus_pltfm_data, + .caps = ((0x1 << RT_SDHCI_MAX_BLOCK_SHIFT) & RT_SDHCI_MAX_BLOCK_MASK) | + RT_SDHCI_CAN_VDD_330 | RT_SDHCI_CAN_VDD_180 | RT_SDHCI_CAN_DO_SUSPEND | + RT_SDHCI_CAN_DO_HISPD | RT_SDHCI_CAN_DO_ADMA2 | RT_SDHCI_CAN_DO_SDMA, + .caps1 = RT_SDHCI_DRIVER_TYPE_C | RT_SDHCI_DRIVER_TYPE_D | RT_SDHCI_SUPPORT_DDR50, + .mmc_caps = MMC_CAP_1_8V_DDR, +}; + +static const struct rt_sdhci_pltfm_data sdhci_iproc_pltfm_data = +{ + .quirks = RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 | + RT_SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = RT_SDHCI_QUIRK2_ACMD23_BROKEN, + .ops = &sdhci_iproc_ops, +}; + +static const struct sdhci_iproc_data iproc_data = +{ + .pdata = &sdhci_iproc_pltfm_data, + .caps = ((0x1 << RT_SDHCI_MAX_BLOCK_SHIFT) & RT_SDHCI_MAX_BLOCK_MASK) | + RT_SDHCI_CAN_VDD_330 | + RT_SDHCI_CAN_VDD_180 | + RT_SDHCI_CAN_DO_SUSPEND | + RT_SDHCI_CAN_DO_HISPD | + RT_SDHCI_CAN_DO_ADMA2 | + RT_SDHCI_CAN_DO_SDMA, + .caps1 = RT_SDHCI_DRIVER_TYPE_C | RT_SDHCI_DRIVER_TYPE_D | RT_SDHCI_SUPPORT_DDR50, +}; + +static const struct rt_sdhci_pltfm_data sdhci_bcm2835_pltfm_data = +{ + .quirks = RT_SDHCI_QUIRK_BROKEN_CARD_DETECTION | + RT_SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + RT_SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = RT_SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .ops = &sdhci_iproc_32only_ops, +}; + +static const struct sdhci_iproc_data bcm2835_data = +{ + .pdata = &sdhci_bcm2835_pltfm_data, + .caps = ((0x1 << RT_SDHCI_MAX_BLOCK_SHIFT) & RT_SDHCI_MAX_BLOCK_MASK) | + RT_SDHCI_CAN_VDD_330 | RT_SDHCI_CAN_DO_HISPD, + .caps1 = RT_SDHCI_DRIVER_TYPE_A | RT_SDHCI_DRIVER_TYPE_C, + .mmc_caps = 0x00000000, + .missing_caps = RT_TRUE, +}; + +static const struct rt_sdhci_ops sdhci_iproc_bcm2711_ops = +{ + .read_l = sdhci_iproc_readl, + .read_w = sdhci_iproc_readw, + .read_b = sdhci_iproc_readb, + .write_l = sdhci_iproc_writel, + .write_w = sdhci_iproc_writew, + .write_b = sdhci_iproc_writeb, + .set_clock = rt_sdhci_set_clock, + .set_power = rt_sdhci_set_power_and_bus_voltage, + .get_max_clock = sdhci_iproc_get_max_clock, + .get_min_clock = sdhci_iproc_bcm2711_get_min_clock, + .set_bus_width = rt_sdhci_set_bus_width, + .reset = rt_sdhci_reset, + .set_uhs_signaling = rt_sdhci_set_uhs, +}; + +static const struct rt_sdhci_pltfm_data sdhci_bcm2711_pltfm_data = +{ + .quirks = RT_SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, + .ops = &sdhci_iproc_bcm2711_ops, +}; + +static const struct sdhci_iproc_data bcm2711_data = +{ + .pdata = &sdhci_bcm2711_pltfm_data, + .mmc_caps = MMC_CAP_3_3V_DDR, +}; + +static const struct rt_sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = +{ + .quirks = RT_SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + RT_SDHCI_QUIRK_BROKEN_DMA | + RT_SDHCI_QUIRK_BROKEN_ADMA, + .ops = &sdhci_iproc_ops, +}; + +#define BCM7211A0_BASE_CLK_MHZ 100 +static const struct sdhci_iproc_data bcm7211a0_data = +{ + .pdata = &sdhci_bcm7211a0_pltfm_data, + .caps = ((BCM7211A0_BASE_CLK_MHZ / 2) << RT_SDHCI_TIMEOUT_CLK_SHIFT) | + (BCM7211A0_BASE_CLK_MHZ << RT_SDHCI_CLOCK_BASE_SHIFT) | + ((0x2 << RT_SDHCI_MAX_BLOCK_SHIFT) & RT_SDHCI_MAX_BLOCK_MASK) | + RT_SDHCI_CAN_VDD_330 | + RT_SDHCI_CAN_VDD_180 | + RT_SDHCI_CAN_DO_SUSPEND | + RT_SDHCI_CAN_DO_HISPD, + .caps1 = RT_SDHCI_DRIVER_TYPE_C | RT_SDHCI_DRIVER_TYPE_D, + .missing_caps = RT_TRUE, +}; + +static rt_err_t sdhci_iproc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_sdhci_host *host; + struct sdhci_iproc_host *iproc_host; + struct rt_sdhci_pltfm_host *pltfm_host; + struct rt_device *dev = &pdev->parent; + const struct sdhci_iproc_data *iproc_data = RT_NULL; + + iproc_data = pdev->id->data; + if (!iproc_data) + { + return -RT_EINVAL; + } + + host = rt_sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); + if (!host) + { + return -RT_ERROR; + } + + pltfm_host = rt_sdhci_priv(host); + iproc_host = rt_sdhci_pltfm_priv(pltfm_host); + + iproc_host->data = iproc_data; + + err = rt_mmc_of_parse(host->mmc); + if (err) + { + goto _err; + } + + rt_sdhci_get_property(pdev); + + host->mmc->caps |= iproc_host->data->mmc_caps; + + if (dev->ofw_node) + { + pltfm_host->clk = rt_clk_get_by_index(dev, 0); + if (rt_is_err(pltfm_host->clk)) + { + err = rt_ptr_err(pltfm_host->clk); + goto _err; + } + + err = rt_clk_prepare_enable(pltfm_host->clk); + if (err) + { + goto _err; + } + } + + /* + * Controllers such as bcm2835 SDIO report unreliable/zero voltage bits in + * CAPABILITIES; rt_sdhci_setup_host() would otherwise overwrite software + * caps when calling rt_sdhci_read_caps(..., NULL, NULL). Seed caps once + * here so the read_caps "already done" guard keeps platform values. + */ + if (iproc_host->data->missing_caps) + { + rt_sdhci_read_caps(host, RT_NULL, &iproc_host->data->caps, &iproc_host->data->caps1); + } + + err = rt_sdhci_set_and_add_host(host); + if (err) + { + goto _err_clk; + } + + return RT_EOK; + +_err_clk: + if (dev->ofw_node) + { + rt_clk_disable_unprepare(pltfm_host->clk); + } + +_err: + rt_sdhci_pltfm_free(pdev); + + return err; +} + +static const struct rt_ofw_node_id sdhci_iproc_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data }, + { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2711_data }, + { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data}, + { .compatible = "brcm,sdhci-iproc", .data = &iproc_data }, + { .compatible = "brcm,bcm7211a0-sdhci", .data = &bcm7211a0_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdhci_iproc_driver = +{ + .name = "sdhci-iproc", + .ids = sdhci_iproc_ofw_ids, + + .probe = sdhci_iproc_probe, + .remove = rt_sdhci_pltfm_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(sdhci_iproc_driver); diff --git a/bsp/raspberry-pi/dm/serial/8250-bcm2835aux.c b/bsp/raspberry-pi/dm/serial/8250-bcm2835aux.c new file mode 100755 index 0000000000..1288c3873f --- /dev/null +++ b/bsp/raspberry-pi/dm/serial/8250-bcm2835aux.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-16 GuEe-GUI first version + */ + +#include + +#include "8250.h" + +#define BCM2835_AUX_UART_CNTL 8 +#define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */ +#define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */ +#define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */ +#define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */ +#define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */ +#define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */ +#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */ +#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */ + +struct bcm2835aux +{ + struct serial8250 parent; + rt_uint32_t cntl; +}; + +#define to_bcm2835aux(serial8250) rt_container_of(serial8250, struct bcm2835aux, parent) + +static void bcm2835aux_free_resource(struct bcm2835aux *bcm2835aux) +{ + struct serial8250 *serial = &bcm2835aux->parent; + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (!rt_is_err_or_null(serial->clk)) + { + rt_clk_disable_unprepare(serial->clk); + rt_clk_put(serial->clk); + } + + rt_free(bcm2835aux); +} + +static void bcm2835aux_serial_remove(struct serial8250 *serial) +{ + struct bcm2835aux *bcm2835aux = to_bcm2835aux(serial); + + bcm2835aux_free_resource(bcm2835aux); +} + +static rt_err_t bcm2835aux_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct serial8250 *serial; + struct rt_device *dev = &pdev->parent; + struct bcm2835aux *bcm2835aux = serial8250_alloc(bcm2835aux); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!bcm2835aux) + { + return -RT_ENOMEM; + } + + serial = &bcm2835aux->parent; + + serial->base = rt_dm_dev_iomap(dev, 0); + + if (!serial->base) + { + err = -RT_ERROR; + goto _free_res; + } + + serial->irq = rt_dm_dev_get_irq(dev, 0); + + if (serial->irq < 0) + { + err = serial->irq; + goto _free_res; + } + + serial->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(serial->clk)) + { + err = rt_ptr_err(serial->clk); + goto _free_res; + } + + if ((err = rt_clk_enable(serial->clk))) + { + goto _free_res; + } + + serial->freq = rt_clk_get_rate(serial->clk); + + dev->user_data = serial; + + rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent); + + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->regshift = 2; + serial->iotype = PORT_MMIO; + serial->remove = &bcm2835aux_serial_remove; + serial->data = bcm2835aux; + + bcm2835aux->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN; + + if ((err = serial8250_setup(serial))) + { + goto _free_res; + } + + return RT_EOK; + +_free_res: + bcm2835aux_free_resource(bcm2835aux); + + return err; +} + +static rt_err_t bcm2835aux_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct serial8250 *serial = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + return serial8250_remove(serial); +} + +static const struct rt_ofw_node_id bcm2835aux_ofw_ids[] = +{ + { .type = "ttyS", .compatible = "brcm,bcm2835-aux-uart" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835aux_driver = +{ + .name = "bcm2835-aux-uart", + .ids = bcm2835aux_ofw_ids, + + .probe = bcm2835aux_probe, + .remove = bcm2835aux_remove, +}; + +static int bcm2835aux_drv_register(void) +{ + rt_platform_driver_register(&bcm2835aux_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(bcm2835aux_drv_register); diff --git a/bsp/raspberry-pi/dm/serial/8250-bcm7271.c b/bsp/raspberry-pi/dm/serial/8250-bcm7271.c new file mode 100755 index 0000000000..792e8001a2 --- /dev/null +++ b/bsp/raspberry-pi/dm/serial/8250-bcm7271.c @@ -0,0 +1,1095 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include + +#define DBG_TAG "serial.8250.bcm7271" +#define DBG_LVL DBG_INFO +#include + +#include "8250.h" + +/* Register definitions for UART DMA block. Version 1.1 or later. */ +#define UDMA_ARB_RX 0x00 +#define UDMA_ARB_TX 0x04 +#define UDMA_ARB_REQ 0x00000001 +#define UDMA_ARB_GRANT 0x00000002 + +#define UDMA_RX_REVISION 0x00 +#define UDMA_RX_REVISION_REQUIRED 0x00000101 +#define UDMA_RX_CTRL 0x04 +#define UDMA_RX_CTRL_BUF_CLOSE_MODE 0x00010000 +#define UDMA_RX_CTRL_MASK_WR_DONE 0x00008000 +#define UDMA_RX_CTRL_ENDIAN_OVERRIDE 0x00004000 +#define UDMA_RX_CTRL_ENDIAN 0x00002000 +#define UDMA_RX_CTRL_OE_IS_ERR 0x00001000 +#define UDMA_RX_CTRL_PE_IS_ERR 0x00000800 +#define UDMA_RX_CTRL_FE_IS_ERR 0x00000400 +#define UDMA_RX_CTRL_NUM_BUF_USED_MASK 0x000003c0 +#define UDMA_RX_CTRL_NUM_BUF_USED_SHIFT 6 +#define UDMA_RX_CTRL_BUF_CLOSE_CLK_SEL_SYS 0x00000020 +#define UDMA_RX_CTRL_BUF_CLOSE_ENA 0x00000010 +#define UDMA_RX_CTRL_TIMEOUT_CLK_SEL_SYS 0x00000008 +#define UDMA_RX_CTRL_TIMEOUT_ENA 0x00000004 +#define UDMA_RX_CTRL_ABORT 0x00000002 +#define UDMA_RX_CTRL_ENA 0x00000001 +#define UDMA_RX_STATUS 0x08 +#define UDMA_RX_STATUS_ACTIVE_BUF_MASK 0x0000000f +#define UDMA_RX_TRANSFER_LEN 0x0c +#define UDMA_RX_TRANSFER_TOTAL 0x10 +#define UDMA_RX_BUFFER_SIZE 0x14 +#define UDMA_RX_SRC_ADDR 0x18 +#define UDMA_RX_TIMEOUT 0x1c +#define UDMA_RX_BUFFER_CLOSE 0x20 +#define UDMA_RX_BLOCKOUT_COUNTER 0x24 +#define UDMA_RX_BUF0_PTR_LO 0x28 +#define UDMA_RX_BUF0_PTR_HI 0x2c +#define UDMA_RX_BUF0_STATUS 0x30 +#define UDMA_RX_BUFX_STATUS_OVERRUN_ERR 0x00000010 +#define UDMA_RX_BUFX_STATUS_FRAME_ERR 0x00000008 +#define UDMA_RX_BUFX_STATUS_PARITY_ERR 0x00000004 +#define UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED 0x00000002 +#define UDMA_RX_BUFX_STATUS_DATA_RDY 0x00000001 +#define UDMA_RX_BUF0_DATA_LEN 0x34 +#define UDMA_RX_BUF1_PTR_LO 0x38 +#define UDMA_RX_BUF1_PTR_HI 0x3c +#define UDMA_RX_BUF1_STATUS 0x40 +#define UDMA_RX_BUF1_DATA_LEN 0x44 + +#define UDMA_TX_REVISION 0x00 +#define UDMA_TX_REVISION_REQUIRED 0x00000101 +#define UDMA_TX_CTRL 0x04 +#define UDMA_TX_CTRL_ENDIAN_OVERRIDE 0x00000080 +#define UDMA_TX_CTRL_ENDIAN 0x00000040 +#define UDMA_TX_CTRL_NUM_BUF_USED_MASK 0x00000030 +#define UDMA_TX_CTRL_NUM_BUF_USED_1 0x00000010 +#define UDMA_TX_CTRL_ABORT 0x00000002 +#define UDMA_TX_CTRL_ENA 0x00000001 +#define UDMA_TX_DST_ADDR 0x08 +#define UDMA_TX_BLOCKOUT_COUNTER 0x10 +#define UDMA_TX_TRANSFER_LEN 0x14 +#define UDMA_TX_TRANSFER_TOTAL 0x18 +#define UDMA_TX_STATUS 0x20 +#define UDMA_TX_BUF0_PTR_LO 0x24 +#define UDMA_TX_BUF0_PTR_HI 0x28 +#define UDMA_TX_BUF0_STATUS 0x2c +#define UDMA_TX_BUFX_LAST 0x00000002 +#define UDMA_TX_BUFX_EMPTY 0x00000001 +#define UDMA_TX_BUF0_DATA_LEN 0x30 +#define UDMA_TX_BUF0_DATA_SENT 0x34 +#define UDMA_TX_BUF1_PTR_LO 0x38 + +#define UDMA_INTR_STATUS 0x00 +#define UDMA_INTR_ARB_TX_GRANT 0x00040000 +#define UDMA_INTR_ARB_RX_GRANT 0x00020000 +#define UDMA_INTR_TX_ALL_EMPTY 0x00010000 +#define UDMA_INTR_TX_EMPTY_BUF1 0x00008000 +#define UDMA_INTR_TX_EMPTY_BUF0 0x00004000 +#define UDMA_INTR_TX_ABORT 0x00002000 +#define UDMA_INTR_TX_DONE 0x00001000 +#define UDMA_INTR_RX_ERROR 0x00000800 +#define UDMA_INTR_RX_TIMEOUT 0x00000400 +#define UDMA_INTR_RX_READY_BUF7 0x00000200 +#define UDMA_INTR_RX_READY_BUF6 0x00000100 +#define UDMA_INTR_RX_READY_BUF5 0x00000080 +#define UDMA_INTR_RX_READY_BUF4 0x00000040 +#define UDMA_INTR_RX_READY_BUF3 0x00000020 +#define UDMA_INTR_RX_READY_BUF2 0x00000010 +#define UDMA_INTR_RX_READY_BUF1 0x00000008 +#define UDMA_INTR_RX_READY_BUF0 0x00000004 +#define UDMA_INTR_RX_READY_MASK 0x000003fc +#define UDMA_INTR_RX_READY_SHIFT 2 +#define UDMA_INTR_RX_ABORT 0x00000002 +#define UDMA_INTR_RX_DONE 0x00000001 +#define UDMA_INTR_SET 0x04 +#define UDMA_INTR_CLEAR 0x08 +#define UDMA_INTR_MASK_STATUS 0x0c +#define UDMA_INTR_MASK_SET 0x10 +#define UDMA_INTR_MASK_CLEAR 0x14 + +#define UDMA_RX_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_READY_BUF0 | \ + UDMA_INTR_RX_READY_BUF1 | \ + UDMA_INTR_RX_READY_BUF2 | \ + UDMA_INTR_RX_READY_BUF3 | \ + UDMA_INTR_RX_READY_BUF4 | \ + UDMA_INTR_RX_READY_BUF5 | \ + UDMA_INTR_RX_READY_BUF6 | \ + UDMA_INTR_RX_READY_BUF7 | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_RX_ERR_INTERRUPTS ( \ + UDMA_INTR_RX_ERROR | \ + UDMA_INTR_RX_TIMEOUT | \ + UDMA_INTR_RX_ABORT | \ + UDMA_INTR_RX_DONE) + +#define UDMA_TX_INTERRUPTS ( \ + UDMA_INTR_TX_ABORT | \ + UDMA_INTR_TX_DONE) + +#define UDMA_IS_RX_INTERRUPT(status) ((status) & UDMA_RX_INTERRUPTS) +#define UDMA_IS_TX_INTERRUPT(status) ((status) & UDMA_TX_INTERRUPTS) + + +/* Current devices have 8 sets of RX buffer registers */ +#define UDMA_RX_BUFS_COUNT 8 +#define UDMA_RX_BUFS_REG_OFFSET (UDMA_RX_BUF1_PTR_LO - UDMA_RX_BUF0_PTR_LO) +#define UDMA_RX_BUFx_PTR_LO(x) (UDMA_RX_BUF0_PTR_LO + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_PTR_HI(x) (UDMA_RX_BUF0_PTR_HI + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_STATUS(x) (UDMA_RX_BUF0_STATUS + ((x) * UDMA_RX_BUFS_REG_OFFSET)) +#define UDMA_RX_BUFx_DATA_LEN(x) (UDMA_RX_BUF0_DATA_LEN + ((x) * UDMA_RX_BUFS_REG_OFFSET)) + +/* Current devices have 2 sets of TX buffer registers */ +#define UDMA_TX_BUFS_COUNT 2 +#define UDMA_TX_BUFS_REG_OFFSET (UDMA_TX_BUF1_PTR_LO - UDMA_TX_BUF0_PTR_LO) +#define UDMA_TX_BUFx_PTR_LO(x) (UDMA_TX_BUF0_PTR_LO + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_PTR_HI(x) (UDMA_TX_BUF0_PTR_HI + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_STATUS(x) (UDMA_TX_BUF0_STATUS + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_LEN(x) (UDMA_TX_BUF0_DATA_LEN + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define UDMA_TX_BUFx_DATA_SENT(x) (UDMA_TX_BUF0_DATA_SENT + ((x) * UDMA_TX_BUFS_REG_OFFSET)) +#define REGS_8250 0 +#define REGS_DMA_RX 1 +#define REGS_DMA_TX 2 +#define REGS_DMA_ISR 3 +#define REGS_DMA_ARB 4 +#define REGS_MAX 5 + +#define TX_BUF_SIZE 4096 +#define RX_BUF_SIZE 4096 +#define RX_BUFS_COUNT 2 +#define UART_XMIT_SIZE RT_DMA_PAGE_SIZE +#define KHZ 1000 +#define MHZ(x) ((x) * KHZ * KHZ) +#define NSEC_PER_SEC 1000000000L +#define NSEC_PER_MSEC 1000000L + +static const rt_uint32_t brcmstb_rate_table[] = +{ + MHZ(81), + MHZ(108), + MHZ(64), /* Actually 64285715 for some chips */ + MHZ(48), +}; + +static const rt_uint32_t brcmstb_rate_table_7278[] = +{ + MHZ(81), + MHZ(108), + 0, + MHZ(48), +}; + +struct brcmuart +{ + struct serial8250 parent; + + int dma_irq; + void *regs[REGS_MAX]; + struct rt_device *dev; + + rt_ubase_t default_mux_rate; + rt_uint32_t real_rates[RT_ARRAY_SIZE(brcmstb_rate_table)]; + const rt_uint32_t *rate_table; + + rt_uint32_t char_wait_ms; + struct rt_timer char_wait_work; + + rt_bool_t dma_enabled; + + void *rx_bufs; + int rx_index; + int rx_next_buf; + rt_ubase_t rx_addr; + rt_size_t rx_size; + rt_bool_t rx_running; + + void *tx_buf; + rt_ubase_t tx_addr; + rt_size_t tx_size; + rt_bool_t tx_running; +}; + +#define to_brcmuart(serial8250) rt_container_of(serial8250, struct brcmuart, parent) + +static rt_uint32_t udma_readl(struct brcmuart *brcmuart, int reg_type, int offset) +{ + return HWREG32(brcmuart->regs[reg_type] + offset); +} + +static void udma_writel(struct brcmuart *brcmuart, int reg_type, int offset, rt_uint32_t value) +{ + HWREG32(brcmuart->regs[reg_type] + offset) = value; +} + +static void udma_set(struct brcmuart *brcmuart, int reg_type, int offset, rt_uint32_t bits) +{ + rt_uint32_t value; + void *reg = brcmuart->regs[reg_type] + offset; + + value = HWREG32(reg); + value |= bits; + HWREG32(reg) = value; +} + +static void udma_unset(struct brcmuart *brcmuart, int reg_type, int offset, rt_uint32_t bits) +{ + rt_uint32_t value; + void *reg = brcmuart->regs[reg_type] + offset; + + value = HWREG32(reg); + value &= ~bits; + HWREG32(reg) = value; +} + +/* + * The UART DMA engine hardware can be used by multiple UARTS, but + * only one at a time. Sharing is not currently supported so + * the first UART to request the DMA engine will get it and any + * subsequent requests by other UARTS will fail. + */ +static int brcmuart_arbitration(struct brcmuart *brcmuart, rt_bool_t acquire) +{ + int ret = 0; + rt_uint32_t rx_grant, tx_grant; + + if (acquire) + { + int waits = 1; + + udma_set(brcmuart, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_set(brcmuart, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + + while (RT_TRUE) + { + rx_grant = udma_readl(brcmuart, REGS_DMA_ARB, UDMA_ARB_RX); + tx_grant = udma_readl(brcmuart, REGS_DMA_ARB, UDMA_ARB_TX); + + if (rx_grant & tx_grant & UDMA_ARB_GRANT) + { + return 0; + } + + if (waits-- == 0) + { + break; + } + + rt_thread_mdelay(1); + } + + ret = 1; + } + + udma_unset(brcmuart, REGS_DMA_ARB, UDMA_ARB_RX, UDMA_ARB_REQ); + udma_unset(brcmuart, REGS_DMA_ARB, UDMA_ARB_TX, UDMA_ARB_REQ); + + return ret; +} + +static void brcmuart_init_dma_hardware(struct brcmuart *brcmuart) +{ + rt_uint32_t daddr, value; + + /* Start with all interrupts disabled */ + udma_writel(brcmuart, REGS_DMA_ISR, UDMA_INTR_MASK_SET, 0xffffffff); + + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_BUFFER_SIZE, RX_BUF_SIZE); + + /* + * Setup buffer close to happen when 32 character times have + * elapsed since the last character was received. + */ + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_BUFFER_CLOSE, 16 * 10 *32); + value = (RX_BUFS_COUNT << UDMA_RX_CTRL_NUM_BUF_USED_SHIFT) + | UDMA_RX_CTRL_BUF_CLOSE_MODE + | UDMA_RX_CTRL_BUF_CLOSE_ENA; + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_CTRL, value); + + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_BLOCKOUT_COUNTER, 0); + daddr = brcmuart->rx_addr; + + for (int i = 0; i < RX_BUFS_COUNT; ++i) + { + /* Set RX transfer length to 0 for unknown */ + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_TRANSFER_LEN, 0); + + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_BUFx_PTR_LO(i), + rt_lower_32_bits(daddr)); + udma_writel(brcmuart, REGS_DMA_RX, UDMA_RX_BUFx_PTR_HI(i), + rt_upper_32_bits(daddr)); + daddr += RX_BUF_SIZE; + } + + daddr = brcmuart->tx_addr; + udma_writel(brcmuart, REGS_DMA_TX, UDMA_TX_BUFx_PTR_LO(0), + rt_lower_32_bits(daddr)); + udma_writel(brcmuart, REGS_DMA_TX, UDMA_TX_BUFx_PTR_HI(0), + rt_upper_32_bits(daddr)); + udma_writel(brcmuart, REGS_DMA_TX, UDMA_TX_CTRL, + UDMA_TX_CTRL_NUM_BUF_USED_1); + + /* Clear all interrupts then enable them */ + udma_writel(brcmuart, REGS_DMA_ISR, UDMA_INTR_CLEAR, 0xffffffff); + udma_writel(brcmuart, REGS_DMA_ISR, UDMA_INTR_MASK_CLEAR, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); +} + +static void start_rx_dma(struct brcmuart *brcmuart) +{ + udma_unset(brcmuart, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + + /* Clear the RX ready bit for all buffers */ + for (int i = 0; i < RX_BUFS_COUNT; ++i) + { + udma_unset(brcmuart, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(i), + UDMA_RX_BUFX_STATUS_DATA_RDY); + } + + /* Always start with buffer 0 */ + udma_unset(brcmuart, REGS_DMA_RX, UDMA_RX_STATUS, + UDMA_RX_STATUS_ACTIVE_BUF_MASK); + brcmuart->rx_next_buf = 0; + + udma_set(brcmuart, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ENA); + brcmuart->rx_running = RT_TRUE; +} + +static void stop_rx_dma(struct brcmuart *brcmuart) +{ + /* If RX is running, set the RX ABORT */ + if (brcmuart->rx_running) + { + udma_set(brcmuart, REGS_DMA_RX, UDMA_RX_CTRL, UDMA_RX_CTRL_ABORT); + } +} + +static int stop_tx_dma(struct brcmuart *brcmuart) +{ + rt_uint32_t value; + + /* If TX is running, set the TX ABORT */ + value = udma_readl(brcmuart, REGS_DMA_TX, UDMA_TX_CTRL); + + if (value & UDMA_TX_CTRL_ENA) + { + udma_set(brcmuart, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ABORT); + } + + brcmuart->tx_running = RT_FALSE; + return 0; +} + +static void brcmuart_rx_buf_done(struct brcmuart *brcmuart, int index) +{ + rt_uint32_t status, length; + + /* Make sure we're still in sync with the hardware */ + status = udma_readl(brcmuart, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(index)); + length = udma_readl(brcmuart, REGS_DMA_RX, UDMA_RX_BUFx_DATA_LEN(index)); + + if ((status & UDMA_RX_BUFX_STATUS_DATA_RDY) == 0) + { + LOG_E("RX done interrupt but DATA_RDY not found"); + return; + } + + if (status & (UDMA_RX_BUFX_STATUS_OVERRUN_ERR | + UDMA_RX_BUFX_STATUS_FRAME_ERR | + UDMA_RX_BUFX_STATUS_PARITY_ERR)) + { + if (status & UDMA_RX_BUFX_STATUS_OVERRUN_ERR) + { + LOG_W("RX Overrun"); + } + if (status & UDMA_RX_BUFX_STATUS_FRAME_ERR) + { + LOG_W("RX Framing"); + } + if (status & UDMA_RX_BUFX_STATUS_PARITY_ERR) + { + LOG_W("RX Parity"); + } + } + + brcmuart->rx_index = index * RX_BUF_SIZE; + serial8250_dma_rx_done(&brcmuart->parent, length); +} + +static void brcmuart_rx_work(struct brcmuart *brcmuart, rt_uint32_t rx_isr) +{ + rt_uint32_t rx_done_isr, check_isr; + + rx_done_isr = (rx_isr & UDMA_INTR_RX_READY_MASK); + + while (rx_done_isr) + { + check_isr = UDMA_INTR_RX_READY_BUF0 << brcmuart->rx_next_buf; + + if (check_isr & rx_done_isr) + { + brcmuart_rx_buf_done(brcmuart, brcmuart->rx_next_buf); + } + else + { + LOG_E("RX buffer ready out of sequence, restarting RX DMA"); + start_rx_dma(brcmuart); + + break; + } + if (rx_isr & UDMA_RX_ERR_INTERRUPTS) + { + if (rx_isr & UDMA_INTR_RX_ERROR) + { + LOG_D("RX Error"); + } + if (rx_isr & UDMA_INTR_RX_TIMEOUT) + { + LOG_E("RX Timeout"); + } + if (rx_isr & UDMA_INTR_RX_ABORT) + { + LOG_D("RX Abort"); + } + + brcmuart->rx_running = RT_FALSE; + } + /* If not ABORT, re-enable RX buffer */ + if (!(rx_isr & UDMA_INTR_RX_ABORT)) + { + udma_unset(brcmuart, REGS_DMA_RX, + UDMA_RX_BUFx_STATUS(brcmuart->rx_next_buf), UDMA_RX_BUFX_STATUS_DATA_RDY); + } + + rx_done_isr &= ~check_isr; + brcmuart->rx_next_buf++; + + if (brcmuart->rx_next_buf == RX_BUFS_COUNT) + { + brcmuart->rx_next_buf = 0; + } + } +} + +static void set_clock_mux(struct brcmuart *brcmuart, rt_uint32_t baud) +{ + rt_tick_t tick; + int best_index = -1, real_baud, i; + rt_uint64_t hires_rate, hires_baud, hires_err; + rt_uint32_t percent, best_percent = RT_UINT32_MAX, quot, best_quot = 1, rate; + + /* Find the closest match for specified baud */ + for (i = 0; i < RT_ARRAY_SIZE(brcmuart->real_rates); ++i) + { + if (brcmuart->real_rates[i] == 0) + { + continue; + } + + rate = brcmuart->real_rates[i] / 16; + quot = RT_DIV_ROUND_CLOSEST(rate, baud); + if (!quot) + { + continue; + } + + /* increase resolution to get xx.xx percent */ + hires_rate = (rt_uint64_t)rate * 10000; + hires_baud = (rt_uint64_t)baud * 10000; + + hires_err = rt_div_u64(hires_rate, (rt_uint64_t)quot); + + /* get the delta */ + if (hires_err > hires_baud) + { + hires_err = hires_err - hires_baud; + } + else + { + hires_err = hires_baud - hires_err; + } + + percent = (rt_ubase_t)RT_DIV_ROUND_CLOSEST_ULL(hires_err, baud); + + LOG_D("Baud rate: %u, MUX Clk: %u, Error: %u.%u%%", + baud, brcmuart->real_rates[i], percent / 100, percent % 100); + + if (percent < best_percent) + { + best_percent = percent; + best_index = i; + best_quot = quot; + } + } + + if (best_index == -1) + { + LOG_E("%d BAUD rate is too fast", baud); + return; + } + + rate = brcmuart->real_rates[best_index]; + + if (rt_clk_set_rate(brcmuart->parent.clk, rate)) + { + LOG_E("Selecting BAUD MUX clock"); + } + + /* Error over 3 percent will cause data errors */ + if (best_percent > 300) + { + LOG_E("Baud: %d has %u.%u%% error", baud, percent / 100, percent % 100); + } + + real_baud = rate / 16 / best_quot; + LOG_D("Selecting BAUD MUX rate: %u", rate); + LOG_D("Requested baud: %u, Actual baud: %u", baud, real_baud); + + /* calc nanoseconds for 1.5 characters time at the given baud rate */ + i = NSEC_PER_SEC / real_baud / 10; + i += (i / 2); + brcmuart->char_wait_ms = NSEC_PER_MSEC / i; + + tick = rt_tick_from_millisecond(brcmuart->char_wait_ms); + rt_timer_control(&brcmuart->char_wait_work, RT_TIMER_CTRL_SET_TIME, &tick); + + brcmuart->parent.freq = rate; +} + +static rt_err_t brcmstb_serial_ios(struct serial8250 *serial, struct serial_configure *ios) +{ + struct brcmuart *brcmuart = to_brcmuart(serial); + + if (brcmuart->dma_enabled) + { + stop_rx_dma(brcmuart); + } + + if (!rt_is_err_or_null(serial->clk)) + { + set_clock_mux(brcmuart, ios->baud_rate); + } + + serial8250_ios(serial, ios); + + if (brcmuart->dma_enabled) + { + start_rx_dma(brcmuart); + } + + return RT_EOK; +} + +static rt_err_t brcmuart_serial_dma_enable(struct serial8250 *serial, rt_bool_t enabled) +{ + struct brcmuart *brcmuart = to_brcmuart(serial); + + if (!brcmuart->dma_enabled) + { + return RT_EOK; + } + + if (enabled) + { + rt_uint32_t ier; + + ier = serial->serial_in(serial, UART_IER); + serial->serial_out(serial, UART_IER, ier & ~UART_IER_RDI); + + brcmuart_init_dma_hardware(brcmuart); + start_rx_dma(brcmuart); + } + else + { + rt_ubase_t level = rt_spin_lock_irqsave(&serial->spinlock); + + stop_rx_dma(brcmuart); + stop_tx_dma(brcmuart); + + /* Disable all interrupts */ + udma_writel(brcmuart, REGS_DMA_ISR, UDMA_INTR_MASK_SET, + UDMA_RX_INTERRUPTS | UDMA_TX_INTERRUPTS); + + rt_spin_unlock_irqrestore(&serial->spinlock, level); + } + + return RT_EOK; +} + +static rt_ssize_t brcmuart_serial_dma_tx(struct serial8250 *serial, + const rt_uint8_t *buf, rt_size_t size) +{ + struct brcmuart *brcmuart = to_brcmuart(serial); + + if (brcmuart->tx_running) + { + return 0; + } + + size = rt_min_t(rt_size_t, size, brcmuart->tx_size); + rt_memcpy(brcmuart->tx_buf, buf, size); + + udma_writel(brcmuart, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, size); + udma_writel(brcmuart, REGS_DMA_TX, UDMA_TX_BUF0_DATA_LEN, size); + udma_unset(brcmuart, REGS_DMA_TX, UDMA_TX_BUF0_STATUS, UDMA_TX_BUFX_EMPTY); + udma_set(brcmuart, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ENA); + brcmuart->tx_running = RT_TRUE; + + return size; +} + +static rt_ssize_t brcmuart_serial_dma_rx(struct serial8250 *serial, + rt_uint8_t *buf, rt_size_t size) +{ + struct brcmuart *brcmuart = to_brcmuart(serial); + + size = rt_min_t(rt_size_t, size, brcmuart->rx_size - brcmuart->rx_index); + rt_memcpy(buf, brcmuart->rx_bufs + brcmuart->rx_index, size); + + return size; +} + +static rt_err_t brcmuart_serial_isr(struct serial8250 *serial, int irq) +{ + rt_ubase_t level; + rt_uint32_t iir, ier, mcr, status; + struct brcmuart *brcmuart = to_brcmuart(serial); + + iir = serial->serial_in(serial, UART_LSR); + + /* + * There's a bug in some 8250 cores where we get a timeout + * interrupt but there is no data ready. + */ + if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT)) + { + level = rt_spin_lock_irqsave(&serial->spinlock); + + status = serial->serial_in(serial, UART_LSR); + + if ((status & UART_LSR_DR) == 0) + { + ier = serial->serial_in(serial, UART_IER); + mcr = serial->serial_in(serial, UART_MCR); + + /* + * if Receive Data Interrupt is enabled and + * we're uing hardware flow control, deassert + * RTS and wait for any chars in the pipline to + * arrive and then check for DR again. + */ + if ((ier & UART_IER_RDI) && (mcr & UART_MCR_AFE)) + { + ier &= ~(UART_IER_RLSI | UART_IER_RDI); + serial->serial_out(serial, UART_IER, ier); + + mcr = serial->serial_in(serial, UART_MCR); + mcr &= ~UART_MCR_RTS; + serial->serial_out(serial, UART_MCR, mcr); + + rt_timer_start(&brcmuart->char_wait_work); + } + else + { + serial->serial_in(serial, UART_RX); + } + } + + rt_spin_unlock_irqrestore(&serial->spinlock, level); + } + + return RT_EOK; +} + +static void brcmuart_dma_isr(int irqno, void *param) +{ + rt_ubase_t level; + rt_uint32_t interrupts, rval, tval; + struct brcmuart *brcmuart = param; + struct serial8250 *serial = &brcmuart->parent; + + interrupts = udma_readl(brcmuart, REGS_DMA_ISR, UDMA_INTR_STATUS); + + if (!interrupts) + { + return; + } + + level = rt_spin_lock_irqsave(&serial->spinlock); + + /* Clear all interrupts */ + udma_writel(brcmuart, REGS_DMA_ISR, UDMA_INTR_CLEAR, interrupts); + + if ((rval = UDMA_IS_RX_INTERRUPT(interrupts))) + { + brcmuart_rx_work(brcmuart, rval); + } + + if ((tval = UDMA_IS_TX_INTERRUPT(interrupts))) + { + if (tval & UDMA_INTR_TX_ABORT) + { + if (brcmuart->tx_running) + { + LOG_E("Unexpected TX_ABORT interrupt"); + } + } + else + { + brcmuart->tx_running = RT_FALSE; + serial8250_dma_tx_done(serial); + } + } + + if ((rval | tval) == 0) + { + LOG_W("Spurious interrupt: 0x%x", interrupts); + } + + rt_spin_unlock_irqrestore(&serial->spinlock, level); +} + +static void brcmuart_char_wait_work(void *param) +{ + rt_ubase_t level; + rt_uint32_t ier, status; + struct brcmuart *brcmuart = param; + struct serial8250 *serial = &brcmuart->parent; + + level = rt_spin_lock_irqsave(&serial->spinlock); + + status = serial->serial_in(serial, UART_LSR); + + /* + * If a character did not arrive after the timeout, clear the false + * receive timeout. + */ + if ((status & UART_LSR_DR) == 0) + { + serial->serial_in(serial, UART_RX); + } + ier = serial->serial_in(serial, UART_IER); + + /* re-enable receive unless upper layer has disabled it */ + if ((ier & (UART_IER_RLSI | UART_IER_RDI)) == (UART_IER_RLSI | UART_IER_RDI)) + { + status = serial->serial_in(serial, UART_IER); + status |= (UART_IER_RLSI | UART_IER_RDI); + serial->serial_out(serial, UART_IER, status); + status = serial->serial_in(serial, UART_MCR); + status |= UART_MCR_RTS; + serial->serial_out(serial, UART_MCR, status); + } + + rt_spin_unlock_irqrestore(&serial->spinlock, level); +} + +static void brcmuart_free_resource(struct brcmuart *brcmuart) +{ + struct serial8250 *serial = &brcmuart->parent; + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (!rt_is_err_or_null(serial->clk)) + { + rt_clk_disable_unprepare(serial->clk); + rt_clk_put(serial->clk); + } + + if (brcmuart->rx_bufs) + { + rt_dma_free_coherent(brcmuart->dev, brcmuart->rx_size, + brcmuart->rx_bufs, brcmuart->rx_addr); + } + if (brcmuart->tx_buf) + { + rt_dma_free_coherent(brcmuart->dev, brcmuart->tx_size, + brcmuart->tx_buf, brcmuart->tx_addr); + } + + if (brcmuart->dma_enabled) + { + brcmuart_arbitration(brcmuart, 0); + } + + rt_free(brcmuart); +} + +static void brcmuart_serial_remove(struct serial8250 *serial) +{ + struct brcmuart *brcmuart = to_brcmuart(serial); + + brcmuart_free_resource(brcmuart); + + rt_timer_detach(&brcmuart->char_wait_work); +} + +static rt_err_t brcmuart_probe(struct rt_platform_device *pdev) +{ + int ridx; + rt_err_t err; + const char *dev_name; + static const char * const reg_names[REGS_MAX] = + { + "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" + }; + struct serial8250 *serial; + struct rt_device *dev = &pdev->parent; + struct brcmuart *brcmuart = rt_calloc(1, sizeof(*brcmuart)); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!brcmuart) + { + return -RT_EINVAL; + } + + brcmuart->dev = dev; + + if (pdev->id) + { + brcmuart->rate_table = pdev->id->data; + } + else + { + brcmuart->rate_table = brcmstb_rate_table; + } + + serial = &brcmuart->parent; + + serial->irq = rt_dm_dev_get_irq(dev, 0); + + if (serial->irq < 0) + { + err = serial->irq; + + goto _free_res; + } + + for (ridx = 0; ridx < REGS_MAX; ++ridx) + { + brcmuart->regs[ridx] = rt_dm_dev_iomap_by_name(dev, reg_names[ridx]); + + if (!brcmuart->regs[ridx]) + { + if (rt_dm_dev_prop_index_of_string(dev, "reg-names", reg_names[ridx]) < 0) + { + break; + } + + err = -RT_EIO; + goto _free_res; + } + + if (ridx == REGS_8250) + { + serial->base = brcmuart->regs[ridx]; + } + } + + if (ridx != 1 && ridx != REGS_MAX) + { + LOG_E("Registers %s not specified", reg_names[ridx]); + err = -RT_EINVAL; + goto _free_res; + } + + if (ridx > REGS_DMA_RX) + { + if (brcmuart_arbitration(brcmuart, 1) == 0) + { + rt_uint32_t txrev = 0, rxrev = 0; + + txrev = udma_readl(brcmuart, REGS_DMA_RX, UDMA_RX_REVISION); + rxrev = udma_readl(brcmuart, REGS_DMA_TX, UDMA_TX_REVISION); + + if (txrev >= UDMA_TX_REVISION_REQUIRED && + rxrev >= UDMA_RX_REVISION_REQUIRED) + { + /* Enable the use of the DMA hardware */ + brcmuart->dma_enabled = RT_TRUE; + } + else + { + brcmuart_arbitration(brcmuart, 0); + + LOG_E("Unsupported DMA Hardware Revision"); + } + } + else + { + LOG_E("Timeout arbitrating for UART DMA hardware"); + } + } + + if (brcmuart->dma_enabled) + { + brcmuart->dma_irq = rt_dm_dev_get_irq_by_name(dev, "dma"); + + if (brcmuart->dma_irq < 0) + { + err = brcmuart->dma_irq; + LOG_E("Get DMA IRQ error = %s", rt_strerror(err)); + + goto _free_res; + } + + brcmuart->rx_size = RX_BUF_SIZE * RX_BUFS_COUNT; + brcmuart->rx_bufs = rt_dma_alloc_coherent(dev, brcmuart->rx_size, &brcmuart->rx_addr); + + if (!brcmuart->rx_bufs) + { + err = -RT_ENOMEM; + goto _free_res; + } + + brcmuart->tx_size = UART_XMIT_SIZE; + brcmuart->tx_buf = rt_dma_alloc_coherent(dev, brcmuart->tx_size, &brcmuart->tx_addr); + + if (!brcmuart->tx_buf) + { + err = -RT_ENOMEM; + goto _free_res; + } + } + + rt_dm_dev_prop_read_u32(dev, "clock-frequency", &serial->freq); + + serial->clk = rt_clk_get_by_name(dev, "sw_baud"); + + if (rt_is_err(serial->clk)) + { + err = rt_ptr_err(serial->clk); + + goto _free_res; + } + else if (serial->clk) + { + if ((err = rt_clk_prepare_enable(serial->clk))) + { + goto _free_res; + } + + brcmuart->default_mux_rate = rt_clk_get_rate(serial->clk); + + for (int i = 0; i < RT_ARRAY_SIZE(brcmuart->real_rates); ++i) + { + if (!brcmuart->rate_table[i]) + { + brcmuart->real_rates[i] = 0; + + continue; + } + + if (rt_clk_set_rate(serial->clk, brcmuart->rate_table[i])) + { + LOG_E("Error selecting BAUD MUX clock for %u", brcmuart->rate_table[i]); + brcmuart->real_rates[i] = brcmuart->rate_table[i]; + } + else + { + brcmuart->real_rates[i] = rt_clk_get_rate(serial->clk); + } + } + + rt_clk_set_rate(serial->clk, brcmuart->default_mux_rate); + + serial->freq = brcmuart->default_mux_rate; + } + + if (!serial->freq) + { + LOG_E("clock-frequency or clk not defined"); + + err = -RT_EINVAL; + goto _free_res; + } + + serial->iotype = rt_dm_dev_prop_read_bool(dev, "big-endian") ? + PORT_MMIO32BE : PORT_MMIO32; + + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + + serial->serial_ios = brcmstb_serial_ios; + if (brcmuart->dma_enabled) + { + serial->serial_dma_enable = brcmuart_serial_dma_enable; + serial->serial_dma_tx = brcmuart_serial_dma_tx; + serial->serial_dma_rx = brcmuart_serial_dma_rx; + } + serial->handle_irq = &brcmuart_serial_isr; + serial->remove = &brcmuart_serial_remove; + serial->data = brcmuart; + + pdev->parent.user_data = serial; + + if ((err = serial8250_setup(serial))) + { + goto _free_res; + } + + dev_name = rt_dm_dev_get_name(&serial->parent.parent); + + rt_timer_init(&brcmuart->char_wait_work, dev_name, brcmuart_char_wait_work, brcmuart, + 0, RT_TIMER_FLAG_PERIODIC); + + if (brcmuart->dma_enabled) + { + rt_hw_interrupt_install(brcmuart->dma_irq, brcmuart_dma_isr, brcmuart, dev_name); + rt_hw_interrupt_umask(brcmuart->dma_irq); + } + + return RT_EOK; + +_free_res: + brcmuart_free_resource(brcmuart); + + return err; +} + +static rt_err_t brcmuart_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct serial8250 *serial = dev->user_data; + + rt_dm_dev_unbind_fwdata(dev, RT_NULL); + + return serial8250_remove(serial); +} + +static const struct rt_ofw_node_id brcmuart_ofw_ids[] = +{ + { .type = "ttyS", .compatible = "brcm,bcm7278-uart", .data = brcmstb_rate_table_7278 }, + { .type = "ttyS", .compatible = "brcm,bcm7271-uart", .data = brcmstb_rate_table }, + { /* sentinel */ } +}; + +static struct rt_platform_driver brcmuart_driver = +{ + .name = "bcm7271-uart", + .ids = brcmuart_ofw_ids, + + .probe = brcmuart_probe, + .remove = brcmuart_remove, +}; + +static int brcmuart_drv_register(void) +{ + rt_platform_driver_register(&brcmuart_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(brcmuart_drv_register); diff --git a/bsp/raspberry-pi/dm/serial/Kconfig b/bsp/raspberry-pi/dm/serial/Kconfig new file mode 100755 index 0000000000..bb5e0ee2d6 --- /dev/null +++ b/bsp/raspberry-pi/dm/serial/Kconfig @@ -0,0 +1,11 @@ +config RT_SERIAL_8250_BCM2835AUX + bool "BCM2835 auxiliar mini UART" + depends on RT_SERIAL_8250 + default n + +config RT_SERIAL_8250_BCM7271 + bool "Broadcom 8250 based serial port" + depends on RT_SERIAL_8250 + depends on RT_USING_DMA + depends on RT_SERIAL_USING_DMA + default n diff --git a/bsp/raspberry-pi/dm/serial/SConscript b/bsp/raspberry-pi/dm/serial/SConscript new file mode 100755 index 0000000000..d78e788b4b --- /dev/null +++ b/bsp/raspberry-pi/dm/serial/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/serial/device/8250'] + +if GetDepend(['RT_SERIAL_8250_BCM2835AUX']): + src += ['8250-bcm2835aux.c'] + +if GetDepend(['RT_SERIAL_8250_BCM7271']): + src += ['8250-bcm7271.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/soc/Kconfig b/bsp/raspberry-pi/dm/soc/Kconfig new file mode 100755 index 0000000000..e1fa03e329 --- /dev/null +++ b/bsp/raspberry-pi/dm/soc/Kconfig @@ -0,0 +1,6 @@ +config RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR + bool "Raspberry Pi voltage monitor" + depends on RT_FIRMWARE_RASPBERRYPI + select RT_USING_DEVICE_IPC + select RT_USING_SYSTEM_WORKQUEUE + default y diff --git a/bsp/raspberry-pi/dm/soc/SConscript b/bsp/raspberry-pi/dm/soc/SConscript new file mode 100755 index 0000000000..63a0379401 --- /dev/null +++ b/bsp/raspberry-pi/dm/soc/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR']): + src += ['raspberrypi-voltage-monitor.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/soc/raspberrypi-voltage-monitor.c b/bsp/raspberry-pi/dm/soc/raspberrypi-voltage-monitor.c new file mode 100755 index 0000000000..56001c5fce --- /dev/null +++ b/bsp/raspberry-pi/dm/soc/raspberrypi-voltage-monitor.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-24 GuEe-GUI first version + */ + +#include +#include +#include + +#define DBG_TAG "soc.raspberrypi-voltage-monitor" +#define DBG_LVL DBG_INFO +#include + +#include + +#define UNDERVOLTAGE_STICKY_BIT RT_BIT(16) + +struct rpi_voltage_monitor +{ + struct rt_device_notify alarm; + + rt_uint32_t last_throttled; + struct rpi_firmware *rpi_fw; + struct rt_work delayed_work; +}; + +static rt_err_t rpi_voltage_monitor_open(rt_device_t dev, rt_uint16_t oflag) +{ + if (dev->ref_count) + { + return -RT_EBUSY; + } + + return RT_EOK; +} + +static rt_err_t rpi_voltage_monitor_close(rt_device_t dev) +{ + struct rpi_voltage_monitor *mon = dev->user_data; + + mon->alarm.notify = RT_NULL; + + return RT_EOK; +} + +static rt_ssize_t rpi_voltage_monitor_read(rt_device_t dev, rt_off_t pos, + void *buffer, rt_size_t size) +{ + struct rpi_voltage_monitor *mon = dev->user_data; + + if (size <= sizeof(mon->last_throttled)) + { + return -RT_ENOSPC; + } + + *(rt_uint32_t *)buffer = !!(mon->last_throttled & UNDERVOLTAGE_STICKY_BIT); + + return sizeof(mon->last_throttled); +} + +static rt_err_t rpi_voltage_monitor_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rpi_voltage_monitor *mon = dev->user_data; + + switch (cmd) + { + case RT_DEVICE_CTRL_NOTIFY_SET: + if (!args) + { + err = -RT_EINVAL; + break; + } + rt_memcpy(&mon->alarm, args, sizeof(mon->alarm)); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops rpi_voltage_monitor_ops = +{ + .open = rpi_voltage_monitor_open, + .close = rpi_voltage_monitor_close, + .read = rpi_voltage_monitor_read, + .control = rpi_voltage_monitor_control, +}; +#endif + +static void rpi_voltage_monitor_delayed_work(struct rt_work *work, void *work_data) +{ + rt_err_t err; + rt_uint32_t new_uv, old_uv, value; + struct rpi_voltage_monitor *mon = work_data; + + /* Request firmware to clear sticky bits */ + value = 0xffff; + + if ((err = rpi_firmware_property(mon->rpi_fw, RPI_FIRMWARE_GET_THROTTLED, + &value, sizeof(value)))) + { + LOG_E("Failed to get throttled error = %s", rt_strerror(err)); + return; + } + + new_uv = value & UNDERVOLTAGE_STICKY_BIT; + old_uv = mon->last_throttled & UNDERVOLTAGE_STICKY_BIT; + mon->last_throttled = value; + + if (new_uv == old_uv) + { + return; + } + + LOG_D(new_uv ? "Undervoltage detected" : "Voltage normalised"); + + if (mon->alarm.notify) + { + mon->alarm.notify(mon->alarm.dev); + } + + rt_work_submit(&mon->delayed_work, rt_tick_from_millisecond(200)); +} + +static rt_err_t rpi_voltage_monitor_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent, *fw_dev = pdev->priv; + struct rpi_voltage_monitor *mon = rt_calloc(1, sizeof(*mon)); + + if (!mon) + { + return -RT_ENOMEM; + } + + mon->rpi_fw = rpi_firmware_get(fw_dev->ofw_node); + + if (!mon->rpi_fw) + { + err = -RT_EINVAL; + goto _fail; + } + + dev->user_data = mon; + + dev->type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + dev->ops = &rpi_voltage_monitor_ops; +#else + dev->open = rpi_voltage_monitor_open, + dev->close = rpi_voltage_monitor_close, + dev->read = rpi_voltage_monitor_read, + dev->control = rpi_voltage_monitor_control, +#endif + + rt_dm_dev_set_name(dev, "rpi_volt"); + dev_name = rt_dm_dev_get_name(dev); + rt_device_register(dev, dev_name, RT_DEVICE_FLAG_RDONLY); + + rt_work_init(&mon->delayed_work, rpi_voltage_monitor_delayed_work, mon); + rt_work_submit(&mon->delayed_work, rt_tick_from_millisecond(200)); + + return RT_EOK; + +_fail: + rt_free(mon); + + return err; +} + +static rt_err_t rpi_voltage_monitor_remove(struct rt_platform_device *pdev) +{ + struct rt_device *dev = &pdev->parent; + struct rpi_voltage_monitor *mon = dev->user_data; + + rt_work_cancel(&mon->delayed_work); + + rt_device_unregister(dev); + + rpi_firmware_put(mon->rpi_fw); + rt_free(mon); + + return RT_EOK; +} + +static struct rt_platform_driver rpi_voltage_monitor_driver = +{ + .name = "raspberrypi-voltage-monitor", + + .probe = rpi_voltage_monitor_probe, + .remove = rpi_voltage_monitor_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpi_voltage_monitor_driver); diff --git a/bsp/raspberry-pi/dm/spi/Kconfig b/bsp/raspberry-pi/dm/spi/Kconfig new file mode 100755 index 0000000000..9dfe16a375 --- /dev/null +++ b/bsp/raspberry-pi/dm/spi/Kconfig @@ -0,0 +1,15 @@ +config RT_SPI_BCM2835 + bool "BCM2835 SPI controller" + depends on RT_USING_DM + depends on RT_USING_SPI + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + default n + +config RT_SPI_BCM2835AUX + bool "BCM2835 SPI auxiliary controller" + depends on RT_USING_DM + depends on RT_USING_SPI + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + default n diff --git a/bsp/raspberry-pi/dm/spi/SConscript b/bsp/raspberry-pi/dm/spi/SConscript new file mode 100755 index 0000000000..cbde02fa56 --- /dev/null +++ b/bsp/raspberry-pi/dm/spi/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend('RT_SPI_BCM2835'): + src += ['spi-bcm2835.c'] + +if GetDepend('RT_SPI_BCM2835AUX'): + src += ['spi-bcm2835aux.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/spi/spi-bcm2835.c b/bsp/raspberry-pi/dm/spi/spi-bcm2835.c new file mode 100755 index 0000000000..00ed169758 --- /dev/null +++ b/bsp/raspberry-pi/dm/spi/spi-bcm2835.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "spi.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include + +/* SPI register offsets */ +#define BCM2835_SPI_CS 0x00 +#define BCM2835_SPI_FIFO 0x04 +#define BCM2835_SPI_CLK 0x08 +#define BCM2835_SPI_DLEN 0x0c +#define BCM2835_SPI_LTOH 0x10 +#define BCM2835_SPI_DC 0x14 + +/* Bitfields in CS */ +#define BCM2835_SPI_CS_LEN_LONG 0x02000000 +#define BCM2835_SPI_CS_DMA_LEN 0x01000000 +#define BCM2835_SPI_CS_CSPOL2 0x00800000 +#define BCM2835_SPI_CS_CSPOL1 0x00400000 +#define BCM2835_SPI_CS_CSPOL0 0x00200000 +#define BCM2835_SPI_CS_RXF 0x00100000 +#define BCM2835_SPI_CS_RXR 0x00080000 +#define BCM2835_SPI_CS_TXD 0x00040000 +#define BCM2835_SPI_CS_RXD 0x00020000 +#define BCM2835_SPI_CS_DONE 0x00010000 +#define BCM2835_SPI_CS_LEN 0x00002000 +#define BCM2835_SPI_CS_REN 0x00001000 +#define BCM2835_SPI_CS_ADCS 0x00000800 +#define BCM2835_SPI_CS_INTR 0x00000400 +#define BCM2835_SPI_CS_INTD 0x00000200 +#define BCM2835_SPI_CS_DMAEN 0x00000100 +#define BCM2835_SPI_CS_TA 0x00000080 +#define BCM2835_SPI_CS_CSPOL 0x00000040 +#define BCM2835_SPI_CS_CLEAR_RX 0x00000020 +#define BCM2835_SPI_CS_CLEAR_TX 0x00000010 +#define BCM2835_SPI_CS_CPOL 0x00000008 +#define BCM2835_SPI_CS_CPHA 0x00000004 +#define BCM2835_SPI_CS_CS_10 0x00000002 +#define BCM2835_SPI_CS_CS_01 0x00000001 + +#define BCM2835_SPI_FIFO_SIZE 64 +#define BCM2835_SPI_FIFO_SIZE_3_4 48 +#define BCM2835_SPI_DMA_MIN_LENGTH 96 +#define BCM2835_SPI_POLLING_LIMIT_US 30 + +struct bcm2835_spi +{ + struct rt_spi_bus parent; + + rt_uint8_t mode; + rt_ubase_t max_speed_hz; + + int irq; + void *regs; + + rt_ubase_t clk_hz; + struct rt_clk *clk; + struct rt_spi_message *msg; + + const rt_uint8_t *tx_buf; + rt_uint8_t *rx_buf; + int tx_len; + int rx_len; + int tx_prologue; + int rx_prologue; + rt_uint32_t tx_spillover; + + rt_uint32_t prepare_cs; + rt_uint32_t clear_rx_cs; + + struct rt_completion done; +}; + +#define raw_to_bcm2835_spi(raw) rt_container_of(raw, struct bcm2835_spi, parent) + +rt_inline rt_uint32_t bcm2835_rd(struct bcm2835_spi *bs, int reg) +{ + return HWREG32(bs->regs + reg); +} + +rt_inline void bcm2835_wr(struct bcm2835_spi *bs, int reg, rt_uint32_t val) +{ + HWREG32(bs->regs + reg) = val; +} + +rt_inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) +{ + rt_uint8_t byte; + + while (bs->rx_len && (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD)) + { + /* Read flush */ + byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); + + if (bs->rx_buf) + { + *bs->rx_buf++ = byte; + } + + --bs->rx_len; + } +} + +rt_inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) +{ + rt_uint8_t byte; + + while (bs->tx_len && (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) + { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); + --bs->tx_len; + } +} + +rt_inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count) +{ + int len; + rt_uint32_t val; + + bs->rx_len -= count; + + do { + val = bcm2835_rd(bs, BCM2835_SPI_FIFO); + len = rt_min(count, 4); + rt_memcpy(bs->rx_buf, &val, len); + bs->rx_buf += len; + count -= 4; + } while (count > 0); +} + +rt_inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count) +{ + int len; + rt_uint32_t val; + + bs->tx_len -= count; + + do { + if (bs->tx_buf) + { + len = rt_min(count, 4); + rt_memcpy(&val, bs->tx_buf, len); + bs->tx_buf += len; + } + else + { + val = 0; + } + + bcm2835_wr(bs, BCM2835_SPI_FIFO, val); + count -= 4; + } while (count > 0); +} + +rt_inline void bcm2835_wait_tx_fifo_empty(struct bcm2835_spi *bs) +{ + while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE)) + { + rt_hw_cpu_relax(); + } +} + +rt_inline void bcm2835_rd_fifo_blind(struct bcm2835_spi *bs, int count) +{ + rt_uint8_t val; + + count = rt_min(count, bs->rx_len); + bs->rx_len -= count; + + do { + val = bcm2835_rd(bs, BCM2835_SPI_FIFO); + + if (bs->rx_buf) + { + *bs->rx_buf++ = val; + } + } while (--count); +} + +rt_inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count) +{ + rt_uint8_t val; + + count = rt_min(count, bs->tx_len); + bs->tx_len -= count; + + do { + val = bs->tx_buf ? *bs->tx_buf++ : 0; + bcm2835_wr(bs, BCM2835_SPI_FIFO, val); + } while (--count); +} + +static void bcm2835_spi_reset_hw(struct bcm2835_spi *bs) +{ + rt_uint32_t cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* Disable SPI interrupts and transfer */ + cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_DMAEN | BCM2835_SPI_CS_TA); + + /* + * Transmission sometimes breaks unless the DONE bit is written at the + * end of every transfer. The spec says it's a RO bit. Either the + * spec is wrong and the bit is actually of type RW1C, or it's a + * hardware erratum. + */ + cs |= BCM2835_SPI_CS_DONE; + /* Reset RX/TX FIFOS */ + cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX; + + /* Reset the SPI_HW */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + /* Reset the DLEN */ + bcm2835_wr(bs, BCM2835_SPI_DLEN, 0); +} + +static void bcm2835_spi_transfer_one_irq(struct bcm2835_spi *bs, + rt_uint32_t cs, rt_bool_t fifo_empty) +{ + /* + * Enable HW block, but with interrupts still disabled. + * Otherwise the empty TX FIFO would immediately trigger an interrupt. + */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); + + /* Fill TX FIFO as much as possible */ + if (fifo_empty) + { + bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); + } + bcm2835_wr_fifo(bs); + + /* Enable interrupts */ + cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA; + bcm2835_wr(bs, BCM2835_SPI_CS, cs); +} + +static rt_err_t bcm2835_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + rt_uint32_t prepare_cs; + struct bcm2835_spi *bs = raw_to_bcm2835_spi(device->bus); + + prepare_cs = BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + + if (conf->mode & RT_SPI_CPOL) + { + prepare_cs |= BCM2835_SPI_CS_CPOL; + } + if (conf->mode & RT_SPI_CPHA) + { + prepare_cs |= BCM2835_SPI_CS_CPHA; + } + device->user_data = (void *)(rt_ubase_t)prepare_cs; + + if (conf->mode & RT_SPI_NO_CS) + { + return RT_EOK; + } + + bcm2835_wr(bs, BCM2835_SPI_CS, prepare_cs); + + return RT_EOK; +} + +static rt_ssize_t bcm2835_spi_xfer(struct rt_spi_device *device, + struct rt_spi_message *msg) +{ + rt_bool_t fifo_empty = RT_TRUE; + rt_ubase_t spi_hz, cdiv, hz_per_byte, byte_limit, effective_speed_hz; + rt_uint32_t cs = (rt_ubase_t)device->user_data; + struct bcm2835_spi *bs = raw_to_bcm2835_spi(device->bus); + + spi_hz = device->config.max_hz; + + if (spi_hz >= bs->clk_hz / 2) + { + cdiv = 2; + } + else if (spi_hz) + { + cdiv = RT_DIV_ROUND_UP(bs->clk_hz, spi_hz); + cdiv += (cdiv % 2); + + if (cdiv >= 65536) + { + cdiv = 0; + } + } + else + { + cdiv = 0; + } + effective_speed_hz = cdiv ? (bs->clk_hz / cdiv) : (bs->clk_hz / 65536); + bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); + + /* Handle all the 3-wire mode */ + if (device->config.mode & RT_SPI_3WIRE && msg->recv_buf) + { + cs |= BCM2835_SPI_CS_REN; + } + + /* Set transmit buffers and length */ + bs->tx_buf = msg->send_buf; + bs->rx_buf = msg->recv_buf; + bs->tx_len = msg->length; + bs->rx_len = msg->length; + + /* + * Calculate the estimated time in us the transfer runs. Note that + * there is 1 idle clocks cycles after each byte getting transferred + * so we have 9 cycles/byte. This is used to find the number of Hz + * per byte per polling limit. E.g., we can transfer 1 byte in 30 us + * per 300,000 Hz of bus clock. + */ + hz_per_byte = BCM2835_SPI_POLLING_LIMIT_US ? (9 * 1000000) / BCM2835_SPI_POLLING_LIMIT_US : 0; + byte_limit = hz_per_byte ? effective_speed_hz / hz_per_byte : 1; + + /* Run in polling mode for short transfers */ + if (msg->length < byte_limit) + { + rt_tick_t timeout; + + /* Enable HW block without interrupts */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); + + /* + * Fill in the fifo before timeout calculations + * if we are interrupted here, then the data is + * getting transferred by the HW while we are interrupted + */ + bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); + + /* Set the timeout to at least 2 jiffies */ + timeout = 2 + RT_TICK_PER_SECOND * BCM2835_SPI_POLLING_LIMIT_US / 1000000; + timeout += rt_tick_get(); + + while (bs->rx_len) + { + /* Fill in tx fifo with remaining data */ + bcm2835_wr_fifo(bs); + + /* Read from fifo as much as possible */ + bcm2835_rd_fifo(bs); + + if (bs->rx_len && rt_tick_get() > timeout) + { + LOG_E("%s: Timeout for poll mode", rt_dm_dev_get_name(&bs->parent.parent)); + + fifo_empty = RT_FALSE; + goto _irq_mode; + } + } + + /* Transfer complete - reset SPI HW */ + bcm2835_spi_reset_hw(bs); + goto _end; + } + +_irq_mode: + bcm2835_spi_transfer_one_irq(bs, cs, fifo_empty); + + rt_completion_wait(&bs->done, RT_WAITING_FOREVER); + +_end: + return msg->length; +} + +static struct rt_spi_ops bcm2835_spi_ops = +{ + .configure = bcm2835_spi_configure, + .xfer = bcm2835_spi_xfer, +}; + +static void bcm2835_spi_isr(int irq, void *param) +{ + rt_uint32_t cs; + struct bcm2835_spi *bs = param; + + cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + /* Bail out early if interrupts are not enabled */ + if (!(cs & BCM2835_SPI_CS_INTR)) + { + return; + } + + /* + * An interrupt is signaled either if DONE is set (TX FIFO empty) + * or if RXR is set (RX FIFO >= 3/4 full). + */ + if (cs & BCM2835_SPI_CS_RXF) + { + bcm2835_rd_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); + } + else if (cs & BCM2835_SPI_CS_RXR) + { + bcm2835_rd_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE_3_4); + } + + if (bs->tx_len && cs & BCM2835_SPI_CS_DONE) + { + bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); + } + + /* Read as many bytes as possible from FIFO */ + bcm2835_rd_fifo(bs); + /* Write as many bytes as possible to FIFO */ + bcm2835_wr_fifo(bs); + + if (!bs->rx_len) + { + /* Transfer complete - reset SPI HW */ + bcm2835_spi_reset_hw(bs); + rt_completion_done(&bs->done); + } +} + +static void bcm2835_spi_free(struct bcm2835_spi *bs) +{ + if (!rt_is_err_or_null(bs->clk)) + { + rt_clk_disable_unprepare(bs->clk); + } +} + +static rt_err_t bcm2835_spi_probe(struct rt_platform_device *pdev) +{ + int id; + rt_err_t err; + const char *bus_name; + struct rt_device *dev = &pdev->parent; + struct bcm2835_spi *bs = rt_calloc(1, sizeof(*bs)); + + if (!bs) + { + return -RT_ENOMEM; + } + + bs->regs = rt_dm_dev_iomap(dev, 0); + + if (!bs->regs) + { + err = -RT_EIO; + goto _fail; + } + + bs->irq = rt_dm_dev_get_irq(dev, 0); + + if (bs->irq < 0) + { + err = bs->irq; + goto _fail; + } + + bs->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(bs->clk)) + { + err = rt_ptr_err(bs->clk); + goto _fail; + } + + rt_clk_prepare_enable(bs->clk); + bs->max_speed_hz = rt_clk_get_rate(bs->clk); + + bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + + bs->mode = RT_SPI_CPOL | RT_SPI_CPHA | RT_SPI_CS_HIGH | RT_SPI_NO_CS | RT_SPI_3WIRE; + bs->parent.num_chipselect = 3; + rt_completion_init(&bs->done); + + dev->user_data = bs; + + bs->parent.parent.ofw_node = dev->ofw_node; + + if ((id = pdev->dev_id) >= 0) + { + rt_dm_dev_set_name(&bs->parent.parent, "spi%u", id); + } + else + { + rt_dm_dev_set_name_auto(&bs->parent.parent, "spi"); + } + bus_name = rt_dm_dev_get_name(&bs->parent.parent); + + rt_hw_interrupt_install(bs->irq, bcm2835_spi_isr, bs, bus_name); + rt_hw_interrupt_umask(bs->irq); + + if ((err = rt_spi_bus_register(&bs->parent, bus_name, &bcm2835_spi_ops))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(bs->irq); + rt_pic_detach_irq(bs->irq, bs); + +_fail: + bcm2835_spi_free(bs); + + return err; +} + +static rt_err_t bcm2835_spi_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_spi *bs = pdev->parent.user_data; + + rt_hw_interrupt_mask(bs->irq); + rt_pic_detach_irq(bs->irq, bs); + + rt_device_unregister(&bs->parent.parent); + + /* Clear FIFOs, and disable the HW block */ + bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + + bcm2835_spi_free(bs); + + return RT_EOK; +} + +static rt_err_t bcm2835_spi_shutdown(struct rt_platform_device *pdev) +{ + return bcm2835_spi_remove(pdev); +} + +static const struct rt_ofw_node_id bcm2835_spi_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-spi", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_spi_driver = +{ + .name = "bcm2835-spi", + .ids = bcm2835_spi_ofw_ids, + + .probe = bcm2835_spi_probe, + .remove = bcm2835_spi_remove, + .shutdown = bcm2835_spi_shutdown, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_spi_driver); diff --git a/bsp/raspberry-pi/dm/spi/spi-bcm2835aux.c b/bsp/raspberry-pi/dm/spi/spi-bcm2835aux.c new file mode 100755 index 0000000000..5f1d8de87c --- /dev/null +++ b/bsp/raspberry-pi/dm/spi/spi-bcm2835aux.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "spi.bcm2835.aux" +#define DBG_LVL DBG_INFO +#include + +/* SPI register offsets */ +#define BCM2835_AUX_SPI_CNTL0 0x00 +#define BCM2835_AUX_SPI_CNTL1 0x04 +#define BCM2835_AUX_SPI_STAT 0x08 +#define BCM2835_AUX_SPI_PEEK 0x0c +#define BCM2835_AUX_SPI_IO 0x20 +#define BCM2835_AUX_SPI_TXHOLD 0x30 + +/* Bitfields in CNTL0 */ +#define BCM2835_AUX_SPI_CNTL0_SPEED 0xfff00000 +#define BCM2835_AUX_SPI_CNTL0_SPEED_MAX 0xfff +#define BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT 20 +#define BCM2835_AUX_SPI_CNTL0_CS 0x000e0000 +#define BCM2835_AUX_SPI_CNTL0_POSTINPUT 0x00010000 +#define BCM2835_AUX_SPI_CNTL0_VAR_CS 0x00008000 +#define BCM2835_AUX_SPI_CNTL0_VAR_WIDTH 0x00004000 +#define BCM2835_AUX_SPI_CNTL0_DOUTHOLD 0x00003000 +#define BCM2835_AUX_SPI_CNTL0_ENABLE 0x00000800 +#define BCM2835_AUX_SPI_CNTL0_IN_RISING 0x00000400 +#define BCM2835_AUX_SPI_CNTL0_CLEARFIFO 0x00000200 +#define BCM2835_AUX_SPI_CNTL0_OUT_RISING 0x00000100 +#define BCM2835_AUX_SPI_CNTL0_CPOL 0x00000080 +#define BCM2835_AUX_SPI_CNTL0_MSBF_OUT 0x00000040 +#define BCM2835_AUX_SPI_CNTL0_SHIFTLEN 0x0000003f + +/* Bitfields in CNTL1 */ +#define BCM2835_AUX_SPI_CNTL1_CSHIGH 0x00000700 +#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000080 +#define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000040 +#define BCM2835_AUX_SPI_CNTL1_MSBF_IN 0x00000002 +#define BCM2835_AUX_SPI_CNTL1_KEEP_IN 0x00000001 + +/* Bitfields in STAT */ +#define BCM2835_AUX_SPI_STAT_TX_LVL 0xff000000 +#define BCM2835_AUX_SPI_STAT_RX_LVL 0x00ff0000 +#define BCM2835_AUX_SPI_STAT_TX_FULL 0x00000400 +#define BCM2835_AUX_SPI_STAT_TX_EMPTY 0x00000200 +#define BCM2835_AUX_SPI_STAT_RX_FULL 0x00000100 +#define BCM2835_AUX_SPI_STAT_RX_EMPTY 0x00000080 +#define BCM2835_AUX_SPI_STAT_BUSY 0x00000040 +#define BCM2835_AUX_SPI_STAT_BITCOUNT 0x0000003f + +#define POLLING_LIMIT_US 30 + +struct bcm2835aux_spi +{ + struct rt_spi_bus parent; + + void *regs; + int irq; + struct rt_clk *clk; + + rt_uint8_t mode; + + rt_uint32_t cntl[2]; + rt_uint8_t *rx_buf; + const rt_uint8_t *tx_buf; + int tx_len; + int rx_len; + int pending; + + struct rt_completion done; +}; + +#define raw_to_bcm2835aux_spi(raw) rt_container_of(raw, struct bcm2835aux_spi, parent) + +rt_inline rt_uint32_t bcm2835aux_rd(struct bcm2835aux_spi *bs, int reg) +{ + return HWREG32(bs->regs + reg); +} + +rt_inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, int reg, rt_uint32_t val) +{ + HWREG32(bs->regs + reg) = val; +} + +rt_inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs) +{ + rt_uint32_t data; + int count = rt_min(bs->rx_len, 3); + + data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO); + + if (bs->rx_buf) + { + switch (count) + { + case 3: + *bs->rx_buf++ = (data >> 16) & 0xff; + /* fallthrough */; + case 2: + *bs->rx_buf++ = (data >> 8) & 0xff; + /* fallthrough */; + case 1: + *bs->rx_buf++ = (data >> 0) & 0xff; + /* fallthrough - no default */ + } + } + + bs->rx_len -= count; + bs->pending -= count; +} + +rt_inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs) +{ + int count; + rt_uint8_t byte; + rt_uint32_t data = 0; + + /* Gather up to 3 bytes to write to the FIFO */ + count = rt_min(bs->tx_len, 3); + for (int i = 0; i < count; ++i) + { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + data |= byte << (8 * (2 - i)); + } + + /* and set the variable bit-length */ + data |= (count * 8) << 24; + + /* and decrement length */ + bs->tx_len -= count; + bs->pending += count; + + /* write to the correct TX-register */ + if (bs->tx_len) + { + bcm2835aux_wr(bs, BCM2835_AUX_SPI_TXHOLD, data); + } + else + { + bcm2835aux_wr(bs, BCM2835_AUX_SPI_IO, data); + } +} + +static void bcm2835aux_spi_reset_hw(struct bcm2835aux_spi *bs) +{ + /* disable spi clearing fifo and interrupts */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, 0); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, BCM2835_AUX_SPI_CNTL0_CLEARFIFO); +} + +static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs) +{ + rt_uint32_t stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT); + + /* Check if we have data to read */ + for (; bs->rx_len && (stat & BCM2835_AUX_SPI_STAT_RX_LVL); + stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT)) + { + bcm2835aux_rd_fifo(bs); + } + + /* Check if we have data to write */ + while (bs->tx_len && bs->pending < 12 && + !(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & BCM2835_AUX_SPI_STAT_TX_FULL)) + { + bcm2835aux_wr_fifo(bs); + } +} + +rt_inline void bcm2835aux_spi_enable_irq(struct bcm2835aux_spi *bs) +{ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] | + BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE); +} + +static rt_err_t bcm2835aux_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + struct bcm2835aux_spi *bs = raw_to_bcm2835aux_spi(device->bus); + + if (!(conf->mode & RT_SPI_NO_CS)) + { + return -RT_EINVAL; + } + + /* Prepare message */ + bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE | + BCM2835_AUX_SPI_CNTL0_VAR_WIDTH | + BCM2835_AUX_SPI_CNTL0_MSBF_OUT; + bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN; + + /* Handle all the modes */ + if (conf->mode & RT_SPI_CPOL) + { + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL; + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_OUT_RISING; + } + else + { + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_IN_RISING; + } + + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + return RT_EOK; +} + +static rt_ssize_t bcm2835aux_spi_xfer(struct rt_spi_device *device, + struct rt_spi_message *msg) +{ + rt_ubase_t effective_speed_hz, spi_hz, clk_hz, speed, hz_per_byte, byte_limit; + struct bcm2835aux_spi *bs = raw_to_bcm2835aux_spi(device->bus); + + spi_hz = device->config.max_hz; + clk_hz = rt_clk_get_rate(bs->clk); + + if (spi_hz >= clk_hz / 2) + { + speed = 0; + } + else if (spi_hz) + { + speed = RT_DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1; + + if (speed > BCM2835_AUX_SPI_CNTL0_SPEED_MAX) + { + speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; + } + } + else + { + speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; + } + /* Mask out old speed from previous spi_transfer */ + bs->cntl[0] &= ~BCM2835_AUX_SPI_CNTL0_SPEED; + /* set the new speed */ + bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; + + effective_speed_hz = clk_hz / (2 * (speed + 1)); + + /* set transmit buffers and length */ + bs->tx_buf = msg->send_buf; + bs->rx_buf = msg->recv_buf; + bs->tx_len = msg->length; + bs->rx_len = msg->length; + bs->pending = 0; + + /* + * Calculate the estimated time in us the transfer runs. + * Note that there are 2 idle clocks cycles after each chunk getting + * transferred - in our case the chunk size is 3 bytes, so we + * approximate this by 9 cycles/byte. + * This is used to find the number of Hz per byte per polling limit. + * E.g., we can transfer 1 byte in 30 us per 300,000 Hz of bus clock. + */ + hz_per_byte = POLLING_LIMIT_US ? (9 * 1000000) / POLLING_LIMIT_US : 0; + byte_limit = hz_per_byte ? effective_speed_hz / hz_per_byte : 1; + + /* Polling mode for short transfers */ + if (msg->length < byte_limit) + { + rt_tick_t timeout; + + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + timeout = 2 + RT_TICK_PER_SECOND * POLLING_LIMIT_US / 1000000; + timeout += rt_tick_get(); + + while (bs->rx_len) + { + bcm2835aux_spi_transfer_helper(bs); + + if (bs->rx_len && rt_tick_get() > timeout) + { + LOG_E("%s: Timeout for poll mode", rt_dm_dev_get_name(&bs->parent.parent)); + goto _enable_irq; + } + } + + goto _out_unprepare; + } + + /* IRQ mode */ + + /* Fill in registers and fifos before enabling interrupts */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + /* Fill in tx fifo with data before enabling interrupts */ + while (bs->tx_len && bs->pending < 12 && + !(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & BCM2835_AUX_SPI_STAT_TX_FULL)) + { + bcm2835aux_wr_fifo(bs); + } + +_enable_irq: + bcm2835aux_spi_enable_irq(bs); + + rt_completion_wait(&bs->done, RT_WAITING_FOREVER); + +_out_unprepare: + /* Unprepare message */ + bcm2835aux_spi_reset_hw(bs); + + return msg->length; +} + +static struct rt_spi_ops bcm2835aux_spi_ops = +{ + .configure = bcm2835aux_spi_configure, + .xfer = bcm2835aux_spi_xfer, +}; + +static void bcm2835aux_spi_isr(int irq, void *param) +{ + struct bcm2835aux_spi *bs = param; + + if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) & + (BCM2835_AUX_SPI_CNTL1_TXEMPTY | BCM2835_AUX_SPI_CNTL1_IDLE))) + { + return; + } + + bcm2835aux_spi_transfer_helper(bs); + + if (!bs->tx_len) + { + /* Disable tx fifo empty interrupt */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] | BCM2835_AUX_SPI_CNTL1_IDLE); + } + + if (!bs->rx_len) + { + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + rt_completion_done(&bs->done); + + /* Unprepare message */ + bcm2835aux_spi_reset_hw(bs); + } +} + +static void bcm2835aux_spi_free(struct bcm2835aux_spi *bs) +{ + if (bs->regs) + { + rt_iounmap(bs->regs); + } + + if (!rt_is_err_or_null(bs->clk)) + { + rt_clk_disable_unprepare(bs->clk); + } + + rt_free(bs); +} + +static rt_err_t bcm2835aux_spi_probe(struct rt_platform_device *pdev) +{ + int id; + rt_err_t err; + rt_ubase_t clk_hz; + const char *bus_name; + struct rt_device *dev = &pdev->parent; + struct bcm2835aux_spi *bs = rt_calloc(1, sizeof(*bs)); + + if (!bs) + { + return -RT_ENOMEM; + } + + bs->regs = rt_dm_dev_iomap(dev, 0); + + if (!bs->regs) + { + err = -RT_EIO; + goto _fail; + } + + bs->irq = rt_dm_dev_get_irq(dev, 0); + + if (bs->irq < 0) + { + err = bs->irq; + goto _fail; + } + + bs->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(bs->clk)) + { + err = rt_ptr_err(bs->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(bs->clk))) + { + goto _fail; + } + + if (!(clk_hz = rt_clk_get_rate(bs->clk))) + { + err = -RT_EINVAL; + goto _fail; + } + + /* Reset SPI-HW block */ + bcm2835aux_spi_reset_hw(bs); + + bs->mode = RT_SPI_CPOL | RT_SPI_CS_HIGH | RT_SPI_NO_CS; + bs->parent.num_chipselect = 1; + rt_completion_init(&bs->done); + + dev->user_data = bs; + + bs->parent.parent.ofw_node = dev->ofw_node; + + if ((id = pdev->dev_id) >= 0) + { + rt_dm_dev_set_name(&bs->parent.parent, "spi%u", id); + } + else + { + rt_dm_dev_set_name_auto(&bs->parent.parent, "spi"); + } + bus_name = rt_dm_dev_get_name(&bs->parent.parent); + + rt_hw_interrupt_install(bs->irq, bcm2835aux_spi_isr, bs, bus_name); + rt_hw_interrupt_umask(bs->irq); + + if ((err = rt_spi_bus_register(&bs->parent, bus_name, &bcm2835aux_spi_ops))) + { + goto _free_irq; + } + + return RT_EOK; + +_free_irq: + rt_hw_interrupt_mask(bs->irq); + rt_pic_detach_irq(bs->irq, bs); + +_fail: + bcm2835aux_spi_free(bs); + + return err; +} + +static rt_err_t bcm2835aux_spi_remove(struct rt_platform_device *pdev) +{ + struct bcm2835aux_spi *bs = pdev->parent.user_data; + + rt_hw_interrupt_mask(bs->irq); + rt_pic_detach_irq(bs->irq, bs); + + rt_device_unregister(&bs->parent.parent); + + bcm2835aux_spi_reset_hw(bs); + + bcm2835aux_spi_free(bs); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835aux_spi_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-aux-spi", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835aux_spi_driver = +{ + .name = "bcm2835-aux-spi", + .ids = bcm2835aux_spi_ofw_ids, + + .probe = bcm2835aux_spi_probe, + .remove = bcm2835aux_spi_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835aux_spi_driver); diff --git a/bsp/raspberry-pi/dm/thermal/Kconfig b/bsp/raspberry-pi/dm/thermal/Kconfig new file mode 100755 index 0000000000..081d92f606 --- /dev/null +++ b/bsp/raspberry-pi/dm/thermal/Kconfig @@ -0,0 +1,9 @@ +config RT_THERMAL_BCM2835 + bool "BCM2835" + default n + +config RT_THERMAL_BCM2711 + bool "BCM2711" + depends on RT_MFD_SYSCON + depends on RT_USING_RESET + default n diff --git a/bsp/raspberry-pi/dm/thermal/SConscript b/bsp/raspberry-pi/dm/thermal/SConscript new file mode 100755 index 0000000000..ea923cb3cd --- /dev/null +++ b/bsp/raspberry-pi/dm/thermal/SConscript @@ -0,0 +1,16 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_THERMAL_BCM2711']): + src += ['thermal-bcm2711.c'] + +if GetDepend(['RT_THERMAL_BCM2835']): + src += ['thermal-bcm2835.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/thermal/thermal-bcm2711.c b/bsp/raspberry-pi/dm/thermal/thermal-bcm2711.c new file mode 100755 index 0000000000..009ddaeb4c --- /dev/null +++ b/bsp/raspberry-pi/dm/thermal/thermal-bcm2711.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "thermal.bcm2711" +#define DBG_LVL DBG_INFO +#include + +#define AVS_RO_TEMP_STATUS 0x200 +#define AVS_RO_TEMP_STATUS_VALID_MSK (RT_BIT(16) | RT_BIT(10)) +#define AVS_RO_TEMP_STATUS_DATA_MSK RT_GENMASK(9, 0) + +struct bcm2711_thermal +{ + struct rt_thermal_zone_device parent; + + struct rt_syscon *regmap; +}; + +#define raw_to_bcm2711_thermal(raw) rt_container_of(raw, struct bcm2711_thermal, parent) + +static rt_err_t bcm2711_thermal_zone_get_temp(struct rt_thermal_zone_device *zdev, + int *out_temp) +{ + rt_err_t err; + rt_uint32_t val; + struct rt_thermal_zone_params *tz_params; + struct bcm2711_thermal *btz = raw_to_bcm2711_thermal(zdev); + + if ((err = rt_syscon_read(btz->regmap, AVS_RO_TEMP_STATUS, &val))) + { + return err; + } + + if (!(val & AVS_RO_TEMP_STATUS_VALID_MSK)) + { + return -RT_EIO; + } + + val &= AVS_RO_TEMP_STATUS_DATA_MSK; + tz_params = &btz->parent.params; + + /* Convert a HW code to a temperature reading (millidegree celsius) */ + *out_temp = tz_params->slope * val + tz_params->offset; + + return RT_EOK; +} + +const static struct rt_thermal_zone_ops bcm2711_thermal_zone_ops = +{ + .get_temp = bcm2711_thermal_zone_get_temp, +}; + +static rt_err_t bcm2711_thermal_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_ofw_node *pnp; + struct rt_device *dev = &pdev->parent; + struct bcm2711_thermal *btz = rt_calloc(1, sizeof(*btz)); + + if (!btz) + { + return -RT_ENOMEM; + } + + pnp = rt_ofw_get_parent(dev->ofw_node); + + if (!pnp) + { + err = -RT_EINVAL; + goto _fail; + } + + btz->regmap = rt_syscon_find_by_ofw_node(pnp); + rt_ofw_node_put(pnp); + + if (!btz->regmap) + { + err = -RT_EINVAL; + goto _fail; + } + + btz->parent.parent.ofw_node = dev->ofw_node; + btz->parent.ops = &bcm2711_thermal_zone_ops; + + rt_dm_dev_set_name(&btz->parent.parent, "bcm2711"); + + if ((err = rt_thermal_zone_device_register(&btz->parent))) + { + goto _fail; + } + + dev->user_data = btz; + + return RT_EOK; + +_fail: + rt_free(btz); + + return err; +} + +static rt_err_t bcm2711_thermal_remove(struct rt_platform_device *pdev) +{ + struct bcm2711_thermal *btz = pdev->parent.user_data; + + rt_thermal_zone_device_unregister(&btz->parent); + + rt_free(btz); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2711_thermal_ofw_ids[] = +{ + { .compatible = "brcm,bcm2711-thermal" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2711_thermal_driver = +{ + .name = "bcm2711-thermal", + .ids = bcm2711_thermal_ofw_ids, + + .probe = bcm2711_thermal_probe, + .remove = bcm2711_thermal_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2711_thermal_driver); diff --git a/bsp/raspberry-pi/dm/thermal/thermal-bcm2835.c b/bsp/raspberry-pi/dm/thermal/thermal-bcm2835.c new file mode 100755 index 0000000000..3c4d7e8a24 --- /dev/null +++ b/bsp/raspberry-pi/dm/thermal/thermal-bcm2835.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +/* + * Note: as per Raspberry Foundation FAQ + * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature) + * the recommended temperature range for the SoC -40C to +85C + * so the trip limit is set to 80C. + * this applies to all the BCM283X SoC + */ + +#include +#include +#include + +#define DBG_TAG "thermal.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#define BCM2835_TS_TSENSCTL 0x00 +#define BCM2835_TS_TSENSSTAT 0x04 + +#define BCM2835_TS_TSENSCTL_PRWDW RT_BIT(0) +#define BCM2835_TS_TSENSCTL_RSTB RT_BIT(1) + +/* + * bandgap reference voltage in 6 mV increments + * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV + */ +#define BCM2835_TS_TSENSCTL_CTRL_BITS 3 +#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2 +#define BCM2835_TS_TSENSCTL_CTRL_MASK \ + RT_GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \ + BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \ + BCM2835_TS_TSENSCTL_CTRL_SHIFT) +#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1 +#define BCM2835_TS_TSENSCTL_EN_INT RT_BIT(5) +#define BCM2835_TS_TSENSCTL_DIRECT RT_BIT(6) +#define BCM2835_TS_TSENSCTL_CLR_INT RT_BIT(7) +#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8 +#define BCM2835_TS_TSENSCTL_THOLD_BITS 10 +#define BCM2835_TS_TSENSCTL_THOLD_MASK \ + RT_GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \ + BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \ + BCM2835_TS_TSENSCTL_THOLD_SHIFT) +/* + * time how long the block to be asserted in reset + * which based on a clock counter (TSENS clock assumed) + */ +#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18 +#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8 +#define BCM2835_TS_TSENSCTL_REGULEN RT_BIT(26) + +#define BCM2835_TS_TSENSSTAT_DATA_BITS 10 +#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0 +#define BCM2835_TS_TSENSSTAT_DATA_MASK \ + RT_GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \ + BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \ + BCM2835_TS_TSENSSTAT_DATA_SHIFT) +#define BCM2835_TS_TSENSSTAT_VALID RT_BIT(10) +#define BCM2835_TS_TSENSSTAT_INTERRUPT RT_BIT(11) + +struct bcm2835_thermal +{ + struct rt_thermal_zone_device parent; + + void *regs; + struct rt_clk *clk; +}; + +#define raw_to_bcm2835_thermal(raw) rt_container_of(raw, struct bcm2835_thermal, parent) + +static int bcm2835_thermal_adc2temp(rt_uint32_t adc, int offset, int slope) +{ + return offset + slope * adc; +} + +static int bcm2835_thermal_temp2adc(int temp, int offset, int slope) +{ + temp -= offset; + temp /= slope; + + if (temp < 0) + { + temp = 0; + } + + if (temp >= RT_BIT(BCM2835_TS_TSENSSTAT_DATA_BITS)) + { + temp = RT_BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1; + } + + return temp; +} + +static rt_err_t bcm2835_thermal_zone_get_temp(struct rt_thermal_zone_device *zdev, + int *out_temp) +{ + rt_uint32_t val; + struct rt_thermal_zone_params *tz_params; + struct bcm2835_thermal *btz = raw_to_bcm2835_thermal(zdev); + + val = HWREG32(btz->regs + BCM2835_TS_TSENSSTAT); + + if (!(val & BCM2835_TS_TSENSSTAT_VALID)) + { + return -RT_EIO; + } + + val &= BCM2835_TS_TSENSSTAT_DATA_MASK; + tz_params = &btz->parent.params; + + *out_temp = bcm2835_thermal_adc2temp(val, tz_params->offset, tz_params->slope); + + return RT_EOK; +} + +const static struct rt_thermal_zone_ops bcm2835_thermal_zone_ops = +{ + .get_temp = bcm2835_thermal_zone_get_temp, +}; + +static rt_err_t bcm2835_thermal_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + rt_ubase_t rate; + struct rt_device *dev = &pdev->parent; + struct bcm2835_thermal *btz = rt_calloc(1, sizeof(*btz)); + + if (!btz) + { + return -RT_ENOMEM; + } + + btz->regs = rt_dm_dev_iomap(dev, 0); + + if (!btz->regs) + { + err = -RT_EIO; + goto _fail; + } + + btz->clk = rt_clk_get_by_index(dev, 0); + + if (rt_is_err(btz->clk)) + { + err = rt_ptr_err(btz->clk); + goto _fail; + } + + if ((err = rt_clk_prepare_enable(btz->clk))) + { + goto _fail; + } + + rate = rt_clk_get_rate(btz->clk); + + if (rate < 1920000 || rate > 5000000) + { + LOG_W("Clock running at %u Hz is outside of the recommended range: 1.92 to 5MHz", rate); + } + + btz->parent.parent.ofw_node = dev->ofw_node; + btz->parent.ops = &bcm2835_thermal_zone_ops; + + rt_dm_dev_set_name(&btz->parent.parent, "bcm2835"); + + if ((err = rt_thermal_zone_device_register(&btz->parent))) + { + goto _fail; + } + + /* + * right now the FW does set up the HW-block, so we are not + * touching the configuration registers. + * But if the HW is not enabled, then set it up + * using "sane" values used by the firmware right now. + */ + val = HWREG32(btz->regs + BCM2835_TS_TSENSCTL); + + if (!(val & BCM2835_TS_TSENSCTL_RSTB)) + { + int offset, slope; + struct rt_thermal_trip trip; + struct rt_thermal_zone_device *tz = &btz->parent; + struct rt_thermal_zone_params *tz_params = &tz->params; + + slope = tz_params->slope; + offset = tz_params->offset; + + if ((err = rt_thermal_zone_get_trip(tz, 0, &trip))) + { + rt_thermal_zone_device_unregister(tz); + + LOG_E("Read trip error = %s", rt_strerror(err)); + goto _fail; + } + + /* set bandgap reference voltage and enable voltage regulator */ + val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT << + BCM2835_TS_TSENSCTL_CTRL_SHIFT) | BCM2835_TS_TSENSCTL_REGULEN; + + /* use the recommended reset duration */ + val |= 0xfe << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT; + + /* trip_adc value from info */ + val |= bcm2835_thermal_temp2adc(trip.temperature, offset, slope) + << BCM2835_TS_TSENSCTL_THOLD_SHIFT; + + /* write the value back to the register as 2 steps */ + HWREG32(btz->regs + BCM2835_TS_TSENSCTL) = val; + val |= BCM2835_TS_TSENSCTL_RSTB; + HWREG32(btz->regs + BCM2835_TS_TSENSCTL) = val; + } + + dev->user_data = btz; + + return RT_EOK; + +_fail: + if (!rt_is_err_or_null(btz->clk)) + { + rt_clk_disable_unprepare(btz->clk); + rt_clk_put(btz->clk); + } + + rt_free(btz); + + return err; +} + +static rt_err_t bcm2835_thermal_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_thermal *btz = pdev->parent.user_data; + + rt_thermal_zone_device_unregister(&btz->parent); + + rt_clk_disable_unprepare(btz->clk); + rt_clk_put(btz->clk); + + rt_free(btz); + + return RT_EOK; +} + +static const struct rt_ofw_node_id bcm2835_thermal_ofw_ids[] = +{ + { .compatible = "brcm,bcm2835-thermal" }, + { .compatible = "brcm,bcm2836-thermal" }, + { .compatible = "brcm,bcm2837-thermal" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_thermal_driver = +{ + .name = "bcm2835-thermal", + .ids = bcm2835_thermal_ofw_ids, + + .probe = bcm2835_thermal_probe, + .remove = bcm2835_thermal_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_thermal_driver); diff --git a/bsp/raspberry-pi/dm/watchdog/Kconfig b/bsp/raspberry-pi/dm/watchdog/Kconfig new file mode 100755 index 0000000000..cca2dd892a --- /dev/null +++ b/bsp/raspberry-pi/dm/watchdog/Kconfig @@ -0,0 +1,5 @@ +config RT_WDT_BCM2835 + bool "Broadcom BCM2835 hardware watchdog" + depends on RT_USING_DM + depends on RT_USING_WDT + default n diff --git a/bsp/raspberry-pi/dm/watchdog/SConscript b/bsp/raspberry-pi/dm/watchdog/SConscript new file mode 100755 index 0000000000..a17da19515 --- /dev/null +++ b/bsp/raspberry-pi/dm/watchdog/SConscript @@ -0,0 +1,13 @@ +from building import * + +group = [] +src = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_WDT_BCM2835']): + src += ['watchdog-bcm2835.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/dm/watchdog/watchdog-bcm2835.c b/bsp/raspberry-pi/dm/watchdog/watchdog-bcm2835.c new file mode 100755 index 0000000000..50ee2c7765 --- /dev/null +++ b/bsp/raspberry-pi/dm/watchdog/watchdog-bcm2835.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#include + +#define PM_RSTC 0x1c +#define PM_RSTS 0x20 +#define PM_WDOG 0x24 + +#define PM_PASSWORD 0x5a000000 + +#define PM_WDOG_TIME_SET 0x000fffff +#define PM_RSTC_WRCFG_CLR 0xffffffcf +#define PM_RSTS_HADWRH_SET 0x00000040 +#define PM_RSTC_WRCFG_SET 0x00000030 +#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTC_RESET 0x00000102 + +/* + * The Raspberry Pi firmware uses the RSTS register to know which partition + * to boot from. The partition value is spread into bits 0, 2, 4, 6, 8, 10. + * Partition 63 is a special partition used by the firmware to indicate halt. + */ +#define PM_RSTS_RASPBERRYPI_HALT 0x555 + +#define SECS_TO_WDOG_TICKS(x) ((x) << 16) +#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) + +#define USEC_PER_SEC 1000000L + +struct bcm2835_wdt +{ + rt_watchdog_t parent; + + void *base; + rt_uint32_t timeout; + struct rt_spinlock lock; +}; + +#define raw_to_bcm2835_wdt(raw) rt_container_of(raw, struct bcm2835_wdt, parent) + +static struct bcm2835_wdt *bcm2835_power_off_wdt; + +static void bcm2835_wdt_start(struct bcm2835_wdt *bcm2835_wdt) +{ + rt_uint32_t cur; + rt_ubase_t level = rt_spin_lock_irqsave(&bcm2835_wdt->lock); + + HWREG32(bcm2835_wdt->base + PM_WDOG) = PM_PASSWORD | (SECS_TO_WDOG_TICKS(bcm2835_wdt->timeout) & PM_WDOG_TIME_SET); + cur = HWREG32(bcm2835_wdt->base + PM_RSTC); + HWREG32(bcm2835_wdt->base + PM_RSTC) = PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET; + + rt_spin_unlock_irqrestore(&bcm2835_wdt->lock, level); +} + +static void bcm2835_wdt_stop(struct bcm2835_wdt *bcm2835_wdt) +{ + HWREG32(bcm2835_wdt->base + PM_RSTC) = PM_PASSWORD | PM_RSTC_RESET; +} + +static rt_uint32_t bcm2835_wdt_get_timeleft(struct bcm2835_wdt *bcm2835_wdt) +{ + rt_uint32_t value = HWREG32(bcm2835_wdt->base + PM_WDOG); + + return WDOG_TICKS_TO_SECS(value & PM_WDOG_TIME_SET); +} + +static void bcm2835_restart(struct bcm2835_wdt *bcm2835_wdt) +{ + rt_uint32_t val; + + /* Use a timeout of 10 ticks (~150us) */ + HWREG32(bcm2835_wdt->base + PM_WDOG) = 10 | PM_PASSWORD; + val = HWREG32(bcm2835_wdt->base + PM_RSTC); + val &= PM_RSTC_WRCFG_CLR; + val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; + HWREG32(bcm2835_wdt->base + PM_RSTC) = val; + + /* No sleeping, possibly atomic. */ + rt_thread_mdelay(1); +} + +static rt_err_t bcm2835_wdt_init(rt_watchdog_t *wdt) +{ + return RT_EOK; +} + +static rt_err_t bcm2835_wdt_control(rt_watchdog_t *wdt, int cmd, void *args) +{ + rt_err_t status = RT_EOK; + struct bcm2835_wdt *bcm2835_wdt = raw_to_bcm2835_wdt(wdt); + + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: + *(rt_uint32_t *)args = bcm2835_wdt->timeout / USEC_PER_SEC; + break; + + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + bcm2835_wdt->timeout = *(rt_uint32_t *)args * USEC_PER_SEC; + break; + + case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: + *(rt_uint32_t *)args = bcm2835_wdt_get_timeleft(bcm2835_wdt) / USEC_PER_SEC; + break; + + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + bcm2835_wdt->timeout = 0; + break; + + case RT_DEVICE_CTRL_WDT_START: + bcm2835_wdt_start(bcm2835_wdt); + break; + + case RT_DEVICE_CTRL_WDT_STOP: + bcm2835_wdt_stop(bcm2835_wdt); + break; + + default: + status = -RT_EINVAL; + } + + return status; +} + +static const struct rt_watchdog_ops bcm2835_wdt_ops = +{ + .init = bcm2835_wdt_init, + .control = bcm2835_wdt_control, +}; + +static void bcm2835_wdt_power_off(void) +{ + rt_uint32_t val; + struct bcm2835_wdt *bcm2835_wdt = bcm2835_power_off_wdt; + + /* + * We set the watchdog hard reset bit here to distinguish this reset from + * the normal (full) reset. bootcode.bin will not reboot after a hard reset. + */ + val = HWREG32(bcm2835_wdt->base + PM_RSTS); + val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; + HWREG32(bcm2835_wdt->base + PM_RSTS) = val; + + /* Continue with normal reset mechanism */ + bcm2835_restart(bcm2835_wdt); +} + +static void bcm2835_wdt_power_reboot(void) +{ + struct bcm2835_wdt *bcm2835_wdt = bcm2835_power_off_wdt; + + /* Continue with normal reset mechanism */ + bcm2835_restart(bcm2835_wdt); +} + +static rt_err_t bcm2835_wdt_probe(struct rt_platform_device *pdev) +{ + const char *dev_name; + struct bcm2835_pm *pm = pdev->priv; + struct rt_ofw_node *np = pm->ofw_node; + struct bcm2835_wdt *bcm2835_wdt = rt_calloc(1, sizeof(*bcm2835_wdt)); + + if (!bcm2835_wdt) + { + return -RT_ENOMEM; + } + + bcm2835_wdt->base = pm->base; + rt_spin_lock_init(&bcm2835_wdt->lock); + + bcm2835_power_off_wdt = bcm2835_wdt; + + if (rt_ofw_prop_read_bool(np, "system-power-controller")) + { + if (!rt_dm_machine_shutdown) + { + rt_dm_machine_shutdown = bcm2835_wdt_power_off; + } + } + + if (!rt_dm_machine_reset) + { + rt_dm_machine_reset = bcm2835_wdt_power_reboot; + } + + pdev->parent.user_data = bcm2835_wdt; + + bcm2835_wdt->parent.ops = &bcm2835_wdt_ops; + + rt_dm_dev_set_name_auto(&bcm2835_wdt->parent.parent, "wdt"); + dev_name = rt_dm_dev_get_name(&bcm2835_wdt->parent.parent); + rt_hw_watchdog_register(&bcm2835_wdt->parent, dev_name, 0, bcm2835_wdt); + + return RT_EOK; +} + +static rt_err_t bcm2835_wdt_remove(struct rt_platform_device *pdev) +{ + struct bcm2835_wdt *bcm2835_wdt = pdev->parent.user_data; + + bcm2835_wdt_stop(bcm2835_wdt); + + rt_device_unregister(&bcm2835_wdt->parent.parent); + + if (rt_dm_machine_shutdown == bcm2835_wdt_power_off) + { + rt_dm_machine_shutdown = RT_NULL; + } + + if (rt_dm_machine_reset == bcm2835_wdt_power_reboot) + { + rt_dm_machine_reset = RT_NULL; + } + + bcm2835_power_off_wdt = RT_NULL; + + rt_free(bcm2835_wdt); + + return RT_EOK; +} + +static struct rt_platform_driver bcm2835_wdt_driver = +{ + .name = "bcm2835-wdt", + .probe = bcm2835_wdt_probe, + .remove = bcm2835_wdt_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_wdt_driver); diff --git a/bsp/raspberry-pi/raspi-dm2.0/README.md b/bsp/raspberry-pi/raspi-dm2.0/README.md deleted file mode 100644 index 9b16c4f3e8..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Raspberry PI 4-dm2.0BSP说明 - -## 1. 简介 - -树莓派4B的核心处理器为博通BCM2711(四核1.5GHz,Cortex A72架构,树莓派3是四核A53)。LPDDR4内存,由5V/3A USB-C供电或GPIO 5V。 - -外设支持上,引入了双频Wi-Fi,蓝牙5.0,千兆网卡,MIPI CSI相机接口,两个USB口,40个扩展帧。 - -这份RT-Thread BSP是针对 Raspberry Pi 4的一份移植,树莓派价格便宜, 使用者甚众,是研究和运行RT-Thread的可选平台之一。 - - -## 2. 编译说明 - -推荐使用[env工具](https://www.rt-thread.org/download.html#download-rt-thread-env-tool),可以在console下进入到`bsp\raspberry-pi\raspi4-64`目录中,运行以下命令: - -``` -scons -``` - -来编译这个板级支持包。如果编译正确无误,会产生 `rtthread.elf`, `rtthread.bin` 文件。 - -## 3. 支持情况 - -| 驱动 | 支持情况 | 备注 | -| ------ | ---- | :------: | -| UART | 支持 | pl011驱动 | -| GPIO | 尚未支持 | 等待dm2.0相关代码合入主线 | -| SPI | 尚未支持 | 等待gpio合入主线 | -| WATCHDOG | 尚未支持 | 等待gpio合入主线 | -| HDMI | 尚未支持 | 等待gpio合入主线 | -| SDIO | 支持 | 能够正常运行在qemu,但是qemu对于raspi目前只支持pio传输,后续需要硬件进行详细测试 | -| ETH | 尚未支持 | 等待gpio合入主线 | - diff --git a/bsp/raspberry-pi/raspi-dm2.0/applications/SConscript b/bsp/raspberry-pi/raspi-dm2.0/applications/SConscript deleted file mode 100644 index bda7b8b585..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/applications/SConscript +++ /dev/null @@ -1,14 +0,0 @@ -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') -CPPPATH = [cwd, str(Dir('#'))] - -group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) - -list = os.listdir(cwd) -for item in list: - if os.path.isfile(os.path.join(cwd, item, 'SConscript')): - group = group + SConscript(os.path.join(item, 'SConscript')) - -Return('group') diff --git a/bsp/raspberry-pi/raspi-dm2.0/applications/main.c b/bsp/raspberry-pi/raspi-dm2.0/applications/main.c deleted file mode 100644 index 882e458d93..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/applications/main.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - */ - -#include -#include -#include - -int main(int argc, char** argv) -{ - rt_kprintf("Hi, this is RT-Thread!!\n"); - return 0; -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/bcm2711-rpi-4-b.dtb b/bsp/raspberry-pi/raspi-dm2.0/bcm2711-rpi-4-b.dtb deleted file mode 100644 index 759c21568f..0000000000 Binary files a/bsp/raspberry-pi/raspi-dm2.0/bcm2711-rpi-4-b.dtb and /dev/null differ diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/Kconfig b/bsp/raspberry-pi/raspi-dm2.0/drivers/Kconfig deleted file mode 100644 index 34d491f587..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ - - -menu "Hardware Drivers Config" - config BSP_USING_PL011 - bool "Enable pl011 for uart" - default n - - config BSP_USING_SDHCI - bool "Enable sdhci driver" - select RT_USING_SDHCI - default y - rsource sdhci/Kconfig -endmenu diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/SConscript b/bsp/raspberry-pi/raspi-dm2.0/drivers/SConscript deleted file mode 100644 index 1a8ce83b72..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/SConscript +++ /dev/null @@ -1,25 +0,0 @@ -from building import * - -cwd = GetCurrentDir() -src = ["board.c"] -CPPPATH = [cwd, str(Dir('#'))] - -if GetDepend(['BSP_USING_PL011']): - src = src + ['drv_uart.c'] - -if GetDepend(['BSP_USING_SDHCI']): - src = src + ['drv_sd.c'] - -group = DefineGroup('driver', src, depend = [''], CPPPATH = CPPPATH) - -# build for sub-directory -list = os.listdir(cwd) -objs = [] - -for d in list: - path = os.path.join(cwd, d) - if os.path.isfile(os.path.join(path, 'SConscript')): - objs = objs + SConscript(os.path.join(d, 'SConscript')) -group = group + objs - -Return('group') diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/board.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/board.c deleted file mode 100644 index 7261199d46..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/board.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-10-28 zhujiale The first version - */ - -#define DBG_TAG "board" -#define DBG_LVL DBG_INFO -#include - -#include -#include -#include -#include -#include "board.h" -#include "drv_uart.h" - -#include "cp15.h" -#include "mmu.h" -#include - -#ifdef RT_USING_SMART -#include -#endif -void rt_hw_board_init(void) -{ - rt_hw_common_setup(); -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/board.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/board.h deleted file mode 100644 index 88e8269855..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/board.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-10-28 zhujiale The first version - */ - -#ifndef BOARD_H__ -#define BOARD_H__ - -#include -#include "mmu.h" -#include "ioremap.h" - -extern int __bss_end; -#define HEAP_BEGIN ((void*)&__bss_end) - -#ifdef RT_USING_SMART -#define HEAP_END ((size_t)KERNEL_VADDR_START + 32 * 1024 * 1024) -#define PAGE_START HEAP_END -#define PAGE_END ((size_t)KERNEL_VADDR_START + 128 * 1024 * 1024) -#else -#define KERNEL_VADDR_START 0x0 - -#define HEAP_END (KERNEL_VADDR_START + 32 * 1024 * 1024) -#define PAGE_START HEAP_END -#define PAGE_END ((size_t)PAGE_START + 128 * 1024 * 1024) -#endif - -void rt_hw_board_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.c deleted file mode 100644 index 2e8103c995..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-10-28 zhujiale The first version - */ - -#include -#include -#include "drv_sd.h" -#define DBG_TAG "SDHCI" -#ifdef DRV_DEBUG -#define DBG_LVL DBG_LOG -#else -#define DBG_LVL DBG_INFO -#endif /* DRV_DEBUG */ -#include -#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) -struct sdhci_iproc_data { - const struct sdhci_pltfm_data *pdata; - rt_uint32_t caps; - rt_uint32_t caps1; - rt_uint32_t mmc_caps; - rt_bool_t missing_caps; -}; - -struct sdhci_iproc_host { - const struct sdhci_iproc_data *data; - rt_uint32_t shadow_cmd; - rt_uint32_t shadow_blk; - rt_bool_t is_cmd_shadowed; - rt_bool_t is_blk_shadowed; -}; - -static inline rt_uint32_t sdhci_iproc_readl(struct sdhci_host *host, int reg) -{ - rt_uint32_t val = readl(host->ioaddr + reg); - - return val; -} - -static rt_uint16_t sdhci_iproc_readw(struct sdhci_host *host, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); - rt_uint32_t val; - rt_uint16_t word; - - if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) - { - /* Get the saved transfer mode */ - val = iproc_host->shadow_cmd; - } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && - iproc_host->is_blk_shadowed) - { - /* Get the saved block info */ - val = iproc_host->shadow_blk; - } else { - val = sdhci_iproc_readl(host, (reg & ~3)); - } - word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; - return word; -} - -static rt_uint8_t sdhci_iproc_readb(struct sdhci_host *host, int reg) -{ - rt_uint32_t val = sdhci_iproc_readl(host, (reg & ~3)); - rt_uint8_t byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; - return byte; -} - -static inline void sdhci_iproc_writel(struct sdhci_host *host, rt_uint32_t val, int reg) -{ - LOG_D("%s: writel [0x%02x] 0x%08x\n", - mmc_hostname(host->mmc), reg, val); - writel(val, host->ioaddr + reg); - if (host->clock <= 400000) - { - /* Round up to micro-second four SD clock delay */ - if (host->clock) - rt_hw_us_delay((4 * 1000000 + host->clock - 1) / host->clock); - else - rt_hw_us_delay(10); - } -} - -static void sdhci_iproc_writew(struct sdhci_host *host, rt_uint16_t val, int reg) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); - rt_uint32_t word_shift = REG_OFFSET_IN_BITS(reg); - rt_uint32_t mask = 0xffff << word_shift; - rt_uint32_t oldval, newval; - - if (reg == SDHCI_COMMAND) - { - /* Write the block now as we are issuing a command */ - if (iproc_host->is_blk_shadowed) - { - sdhci_iproc_writel(host, iproc_host->shadow_blk, - SDHCI_BLOCK_SIZE); - iproc_host->is_blk_shadowed = false; - } - oldval = iproc_host->shadow_cmd; - iproc_host->is_cmd_shadowed = false; - } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && - iproc_host->is_blk_shadowed) - { - /* Block size and count are stored in shadow reg */ - oldval = iproc_host->shadow_blk; - } else { - /* Read reg, all other registers are not shadowed */ - oldval = sdhci_iproc_readl(host, (reg & ~3)); - } - newval = (oldval & ~mask) | (val << word_shift); - - if (reg == SDHCI_TRANSFER_MODE) - { - /* Save the transfer mode until the command is issued */ - iproc_host->shadow_cmd = newval; - iproc_host->is_cmd_shadowed = true; - } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) - { - /* Save the block info until the command is issued */ - iproc_host->shadow_blk = newval; - iproc_host->is_blk_shadowed = true; - } else { - /* Command or other regular 32-bit write */ - sdhci_iproc_writel(host, newval, reg & ~3); - } -} - -static void sdhci_iproc_writeb(struct sdhci_host *host, rt_uint8_t val, int reg) -{ - rt_uint32_t oldval = sdhci_iproc_readl(host, (reg & ~3)); - rt_uint32_t byte_shift = REG_OFFSET_IN_BITS(reg); - rt_uint32_t mask = 0xff << byte_shift; - rt_uint32_t newval = (oldval & ~mask) | (val << byte_shift); - - sdhci_iproc_writel(host, newval, reg & ~3); -} - -static const struct sdhci_ops sdhci_iproc_bcm2711_ops = { - .read_l = sdhci_iproc_readl, - .read_w = sdhci_iproc_readw, - .read_b = sdhci_iproc_readb, - .write_l = sdhci_iproc_writel, - .write_w = sdhci_iproc_writew, - .write_b = sdhci_iproc_writeb, - .set_clock = sdhci_set_clock, - .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, -}; - -static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = { - .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, - .ops = &sdhci_iproc_bcm2711_ops, -}; - -static const struct sdhci_iproc_data bcm2711_data = { - .pdata = &sdhci_bcm2711_pltfm_data, - .mmc_caps = MMC_CAP_3_3V_DDR, -}; - -rt_err_t bcm2835_probe(struct rt_platform_device *pdev) -{ - struct sdhci_iproc_host *iproc_host; - const struct sdhci_iproc_data *iproc_data = NULL; - struct sdhci_host *host; - struct sdhci_pltfm_host *pltfm_host; - int ret; - iproc_data = &bcm2711_data; - host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); - pltfm_host = sdhci_priv(host); - iproc_host = sdhci_pltfm_priv(pltfm_host); - - iproc_host->data = iproc_data; - - ret = mmc_of_parse(host->mmc); - if (ret) - goto err; - - sdhci_get_property(pdev); - - host->mmc->caps |= iproc_host->data->mmc_caps; - - ret = sdhci_add_host(host); - if (ret) - goto err; - - return 0; -err: - return ret; -} - -static const struct rt_ofw_node_id bcm2835_ofw_ids[] = -{ - /* { .compatible = "brcm,bcm2711-emmc2"},*/ - { .compatible = "brcm,bcm2835-mmc"}, - { /* sentinel */ } -}; - -static struct rt_platform_driver bcm2835_driver = -{ - .name = "bcm2835", - .ids = bcm2835_ofw_ids, - - .probe = bcm2835_probe, - /* .remove = pl011_remove,*/ -}; - - -RT_PLATFORM_DRIVER_EXPORT(bcm2835_driver); - - diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.h deleted file mode 100644 index 506b1fafd9..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_sd.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-10-28 zhujiale The first version - */ - -#ifndef __DRV_SD_BCM2835_H_ -#define __DRV_SD_BCM2835_H_ -#include -#include -#include -#include -struct sdhci_bcm2835 { - struct sdhci_host *host; - struct rt_platform_device *pdev; - struct rt_mmcsd_req *mrq; - - void *ioaddr; - rt_mutex_t mutex; -}; -#define SDCMD 0x00 /* Command to SD card - 16 R/W */ -#define SDARG 0x04 /* Argument to SD card - 32 R/W */ -#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ -#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */ -#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */ -#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */ -#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */ -#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */ -#define SDHSTS 0x20 /* SD host status - 11 R/W */ -#define SDVDD 0x30 /* SD card power control - 1 R/W */ -#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */ -#define SDHCFG 0x38 /* Host configuration - 2 R/W */ -#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */ -#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */ -#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */ - -#define SDCMD_NEW_FLAG 0x8000 -#define SDCMD_FAIL_FLAG 0x4000 -#define SDCMD_BUSYWAIT 0x800 -#define SDCMD_NO_RESPONSE 0x400 -#define SDCMD_LONG_RESPONSE 0x200 -#define SDCMD_WRITE_CMD 0x80 -#define SDCMD_READ_CMD 0x40 -#define SDCMD_CMD_MASK 0x3f - -#define SDCDIV_MAX_CDIV 0x7ff - -#define SDHSTS_BUSY_IRPT 0x400 -#define SDHSTS_BLOCK_IRPT 0x200 -#define SDHSTS_SDIO_IRPT 0x100 -#define SDHSTS_REW_TIME_OUT 0x80 -#define SDHSTS_CMD_TIME_OUT 0x40 -#define SDHSTS_CRC16_ERROR 0x20 -#define SDHSTS_CRC7_ERROR 0x10 -#define SDHSTS_FIFO_ERROR 0x08 -/* Reserved */ -/* Reserved */ -#define SDHSTS_DATA_FLAG 0x01 - -#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR | \ - SDHSTS_CRC16_ERROR | \ - SDHSTS_REW_TIME_OUT | \ - SDHSTS_FIFO_ERROR) - -#define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT | \ - SDHSTS_TRANSFER_ERROR_MASK) - -#define SDHCFG_BUSY_IRPT_EN BIT(10) -#define SDHCFG_BLOCK_IRPT_EN BIT(8) -#define SDHCFG_SDIO_IRPT_EN BIT(5) -#define SDHCFG_DATA_IRPT_EN BIT(4) -#define SDHCFG_SLOW_CARD BIT(3) -#define SDHCFG_WIDE_EXT_BUS BIT(2) -#define SDHCFG_WIDE_INT_BUS BIT(1) -#define SDHCFG_REL_CMD_LINE BIT(0) - -#define SDVDD_POWER_OFF 0 -#define SDVDD_POWER_ON 1 - -#define SDEDM_FORCE_DATA_MODE BIT(19) -#define SDEDM_CLOCK_PULSE BIT(20) -#define SDEDM_BYPASS BIT(21) - -#define SDEDM_WRITE_THRESHOLD_SHIFT 9 -#define SDEDM_READ_THRESHOLD_SHIFT 14 -#define SDEDM_THRESHOLD_MASK 0x1f - -#define SDEDM_FSM_MASK 0xf -#define SDEDM_FSM_IDENTMODE 0x0 -#define SDEDM_FSM_DATAMODE 0x1 -#define SDEDM_FSM_READDATA 0x2 -#define SDEDM_FSM_WRITEDATA 0x3 -#define SDEDM_FSM_READWAIT 0x4 -#define SDEDM_FSM_READCRC 0x5 -#define SDEDM_FSM_WRITECRC 0x6 -#define SDEDM_FSM_WRITEWAIT1 0x7 -#define SDEDM_FSM_POWERDOWN 0x8 -#define SDEDM_FSM_POWERUP 0x9 -#define SDEDM_FSM_WRITESTART1 0xa -#define SDEDM_FSM_WRITESTART2 0xb -#define SDEDM_FSM_GENPULSES 0xc -#define SDEDM_FSM_WRITEWAIT2 0xd -#define SDEDM_FSM_STARTPOWDOWN 0xf - -#define SDDATA_FIFO_WORDS 16 - -#define FIFO_READ_THRESHOLD 4 -#define FIFO_WRITE_THRESHOLD 4 -#define SDDATA_FIFO_PIO_BURST 8 - -#define PIO_THRESHOLD 1 /* Maximum block count for PIO (0 = always DMA) */ - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.c deleted file mode 100644 index a72bbcd6e8..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018-05-05 Bernard The first version - * 2022-08-24 GuEe-GUI add OFW support - */ - -#include -#include -#include - -#include - -#include - -#include - -#define PL011_OEIM RT_BIT(10) /* overrun error interrupt mask */ -#define PL011_BEIM RT_BIT(9) /* break error interrupt mask */ -#define PL011_PEIM RT_BIT(8) /* parity error interrupt mask */ -#define PL011_FEIM RT_BIT(7) /* framing error interrupt mask */ -#define PL011_RTIM RT_BIT(6) /* receive timeout interrupt mask */ -#define PL011_TXIM RT_BIT(5) /* transmit interrupt mask */ -#define PL011_RXIM RT_BIT(4) /* receive interrupt mask */ -#define PL011_DSRMIM RT_BIT(3) /* DSR interrupt mask */ -#define PL011_DCDMIM RT_BIT(2) /* DCD interrupt mask */ -#define PL011_CTSMIM RT_BIT(1) /* CTS interrupt mask */ -#define PL011_RIMIM RT_BIT(0) /* RI interrupt mask */ - -#define PL011_DR 0x000 -#define PL011_FR 0x018 -#define PL011_IBRD 0x024 -#define PL011_FBRD 0x028 -#define PL011_LCR 0x02c -#define PL011_CR 0x030 -#define PL011_IMSC 0x038 -#define PL011_RIS 0x03c -#define PL011_DMACR 0x048 - -#define PL011_LCRH_SPS (1 << 7) -#define PL011_LCRH_WLEN_8 (3 << 5) -#define PL011_LCRH_WLEN_7 (2 << 5) -#define PL011_LCRH_WLEN_6 (1 << 5) -#define PL011_LCRH_WLEN_5 (0 << 5) -#define PL011_LCRH_FEN (1 << 4) -#define PL011_LCRH_STP2 (1 << 3) -#define PL011_LCRH_EPS (1 << 2) -#define PL011_LCRH_PEN (1 << 1) -#define PL011_LCRH_BRK (1 << 0) - -#define PL011_LCRH_WLEN(n) ((n - 5) << 5) - -#define PL011_CR_CTSEN RT_BIT(15) -#define PL011_CR_RTSEN RT_BIT(14) -#define PL011_CR_RTS RT_BIT(11) -#define PL011_CR_DTR RT_BIT(10) -#define PL011_CR_RXE RT_BIT(9) -#define PL011_CR_TXE RT_BIT(8) -#define PL011_CR_LBE RT_BIT(7) -#define PL011_CR_SIRLP RT_BIT(2) -#define PL011_CR_SIREN RT_BIT(1) -#define PL011_CR_UARTEN RT_BIT(0) - -struct pl011 -{ - struct rt_serial_device parent; - - int irq; - void *base; - rt_ubase_t freq; - struct rt_clk *clk; - struct rt_clk *pclk; - - struct rt_spinlock spinlock; -}; - -#define raw_to_pl011(raw) rt_container_of(raw, struct pl011, parent) - -rt_inline rt_uint32_t pl011_read(struct pl011 *pl011, int offset) -{ - return HWREG32(pl011->base + offset); -} - -rt_inline void pl011_write(struct pl011 *pl011, int offset, rt_uint32_t value) -{ - HWREG32(pl011->base + offset) = value; -} - -static void pl011_isr(int irqno, void *param) -{ - struct pl011 *pl011 = param; - - /* Check irq */ - if (pl011_read(pl011, PL011_RIS) & PL011_RXIM) - { - rt_base_t level = rt_spin_lock_irqsave(&pl011->spinlock); - - rt_hw_serial_isr(&pl011->parent, RT_SERIAL_EVENT_RX_IND); - - rt_spin_unlock_irqrestore(&pl011->spinlock, level); - } -} - -static rt_err_t pl011_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) -{ - rt_ubase_t quot; - struct pl011 *pl011 = raw_to_pl011(serial); - - /* Clear UART setting */ - pl011_write(pl011, PL011_CR, 0); - /* Disable FIFO */ - pl011_write(pl011, PL011_LCR, 0); - - if (cfg->baud_rate > pl011->freq / 16) - { - quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 8, cfg->baud_rate); - } - else - { - quot = RT_DIV_ROUND_CLOSEST(pl011->freq * 4, cfg->baud_rate); - } - - pl011_write(pl011, PL011_IBRD, quot >> 6); - pl011_write(pl011, PL011_FBRD, quot & 0x3f); - /* FIFO */ - pl011_write(pl011, PL011_LCR, PL011_LCRH_WLEN(cfg->data_bits)); - - /* Art enable, TX/RX enable */ - pl011_write(pl011, PL011_CR, PL011_CR_UARTEN | PL011_CR_TXE | PL011_CR_RXE); - - return RT_EOK; -} - -static rt_err_t pl011_uart_control(struct rt_serial_device *serial, int cmd, void *arg) -{ - struct pl011 *pl011 = raw_to_pl011(serial); - - switch (cmd) - { - case RT_DEVICE_CTRL_CLR_INT: - /* Disable rx irq */ - pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) & ~PL011_RXIM); - - rt_hw_interrupt_mask(pl011->irq); - - break; - - case RT_DEVICE_CTRL_SET_INT: - /* Enable rx irq */ - pl011_write(pl011, PL011_IMSC, pl011_read(pl011, PL011_IMSC) | PL011_RXIM); - - rt_hw_interrupt_umask(pl011->irq); - - break; - } - - return RT_EOK; -} - -static int pl011_uart_putc(struct rt_serial_device *serial, char c) -{ - struct pl011 *pl011 = raw_to_pl011(serial); - - while (pl011_read(pl011, PL011_FR) & PL011_TXIM) - { - rt_hw_cpu_relax(); - } - - pl011_write(pl011, PL011_DR, c); - - return 1; -} - -static int pl011_uart_getc(struct rt_serial_device *serial) -{ - int ch = -1; - struct pl011 *pl011 = raw_to_pl011(serial); - - if (!(pl011_read(pl011, PL011_FR) & PL011_RXIM)) - { - ch = pl011_read(pl011, PL011_DR); - } - - return ch; -} - -static const struct rt_uart_ops pl011_uart_ops = -{ - .configure = pl011_uart_configure, - .control = pl011_uart_control, - .putc = pl011_uart_putc, - .getc = pl011_uart_getc, -}; - -static void pl011_early_kick(struct rt_fdt_earlycon *con, int why) -{ - struct pl011 *pl011 = raw_to_pl011(con->data); - - switch (why) - { - case FDT_EARLYCON_KICK_UPDATE: - pl011->base = rt_ioremap((void *)con->mmio, con->size); - break; - - case FDT_EARLYCON_KICK_COMPLETED: - rt_iounmap(pl011->base); - break; - - default: - break; - } -} - -static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *options) -{ - rt_err_t err = RT_EOK; - static struct pl011 pl011 = { }; - - if (options && !con->mmio) - { - char *arg; - - con->mmio = RT_NULL; - - /* - * The pl011 serial port must already be setup and configured in early. - * Options are not yet supported. - * pl011, - * pl011,mmio32, - */ - serial_for_each_args(arg, options) - { - if (!rt_strcmp(arg, "pl011") || !rt_strcmp(arg, "mmio32")) - { - continue; - } - if (!con->mmio) - { - con->mmio = (rt_ubase_t)serial_base_from_args(arg); - break; - } - } - } - - if (!con->size) - { - con->size = 0x1000; - } - - if (con->mmio) - { - pl011.base = rt_ioremap_early((void *)con->mmio, con->size); - } - - if (pl011.base) - { - con->console_putc = (typeof(con->console_putc))&pl011_uart_putc; - con->console_kick = pl011_early_kick; - con->data = &pl011.parent; - pl011.parent.config = (typeof(pl011.parent.config))RT_SERIAL_CONFIG_DEFAULT; - } - else - { - err = -RT_ERROR; - } - - return err; -} -RT_FDT_EARLYCON_EXPORT(pl011, "pl011", "arm,pl011", pl011_early_setup); - -static void pl011_free(struct pl011 *pl011) -{ - if (pl011->base) - { - rt_iounmap(pl011->base); - } - - /* if (!rt_is_err_or_null(pl011->clk))*/ - /* {*/ - /* rt_clk_disable(pl011->clk);*/ - /* rt_clk_put(pl011->clk);*/ - /* }*/ - - /* if (!rt_is_err_or_null(pl011->pclk))*/ - /* {*/ - /* rt_clk_disable_unprepare(pl011->pclk);*/ - /* rt_clk_put(pl011->pclk);*/ - /* }*/ - - rt_free(pl011); -} - -static rt_err_t pl011_probe(struct rt_platform_device *pdev) -{ - rt_err_t err; - const char *name; - char isr_name[RT_NAME_MAX]; - struct rt_device *dev = &pdev->parent; - struct pl011 *pl011 = rt_calloc(1, sizeof(*pl011)); - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - - if (!pl011) - { - return -RT_ENOMEM; - } - - pl011->base = rt_dm_dev_iomap(dev, 0); - - if (!pl011->base) - { - err = -RT_EIO; - - goto _fail; - } - - pl011->irq = rt_dm_dev_get_irq(dev, 0); - - if (pl011->irq < 0) - { - err = pl011->irq; - - goto _fail; - } - - /* pl011->clk = rt_clk_get_by_index(dev, 0);*/ - - /* if (rt_is_err(pl011->clk))*/ - /* {*/ - /* err = rt_ptr_err(pl011->clk);*/ - - /* goto _fail;*/ - /* }*/ - - /* pl011->pclk = rt_clk_get_by_name(dev, "apb_pclk");*/ - - /* if (rt_is_err(pl011->pclk))*/ - /* {*/ - /* err = rt_ptr_err(pl011->pclk);*/ - - /* goto _fail;*/ - /* }*/ - - /* if ((err = rt_clk_prepare_enable(pl011->pclk)))*/ - /* {*/ - /* goto _fail;*/ - /* }*/ - - rt_dm_dev_bind_fwdata(&pl011->parent.parent, dev->ofw_node, &pl011->parent); - - /* rt_clk_enable(pl011->clk);*/ - /* pl011->freq = rt_clk_get_rate(pl011->clk);*/ - - dev->user_data = pl011; - - pl011->parent.ops = &pl011_uart_ops; - pl011->parent.config = config; - - rt_spin_lock_init(&pl011->spinlock); - - serial_dev_set_name(&pl011->parent); - name = rt_dm_dev_get_name(&pl011->parent.parent); - - rt_hw_serial_register(&pl011->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, pl011); - rt_snprintf(isr_name, RT_NAME_MAX, "%s-pl011", name); - rt_hw_interrupt_install(pl011->irq, pl011_isr, pl011, isr_name); - - return RT_EOK; - -_fail: - pl011_free(pl011); - - return err; -} - -static rt_err_t pl011_remove(struct rt_platform_device *pdev) -{ - struct rt_device *dev = &pdev->parent; - struct pl011 *pl011 = dev->user_data; - - rt_dm_dev_unbind_fwdata(dev, RT_NULL); - - rt_hw_interrupt_mask(pl011->irq); - rt_pic_detach_irq(pl011->irq, pl011); - - rt_device_unregister(&pl011->parent.parent); - - pl011_free(pl011); - - return RT_EOK; -} - -static const struct rt_ofw_node_id pl011_ofw_ids[] = -{ - { .type = "ttyAMA", .compatible = "arm,pl011" }, - { .type = "ttyAMA", .compatible = "arm,pl011-axi" }, - { /* sentinel */ } -}; - -static struct rt_platform_driver pl011_driver = -{ - .name = "serial-pl011", - .ids = pl011_ofw_ids, - - .probe = pl011_probe, - .remove = pl011_remove, -}; - -static int pl011_drv_register(void) -{ - rt_platform_driver_register(&pl011_driver); - - return 0; -} -INIT_DRIVER_EARLY_EXPORT(pl011_drv_register); diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.h deleted file mode 100644 index b47afcce14..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/drv_uart.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - */ - -#ifndef DRV_UART_H__ -#define DRV_UART_H__ - -/* register's bit*/ -#define PL011_FR_RI (1 << 8) -#define PL011_FR_TXFE (1 << 7) -#define PL011_FR_RXFF (1 << 6) -#define PL011_FR_TXFF (1 << 5) -#define PL011_FR_RXFE (1 << 4) -#define PL011_FR_BUSY (1 << 3) -#define PL011_FR_DCD (1 << 2) -#define PL011_FR_DSR (1 << 1) -#define PL011_FR_CTS (1 << 0) - -#define PL011_LCRH_SPS (1 << 7) -#define PL011_LCRH_WLEN_8 (3 << 5) -#define PL011_LCRH_WLEN_7 (2 << 5) -#define PL011_LCRH_WLEN_6 (1 << 5) -#define PL011_LCRH_WLEN_5 (0 << 5) -#define PL011_LCRH_FEN (1 << 4) -#define PL011_LCRH_STP2 (1 << 3) -#define PL011_LCRH_EPS (1 << 2) -#define PL011_LCRH_PEN (1 << 1) -#define PL011_LCRH_BRK (1 << 0) - -#define PL011_CR_CTSEN (1 << 15) -#define PL011_CR_RTSEN (1 << 14) -#define PL011_CR_RTS (1 << 11) -#define PL011_CR_DTR (1 << 10) -#define PL011_CR_RXE (1 << 9) -#define PL011_CR_TXE (1 << 8) -#define PL011_CR_LBE (1 << 7) -#define PL011_CR_SIRLP (1 << 2) -#define PL011_CR_SIREN (1 << 1) -#define PL011_CR_UARTEN (1 << 0) - -#define PL011_IMSC_TXIM (1 << 5) -#define PL011_IMSC_RXIM (1 << 4) - -#define PL011_INTERRUPT_OVERRUN_ERROR (1 << 10) -#define PL011_INTERRUPT_BREAK_ERROR (1 << 9) -#define PL011_INTERRUPT_PARITY_ERROR (1 << 8) -#define PL011_INTERRUPT_FRAMING_ERROR (1 << 7) -#define PL011_INTERRUPT_RECEIVE_TIMEOUT (1 << 6) -#define PL011_INTERRUPT_TRANSMIT (1 << 5) -#define PL011_INTERRUPT_RECEIVE (1 << 4) -#define PL011_INTERRUPT_nUARTCTS (1 << 1) - -#define PL011_REG_DR(BASE) HWREG32(BASE + 0x00) -#define PL011_REG_RSRECR(BASE) HWREG32(BASE + 0x04) -#define PL011_REG_RESERVED0(BASE) HWREG32(BASE + 0x08) -#define PL011_REG_FR(BASE) HWREG32(BASE + 0x18) -#define PL011_REG_RESERVED1(BASE) HWREG32(BASE + 0x1C) -#define PL011_REG_ILPR(BASE) HWREG32(BASE + 0x20) -#define PL011_REG_IBRD(BASE) HWREG32(BASE + 0x24) -#define PL011_REG_FBRD(BASE) HWREG32(BASE + 0x28) -#define PL011_REG_LCRH(BASE) HWREG32(BASE + 0x2C) -#define PL011_REG_CR(BASE) HWREG32(BASE + 0x30) -#define PL011_REG_IFLS(BASE) HWREG32(BASE + 0x34) -#define PL011_REG_IMSC(BASE) HWREG32(BASE + 0x38) -#define PL011_REG_RIS(BASE) HWREG32(BASE + 0x3C) -#define PL011_REG_MIS(BASE) HWREG32(BASE + 0x40) -#define PL011_REG_ICR(BASE) HWREG32(BASE + 0x44) -#define PL011_REG_DMACR(BASE) HWREG32(BASE + 0x48) -#define PL011_REG_RESERVED2(BASE) HWREG32(BASE + 0x4C) -#define PL011_REG_ITCR(BASE) HWREG32(BASE + 0x80) -#define PL011_REG_ITIP(BASE) HWREG32(BASE + 0x84) -#define PL011_REG_ITOP(BASE) HWREG32(BASE + 0x88) -#define PL011_REG_TDR(BASE) HWREG32(BASE + 0x8C) - -/* - * Auxiliary - */ -#define AUX_IRQ(BASE) HWREG32(BASE + 0x00) /* Auxiliary Interrupt status 3 */ -#define AUX_ENABLES(BASE) HWREG32(BASE + 0x04) /* Auxiliary enables 3bit */ -#define AUX_MU_IO_REG(BASE) HWREG32(BASE + 0x40) /* Mini Uart I/O Data 8bit */ -#define AUX_MU_IER_REG(BASE) HWREG32(BASE + 0x44) /* Mini Uart Interrupt Enable 8bit */ -#define AUX_MU_IIR_REG(BASE) HWREG32(BASE + 0x48) /* Mini Uart Interrupt Identify 8bit */ -#define AUX_MU_LCR_REG(BASE) HWREG32(BASE + 0x4C) /* Mini Uart Line Control 8bit */ -#define AUX_MU_MCR_REG(BASE) HWREG32(BASE + 0x50) /* Mini Uart Modem Control 8bit */ -#define AUX_MU_LSR_REG(BASE) HWREG32(BASE + 0x54) /* Mini Uart Line Status 8bit */ -#define AUX_MU_MSR_REG(BASE) HWREG32(BASE + 0x58) /* Mini Uart Modem Status 8bit */ -#define AUX_MU_SCRATCH(BASE) HWREG32(BASE + 0x5C) /* Mini Uart Scratch 8bit */ -#define AUX_MU_CNTL_REG(BASE) HWREG32(BASE + 0x60) /* Mini Uart Extra Control 8bit */ -#define AUX_MU_STAT_REG(BASE) HWREG32(BASE + 0x64) /* Mini Uart Extra Status 32bit */ -#define AUX_MU_BAUD_REG(BASE) HWREG32(BASE + 0x68) /* Mini Uart Baudrate 16bit */ -#define AUX_SPI0_CNTL0_REG(BASE) HWREG32(BASE + 0x80) /* SPI 1 Control register 0 32bit */ -#define AUX_SPI0_CNTL1_REG(BASE) HWREG32(BASE + 0x84) /* SPI 1 Control register 1 8bit */ -#define AUX_SPI0_STAT_REG(BASE) HWREG32(BASE + 0x88) /* SPI 1 Status 32bit */ -#define AUX_SPI0_IO_REG(BASE) HWREG32(BASE + 0x90) /* SPI 1 Data 32bit */ -#define AUX_SPI0_PEEK_REG(BASE) HWREG32(BASE + 0x94) /* SPI 1 Peek 16bit */ -#define AUX_SPI1_CNTL0_REG(BASE) HWREG32(BASE + 0xC0) /* SPI 2 Control register 0 32bit */ -#define AUX_SPI1_CNTL1_REG(BASE) HWREG32(BASE + 0xC4) /* SPI 2 Control register 1 8bit */ - -int rt_hw_uart_init(void); -void rt_hw_earlycon_ioremap_early(void); - -#endif /* DRV_UART_H__ */ diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/Kconfig b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/Kconfig deleted file mode 100644 index ab101b8be5..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -menuconfig RT_USING_SDHCI - bool "Using sdhci for sd/mmc drivers" - default n diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/SConscript b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/SConscript deleted file mode 100644 index 3eab8df97a..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/SConscript +++ /dev/null @@ -1,18 +0,0 @@ -from building import * - -group = [] - -if not GetDepend(['RT_USING_SDHCI']): - Return('group') - -cwd = GetCurrentDir() -CPPPATH = [cwd + '/include'] - -src = [] -src += Glob('*.c') -src += Glob('src/*.c') -src += Glob('sdhci-platform/*.c') - -group = DefineGroup('sdhci-drivers', src, depend = [''], CPPPATH = CPPPATH) - -Return('group') diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci-platform.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci-platform.h deleted file mode 100644 index bc5c7dab2a..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci-platform.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ - -#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H -#define _DRIVERS_MMC_SDHCI_PLTFM_H -#include -#include -#include -#include -#include -#include "sdhci.h" - -struct sdhci_pltfm_data -{ - const struct sdhci_ops *ops; - unsigned int quirks; - unsigned int quirks2; -}; - -struct sdhci_pltfm_host -{ - struct rt_clk *clk; - - /* migrate from sdhci_of_host */ - unsigned int clock; - rt_uint64_t xfer_mode_shadow; - - unsigned long private[]; -}; - -void sdhci_get_property(struct rt_platform_device *pdev); - -static inline void sdhci_get_of_property(struct rt_platform_device *pdev) -{ - return sdhci_get_property(pdev); -} - - -extern struct sdhci_host *sdhci_pltfm_init(struct rt_platform_device *pdev, - const struct sdhci_pltfm_data *pdata, - size_t priv_size); -extern void sdhci_pltfm_free(struct rt_platform_device *pdev); - -extern int sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev, - const struct sdhci_pltfm_data *pdata, - size_t priv_size); -extern void sdhci_pltfm_remove(struct rt_platform_device *pdev); - -extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); - -static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host) -{ - return host->private; -} - -extern const struct dev_pm_ops sdhci_pltfm_pmops; -static inline int sdhci_pltfm_suspend(struct rt_device *dev) -{ - return 0; -} -static inline int sdhci_pltfm_resume(struct rt_device *dev) -{ - return 0; -} - - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci.h deleted file mode 100644 index e58517d394..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci.h +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#ifndef __SDHCI_HW_H -#define __SDHCI_HW_H - -#include "sdhci_host.h" -#include "sdhci_misc.h" -#include "sdhci_dma.h" -#include "sdhci-platform.h" -#include -#include -#include -/* - * Controller registers - */ -#define lower_32_bits(n) ((rt_uint32_t)((n) & 0xffffffff)) -#define upper_32_bits(n) ((rt_uint32_t)(((n) >> 16) >> 16)) - -#define MAX_TUNING_LOOP 40 - -#define SDHCI_DMA_ADDRESS 0x00 -#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS -#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS - -#define SDHCI_BLOCK_SIZE 0x04 -#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) - -#define SDHCI_BLOCK_COUNT 0x06 - -#define SDHCI_ARGUMENT 0x08 - -#define SDHCI_TRANSFER_MODE 0x0C -#define SDHCI_TRNS_DMA 0x01 -#define SDHCI_TRNS_BLK_CNT_EN 0x02 -#define SDHCI_TRNS_AUTO_CMD12 0x04 -#define SDHCI_TRNS_AUTO_CMD23 0x08 -#define SDHCI_TRNS_AUTO_SEL 0x0C -#define SDHCI_TRNS_READ 0x10 -#define SDHCI_TRNS_MULTI 0x20 - -#define SDHCI_COMMAND 0x0E -#define SDHCI_CMD_RESP_MASK 0x03 -#define SDHCI_CMD_CRC 0x08 -#define SDHCI_CMD_INDEX 0x10 -#define SDHCI_CMD_DATA 0x20 -#define SDHCI_CMD_ABORTCMD 0xC0 - -#define SDHCI_CMD_RESP_NONE 0x00 -#define SDHCI_CMD_RESP_LONG 0x01 -#define SDHCI_CMD_RESP_SHORT 0x02 -#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 - -#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) -#define SDHCI_GET_CMD(c) ((c >> 8) & 0x3f) - -#define SDHCI_RESPONSE 0x10 - -#define SDHCI_BUFFER 0x20 - -#define SDHCI_PRESENT_STATE 0x24 -#define SDHCI_CMD_INHIBIT 0x00000001 -#define SDHCI_DATA_INHIBIT 0x00000002 -#define SDHCI_DOING_WRITE 0x00000100 -#define SDHCI_DOING_READ 0x00000200 -#define SDHCI_SPACE_AVAILABLE 0x00000400 -#define SDHCI_DATA_AVAILABLE 0x00000800 -#define SDHCI_CARD_PRESENT 0x00010000 -#define SDHCI_CARD_PRES_SHIFT 16 -#define SDHCI_CD_STABLE 0x00020000 -#define SDHCI_CD_LVL 0x00040000 -#define SDHCI_CD_LVL_SHIFT 18 -#define SDHCI_WRITE_PROTECT 0x00080000 -#define SDHCI_DATA_LVL_MASK 0x00F00000 -#define SDHCI_DATA_LVL_SHIFT 20 -#define SDHCI_DATA_0_LVL_MASK 0x00100000 -#define SDHCI_CMD_LVL 0x01000000 - -#define SDHCI_HOST_CONTROL 0x28 -#define SDHCI_CTRL_LED 0x01 -#define SDHCI_CTRL_4BITBUS 0x02 -#define SDHCI_CTRL_HISPD 0x04 -#define SDHCI_CTRL_DMA_MASK 0x18 -#define SDHCI_CTRL_SDMA 0x00 -#define SDHCI_CTRL_ADMA1 0x08 -#define SDHCI_CTRL_ADMA32 0x10 -#define SDHCI_CTRL_ADMA64 0x18 -#define SDHCI_CTRL_ADMA3 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 -#define SDHCI_CTRL_CDTEST_INS 0x40 -#define SDHCI_CTRL_CDTEST_EN 0x80 - -#define SDHCI_POWER_CONTROL 0x29 -#define SDHCI_POWER_ON 0x01 -#define SDHCI_POWER_180 0x0A -#define SDHCI_POWER_300 0x0C -#define SDHCI_POWER_330 0x0E -/* - * VDD2 - UHS2 or PCIe/NVMe - * VDD2 power on/off and voltage select - */ -#define SDHCI_VDD2_POWER_ON 0x10 -#define SDHCI_VDD2_POWER_120 0x80 -#define SDHCI_VDD2_POWER_180 0xA0 - -#define SDHCI_BLOCK_GAP_CONTROL 0x2A - -#define SDHCI_WAKE_UP_CONTROL 0x2B -#define SDHCI_WAKE_ON_INT 0x01 -#define SDHCI_WAKE_ON_INSERT 0x02 -#define SDHCI_WAKE_ON_REMOVE 0x04 - -#define SDHCI_CLOCK_CONTROL 0x2C -#define SDHCI_DIVIDER_SHIFT 8 -#define SDHCI_DIVIDER_HI_SHIFT 6 -#define SDHCI_DIV_MASK 0xFF -#define SDHCI_DIV_MASK_LEN 8 -#define SDHCI_DIV_HI_MASK 0x300 -#define SDHCI_PROG_CLOCK_MODE 0x0020 -#define SDHCI_CLOCK_CARD_EN 0x0004 -#define SDHCI_CLOCK_PLL_EN 0x0008 -#define SDHCI_CLOCK_INT_STABLE 0x0002 -#define SDHCI_CLOCK_INT_EN 0x0001 - -#define SDHCI_TIMEOUT_CONTROL 0x2E - -#define SDHCI_SOFTWARE_RESET 0x2F -#define SDHCI_RESET_ALL 0x01 -#define SDHCI_RESET_CMD 0x02 -#define SDHCI_RESET_DATA 0x04 - -#define SDHCI_INT_STATUS 0x30 -#define SDHCI_INT_ENABLE 0x34 -#define SDHCI_SIGNAL_ENABLE 0x38 -#define SDHCI_INT_RESPONSE 0x00000001 -#define SDHCI_INT_DATA_END 0x00000002 -#define SDHCI_INT_BLK_GAP 0x00000004 -#define SDHCI_INT_DMA_END 0x00000008 -#define SDHCI_INT_SPACE_AVAIL 0x00000010 -#define SDHCI_INT_DATA_AVAIL 0x00000020 -#define SDHCI_INT_CARD_INSERT 0x00000040 -#define SDHCI_INT_CARD_REMOVE 0x00000080 -#define SDHCI_INT_CARD_INT 0x00000100 -#define SDHCI_INT_RETUNE 0x00001000 -#define SDHCI_INT_CQE 0x00004000 -#define SDHCI_INT_ERROR 0x00008000 -#define SDHCI_INT_TIMEOUT 0x00010000 -#define SDHCI_INT_CRC 0x00020000 -#define SDHCI_INT_END_BIT 0x00040000 -#define SDHCI_INT_INDEX 0x00080000 -#define SDHCI_INT_DATA_TIMEOUT 0x00100000 -#define SDHCI_INT_DATA_CRC 0x00200000 -#define SDHCI_INT_DATA_END_BIT 0x00400000 -#define SDHCI_INT_BUS_POWER 0x00800000 -#define SDHCI_INT_AUTO_CMD_ERR 0x01000000 -#define SDHCI_INT_ADMA_ERROR 0x02000000 - -#define SDHCI_INT_NORMAL_MASK 0x00007FFF -#define SDHCI_INT_ERROR_MASK 0xFFFF8000 - -#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | SDHCI_INT_AUTO_CMD_ERR) -#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | SDHCI_INT_BLK_GAP) -#define SDHCI_INT_ALL_MASK ((unsigned int)-1) - -#define SDHCI_CQE_INT_ERR_MASK ( \ - SDHCI_INT_ADMA_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT) - -#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE) - -#define SDHCI_AUTO_CMD_STATUS 0x3C -#define SDHCI_AUTO_CMD_TIMEOUT 0x00000002 -#define SDHCI_AUTO_CMD_CRC 0x00000004 -#define SDHCI_AUTO_CMD_END_BIT 0x00000008 -#define SDHCI_AUTO_CMD_INDEX 0x00000010 - -#define SDHCI_HOST_CONTROL2 0x3E -#define SDHCI_CTRL_UHS_MASK 0x0007 -#define SDHCI_CTRL_UHS_SDR12 0x0000 -#define SDHCI_CTRL_UHS_SDR25 0x0001 -#define SDHCI_CTRL_UHS_SDR50 0x0002 -#define SDHCI_CTRL_UHS_SDR104 0x0003 -#define SDHCI_CTRL_UHS_DDR50 0x0004 -#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ -#define SDHCI_CTRL_VDD_180 0x0008 -#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 -#define SDHCI_CTRL_DRV_TYPE_B 0x0000 -#define SDHCI_CTRL_DRV_TYPE_A 0x0010 -#define SDHCI_CTRL_DRV_TYPE_C 0x0020 -#define SDHCI_CTRL_DRV_TYPE_D 0x0030 -#define SDHCI_CTRL_EXEC_TUNING 0x0040 -#define SDHCI_CTRL_TUNED_CLK 0x0080 -#define SDHCI_CMD23_ENABLE 0x0800 -#define SDHCI_CTRL_V4_MODE 0x1000 -#define SDHCI_CTRL_64BIT_ADDR 0x2000 -#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 - -#define SDHCI_CAPABILITIES 0x40 -#define SDHCI_TIMEOUT_CLK_MASK RT_GENMASK(5, 0) -#define SDHCI_TIMEOUT_CLK_SHIFT 0 -#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -#define SDHCI_CLOCK_BASE_MASK RT_GENMASK(13, 8) -#define SDHCI_CLOCK_BASE_SHIFT 8 -#define SDHCI_CLOCK_V3_BASE_MASK RT_GENMASK(15, 8) -#define SDHCI_MAX_BLOCK_MASK 0x00030000 -#define SDHCI_MAX_BLOCK_SHIFT 16 -#define SDHCI_CAN_DO_8BIT 0x00040000 -#define SDHCI_CAN_DO_ADMA2 0x00080000 -#define SDHCI_CAN_DO_ADMA1 0x00100000 -#define SDHCI_CAN_DO_HISPD 0x00200000 -#define SDHCI_CAN_DO_SDMA 0x00400000 -#define SDHCI_CAN_DO_SUSPEND 0x00800000 -#define SDHCI_CAN_VDD_330 0x01000000 -#define SDHCI_CAN_VDD_300 0x02000000 -#define SDHCI_CAN_VDD_180 0x04000000 -#define SDHCI_CAN_64BIT_V4 0x08000000 -#define SDHCI_CAN_64BIT 0x10000000 - -#define SDHCI_CAPABILITIES_1 0x44 -#define SDHCI_SUPPORT_SDR50 0x00000001 -#define SDHCI_SUPPORT_SDR104 0x00000002 -#define SDHCI_SUPPORT_DDR50 0x00000004 -#define SDHCI_DRIVER_TYPE_A 0x00000010 -#define SDHCI_DRIVER_TYPE_C 0x00000020 -#define SDHCI_DRIVER_TYPE_D 0x00000040 -#define SDHCI_RETUNING_TIMER_COUNT_MASK RT_GENMASK(11, 8) -#define SDHCI_USE_SDR50_TUNING 0x00002000 -#define SDHCI_RETUNING_MODE_MASK RT_GENMASK(15, 14) -#define SDHCI_CLOCK_MUL_MASK RT_GENMASK(23, 16) -#define SDHCI_CAN_DO_ADMA3 0x08000000 -#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ - -#define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_MAX_CURRENT_LIMIT RT_GENMASK(7, 0) -#define SDHCI_MAX_CURRENT_330_MASK RT_GENMASK(7, 0) -#define SDHCI_MAX_CURRENT_300_MASK RT_GENMASK(15, 8) -#define SDHCI_MAX_CURRENT_180_MASK RT_GENMASK(23, 16) -#define SDHCI_MAX_CURRENT_MULTIPLIER 4 - -/* 4C-4F reserved for more max current */ - -#define SDHCI_SET_ACMD12_ERROR 0x50 -#define SDHCI_SET_INT_ERROR 0x52 - -#define SDHCI_ADMA_ERROR 0x54 - -/* 55-57 reserved */ - -#define SDHCI_ADMA_ADDRESS 0x58 -#define SDHCI_ADMA_ADDRESS_HI 0x5C - -/* 60-FB reserved */ - -#define SDHCI_PRESET_FOR_HIGH_SPEED 0x64 -#define SDHCI_PRESET_FOR_SDR12 0x66 -#define SDHCI_PRESET_FOR_SDR25 0x68 -#define SDHCI_PRESET_FOR_SDR50 0x6A -#define SDHCI_PRESET_FOR_SDR104 0x6C -#define SDHCI_PRESET_FOR_DDR50 0x6E -#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ -#define SDHCI_PRESET_DRV_MASK RT_GENMASK(15, 14) -#define BIT(nr) ((1) << (nr)) - -#define SDHCI_PRESET_CLKGEN_SEL BIT(10) -#define SDHCI_PRESET_SDCLK_FREQ_MASK RT_GENMASK(9, 0) - -#define SDHCI_SLOT_INT_STATUS 0xFC - -#define SDHCI_HOST_VERSION 0xFE -#define SDHCI_VENDOR_VER_MASK 0xFF00 -#define SDHCI_VENDOR_VER_SHIFT 8 -#define SDHCI_SPEC_VER_MASK 0x00FF -#define SDHCI_SPEC_VER_SHIFT 0 -#define SDHCI_SPEC_100 0 -#define SDHCI_SPEC_200 1 -#define SDHCI_SPEC_300 2 -#define SDHCI_SPEC_400 3 -#define SDHCI_SPEC_410 4 -#define SDHCI_SPEC_420 5 - -/* - * End of controller registers. - */ - -#define SDHCI_MAX_DIV_SPEC_200 256 -#define SDHCI_MAX_DIV_SPEC_300 2046 - -/* - * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. - */ -#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) -#define ilog2(v) __rt_ffs(v) -#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) - -/* ADMA2 32-bit DMA descriptor size */ -#define SDHCI_ADMA2_32_DESC_SZ 8 - -/* ADMA2 32-bit descriptor */ -struct sdhci_adma2_32_desc -{ - rt_uint16_t cmd; - rt_uint16_t len; - rt_uint16_t addr; -} rt_align(4); -/* ADMA2 data alignment */ -#define SDHCI_ADMA2_ALIGN 4 -#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1) - -/* - * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte - * alignment for the descriptor table even in 32-bit DMA mode. Memory - * allocation is at least 8 byte aligned anyway, so just stipulate 8 always. - */ -#define SDHCI_ADMA2_DESC_ALIGN 8 - -/* - * ADMA2 64-bit DMA descriptor size - * According to SD Host Controller spec v4.10, there are two kinds of - * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit - * Descriptor, if Host Version 4 Enable is set in the Host Control 2 - * register, 128-bit Descriptor will be selected. - */ -#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12) - -/* - * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte - * aligned. - */ -struct sdhci_adma2_64_desc -{ - rt_uint16_t cmd; - rt_uint16_t len; - rt_uint16_t addr_lo; - rt_uint16_t addr_hi; -}; - -#define ADMA2_TRAN_VALID 0x21 -#define ADMA2_NOP_END_VALID 0x3 -#define ADMA2_END 0x2 - -/* - * Maximum segments assuming a 512KiB maximum requisition size and a minimum - * 4KiB page size. Note this also allows enough for multiple descriptors in - * case of PAGE_SIZE >= 64KiB. - */ -#define SDHCI_MAX_SEGS 128 - -/* Allow for a command request and a data request at the same time */ -#define SDHCI_MAX_MRQS 2 - -/* - * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. - * However since the start time of the command, the time between - * command and response, and the time between response and start of data is - * not known, set the command transfer time to 10ms. - */ -#define MMC_CMD_TRANSFER_TIME (10 * 1000000L) /* max 10 ms */ - - -enum sdhci_cookie -{ - COOKIE_UNMAPPED, - COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ - COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */ -}; - -struct sdhci_host -{ - /* Data set by hardware interface driver */ - const char *hw_name; /* Hardware bus name */ - - unsigned int quirks; /* Deviations from spec. */ - - void *data_buf; -/* Controller doesn't honor resets unless we touch the clock register */ -#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0) -/* Controller has bad caps bits, but really supports DMA */ -#define SDHCI_QUIRK_FORCE_DMA (1 << 1) -/* Controller doesn't like to be reset when there is no card inserted. */ -#define SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 2) -/* Controller doesn't like clearing the power reg before a change */ -#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1 << 3) -/* Controller has an unusable DMA engine */ -#define SDHCI_QUIRK_BROKEN_DMA (1 << 5) -/* Controller has an unusable ADMA engine */ -#define SDHCI_QUIRK_BROKEN_ADMA (1 << 6) -/* Controller can only DMA from 32-bit aligned addresses */ -#define SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 7) -/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ -#define SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 8) -/* Controller can only ADMA chunks that are a multiple of 32 bits */ -#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1 << 9) -/* Controller needs to be reset after each request to stay stable */ -#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 10) -/* Controller needs voltage and power writes to happen separately */ -#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 11) -/* Controller provides an incorrect timeout value for transfers */ -#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1 << 12) -/* Controller has an issue with buffer bits for small transfers */ -#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1 << 13) -/* Controller does not provide transfer-complete interrupt when not busy */ -#define SDHCI_QUIRK_NO_BUSY_IRQ (1 << 14) -/* Controller has unreliable card detection */ -#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1 << 15) -/* Controller reports inverted write-protect state */ -#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1 << 16) -/* Controller has unusable command queue engine */ -#define SDHCI_QUIRK_BROKEN_CQE (1 << 17) -/* Controller does not like fast PIO transfers */ -#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1 << 18) -/* Controller does not have a LED */ -#define SDHCI_QUIRK_NO_LED (1 << 19) -/* Controller has to be forced to use block size of 2048 bytes */ -#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1 << 20) -/* Controller cannot do multi-block transfers */ -#define SDHCI_QUIRK_NO_MULTIBLOCK (1 << 21) -/* Controller can only handle 1-bit data transfers */ -#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1 << 22) -/* Controller needs 10ms delay between applying power and clock */ -#define SDHCI_QUIRK_DELAY_AFTER_POWER (1 << 23) -/* Controller uses SDCLK instead of TMCLK for data timeouts */ -#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1 << 24) -/* Controller reports wrong base clock capability */ -#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1 << 25) -/* Controller cannot support End Attribute in NOP ADMA descriptor */ -#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1 << 26) -/* Controller uses Auto CMD12 command to stop the transfer */ -#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1 << 28) -/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ -#define SDHCI_QUIRK_NO_HISPD_BIT (1 << 29) -/* Controller treats ADMA descriptors with length 0000h incorrectly */ -#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1 << 30) -/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ -#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1 << 31) - - unsigned int quirks2; /* More deviations from spec. */ - -#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1 << 0) -#define SDHCI_QUIRK2_HOST_NO_CMD23 (1 << 1) -/* The system physically doesn't support 1.8v, even if the host does */ -#define SDHCI_QUIRK2_NO_1_8_V (1 << 2) -#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1 << 3) -#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1 << 4) -/* Controller has a non-standard host control register */ -#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1 << 5) -/* Controller does not support HS200 */ -#define SDHCI_QUIRK2_BROKEN_HS200 (1 << 6) -/* Controller does not support DDR50 */ -#define SDHCI_QUIRK2_BROKEN_DDR50 (1 << 7) -/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ -#define SDHCI_QUIRK2_STOP_WITH_TC (1 << 8) -/* Controller does not support 64-bit DMA */ -#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1 << 9) -/* need clear transfer mode register before send cmd */ -#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1 << 10) -/* Capability register bit-63 indicates HS400 support */ -#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1 << 11) -/* forced tuned clock */ -#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1 << 12) -/* disable the block count for single block transactions */ -#define SDHCI_QUIRK2_SUPPORT_SINGLE (1 << 13) -/* Controller broken with using ACMD23 */ -#define SDHCI_QUIRK2_ACMD23_BROKEN (1 << 14) -/* Broken Clock divider zero in controller */ -#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1 << 15) -/* Controller has CRC in 136 bit Command Response */ -#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1 << 16) -/* - * Disable HW timeout if the requested timeout is more than the maximum - * obtainable timeout. - */ -#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1 << 17) -/* - * 32-bit block count may not support eMMC where upper bits of CMD23 are used - * for other purposes. Consequently we support 16-bit block count by default. - * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit - * block count. - */ -#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1 << 18) -/* Issue CMD and DATA reset together */ -#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1 << 19) - - int irq; /* Device IRQ */ - void *ioaddr; /* Mapped address */ - char *bounce_buffer; /* For packing SDMA reads/writes */ - rt_uint64_t bounce_addr; - unsigned int bounce_buffer_size; - - const struct sdhci_ops *ops; /* Low level hw interface */ - - /* Internal data */ - struct mmc_host *mmc; /* MMC structure */ - struct mmc_host_ops mmc_host_ops; /* MMC host ops */ - rt_uint64_t dma_mask; /* custom DMA mask */ - - rt_spinlock_t lock; - int flags; /* Host attributes */ -#define SDHCI_USE_SDMA (1 << 0) /* Host is SDMA capable */ -#define SDHCI_USE_ADMA (1 << 1) /* Host is ADMA capable */ -#define SDHCI_REQ_USE_DMA (1 << 2) /* Use DMA for this req. */ -#define SDHCI_DEVICE_DEAD (1 << 3) /* Device unresponsive */ -#define SDHCI_SDR50_NEEDS_TUNING (1 << 4) /* SDR50 needs tuning */ -#define SDHCI_AUTO_CMD12 (1 << 6) /* Auto CMD12 support */ -#define SDHCI_AUTO_CMD23 (1 << 7) /* Auto CMD23 support */ -#define SDHCI_PV_ENABLED (1 << 8) /* Preset value enabled */ -#define SDHCI_USE_64_BIT_DMA (1 << 12) /* Use 64-bit DMA */ -#define SDHCI_HS400_TUNING (1 << 13) /* Tuning for HS400 */ -#define SDHCI_SIGNALING_330 (1 << 14) /* Host is capable of 3.3V signaling */ -#define SDHCI_SIGNALING_180 (1 << 15) /* Host is capable of 1.8V signaling */ -#define SDHCI_SIGNALING_120 (1 << 16) /* Host is capable of 1.2V signaling */ - - unsigned int version; /* SDHCI spec. version */ - - unsigned int max_clk; /* Max possible freq (MHz) */ - unsigned int timeout_clk; /* Timeout freq (KHz) */ - rt_uint8_t max_timeout_count; /* Vendor specific max timeout count */ - unsigned int clk_mul; /* Clock Muliplier value */ - - unsigned int clock; /* Current clock (MHz) */ - rt_uint8_t pwr; /* Current voltage */ - rt_uint8_t drv_type; /* Current UHS-I driver type */ - rt_bool_t reinit_uhs; /* Force UHS-related re-initialization */ - - rt_bool_t runtime_suspended; /* Host is runtime suspended */ - rt_bool_t bus_on; /* Bus power prevents runtime suspend */ - rt_bool_t preset_enabled; /* Preset is enabled */ - rt_bool_t pending_reset; /* Cmd/data reset is pending */ - rt_bool_t irq_wake_enabled; /* IRQ wakeup is enabled */ - rt_bool_t v4_mode; /* Host Version 4 Enable */ - rt_bool_t use_external_dma; /* Host selects to use external DMA */ - rt_bool_t always_defer_done; /* Always defer to complete requests */ - - struct rt_mmcsd_req *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ - struct rt_mmcsd_cmd *cmd; /* Current command */ - struct rt_mmcsd_cmd *data_cmd; /* Current data command */ - struct rt_mmcsd_cmd *deferred_cmd; /* Deferred command */ - struct rt_mmcsd_data *data; /* Current data request */ - unsigned int data_early : 1; /* Data finished before cmd */ - - unsigned int blocks; /* remaining PIO blocks */ - - int sg_count; /* Mapped sg entries */ - int max_adma; /* Max. length in ADMA descriptor */ - - void *adma_table; /* ADMA descriptor table */ - void *align_buffer; /* Bounce buffer */ - - size_t adma_table_sz; /* ADMA descriptor table size */ - size_t align_buffer_sz; /* Bounce buffer size */ - - rt_uint64_t adma_addr; /* Mapped ADMA descr. table */ - rt_uint64_t align_addr; /* Mapped bounce buffer */ - - unsigned int desc_sz; /* ADMA current descriptor size */ - unsigned int alloc_desc_sz; /* ADMA descr. max size host supports */ - - struct rt_workqueue *complete_wq; /* Request completion wq */ - struct rt_work complete_work; /* Request completion work */ - - struct rt_workqueue *irq_wq; - struct rt_work irq_work; - - struct rt_timer timer; /* Timer for timeouts */ - struct rt_timer data_timer; /* Timer for data timeouts */ - - rt_uint32_t caps; /* CAPABILITY_0 */ - rt_uint32_t caps1; /* CAPABILITY_1 */ - rt_bool_t read_caps; /* Capability flags have been read */ - - rt_bool_t sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */ - unsigned int ocr_avail_sdio; /* OCR bit masks */ - unsigned int ocr_avail_sd; - unsigned int ocr_avail_mmc; - rt_uint32_t ocr_mask; /* available voltages */ - - unsigned timing; /* Current timing */ - - rt_uint32_t thread_isr; - - /* cached registers */ - rt_uint32_t ier; - - rt_bool_t cqe_on; /* CQE is operating */ - rt_uint32_t cqe_ier; /* CQE interrupt mask */ - rt_uint32_t cqe_err_ier; /* CQE error interrupt mask */ - - rt_wqueue_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ - unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ - - unsigned int tuning_count; /* Timer count for re-tuning */ - unsigned int tuning_mode; /* Re-tuning mode supported by host */ - unsigned int tuning_err; /* Error code for re-tuning */ -#define SDHCI_TUNING_MODE_1 0 -#define SDHCI_TUNING_MODE_2 1 -#define SDHCI_TUNING_MODE_3 2 - /* Delay (ms) between tuning commands */ - int tuning_delay; - int tuning_loop_count; - - /* Host SDMA buffer boundary. */ - rt_uint32_t sdma_boundary; - - /* Host ADMA table count */ - rt_uint32_t adma_table_cnt; - rt_uint64_t data_timeout; - - unsigned long private[]; -}; - -struct sdhci_ops -{ - rt_uint32_t (*read_l)(struct sdhci_host *host, int reg); - rt_uint16_t (*read_w)(struct sdhci_host *host, int reg); - rt_uint8_t (*read_b)(struct sdhci_host *host, int reg); - void (*write_l)(struct sdhci_host *host, rt_uint32_t val, int reg); - void (*write_w)(struct sdhci_host *host, rt_uint16_t val, int reg); - void (*write_b)(struct sdhci_host *host, rt_uint8_t val, int reg); - void (*set_clock)(struct sdhci_host *host, unsigned int clock); - void (*set_power)(struct sdhci_host *host, unsigned char mode, - unsigned short vdd); - - rt_uint32_t (*irq)(struct sdhci_host *host, rt_uint32_t intmask); - - int (*set_dma_mask)(struct sdhci_host *host); - int (*enable_dma)(struct sdhci_host *host); - unsigned int (*get_max_clock)(struct sdhci_host *host); - unsigned int (*get_min_clock)(struct sdhci_host *host); - /* get_timeout_clock should return clk rate in unit of Hz */ - unsigned int (*get_timeout_clock)(struct sdhci_host *host); - unsigned int (*get_max_timeout_count)(struct sdhci_host *host); - void (*set_timeout)(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd); - void (*set_bus_width)(struct sdhci_host *host, int width); - void (*platform_send_init_74_clocks)(struct sdhci_host *host, - rt_uint8_t power_mode); - unsigned int (*get_ro)(struct sdhci_host *host); - void (*reset)(struct sdhci_host *host, rt_uint8_t mask); - int (*platform_execute_tuning)(struct sdhci_host *host, rt_uint32_t opcode); - void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); - void (*hw_reset)(struct sdhci_host *host); - void (*adma_workaround)(struct sdhci_host *host, rt_uint32_t intmask); - void (*card_event)(struct sdhci_host *host); - void (*voltage_switch)(struct sdhci_host *host); - void (*adma_write_desc)(struct sdhci_host *host, void **desc, - rt_uint64_t addr, int len, unsigned int cmd); - void (*copy_to_bounce_buffer)(struct sdhci_host *host, - struct rt_mmcsd_data *data, - unsigned int length); - void (*request_done)(struct sdhci_host *host, - struct rt_mmcsd_req *mrq); - void (*dump_vendor_regs)(struct sdhci_host *host); -}; - -static inline rt_uint8_t rt_uint8_t_read(const volatile void *addr) -{ - return *(const volatile rt_uint8_t *)addr; -} - -static inline rt_uint16_t rt_uint16_t_read(const volatile void *addr) -{ - return *(const volatile rt_uint16_t *)addr; -} - -static inline rt_uint32_t rt_uint32_t_read(const volatile void *addr) -{ - return *(const volatile rt_uint32_t *)addr; -} - -static inline void rt_uint8_t_write(rt_uint8_t value, volatile void *addr) -{ - *(volatile rt_uint8_t *)addr = value; -} - -static inline void rt_uint16_t_write(rt_uint16_t value, volatile void *addr) -{ - *(volatile rt_uint16_t *)addr = value; -} - -static inline void rt_uint32_t_write(rt_uint32_t value, volatile void *addr) -{ - *(volatile rt_uint32_t *)addr = value; -} - -#define readb(c) rt_uint8_t_read(c) -#define readw(c) rt_uint16_t_read(c) -#define readl(c) rt_uint32_t_read(c) -#define readsb(p, d, l) ({ __raw_readsb(p,d,l); __iormb(); }) -#define readsw(p, d, l) ({ __raw_readsw(p,d,l); __iormb(); }) -#define readsl(p, d, l) ({ __raw_readsl(p,d,l); __iormb(); }) - -#define writeb(v, c) rt_uint8_t_write(v, c) -#define writew(v, c) rt_uint16_t_write(v, c) -#define writel(v, c) rt_uint32_t_write(v, c) -#define writesb(p, d, l) ({ __iowmb(); __raw_writesb(p,d,l); }) -#define writesw(p, d, l) ({ __iowmb(); __raw_writesw(p,d,l); }) -#define writesl(p, d, l) ({ __iowmb(); __raw_writesl(p,d,l); }) - -static inline void sdhci_writel(struct sdhci_host *host, rt_uint32_t val, int reg) -{ - if (host->ops->write_l) - host->ops->write_l(host, val, reg); - else - writel(val, host->ioaddr + reg); -} - -static inline void sdhci_writew(struct sdhci_host *host, rt_uint16_t val, int reg) -{ - if (host->ops->write_w) - host->ops->write_w(host, val, reg); - else - writew(val, host->ioaddr + reg); -} - -static inline void sdhci_writeb(struct sdhci_host *host, rt_uint8_t val, int reg) -{ - if (host->ops->write_b) - host->ops->write_b(host, val, reg); - else - writeb(val, host->ioaddr + reg); -} - -static inline rt_uint32_t sdhci_readl(struct sdhci_host *host, int reg) -{ - if (host->ops->read_l) - return host->ops->read_l(host, reg); - else - return readl(host->ioaddr + reg); -} - -static inline rt_uint16_t sdhci_readw(struct sdhci_host *host, int reg) -{ - if (host->ops->read_w) - return host->ops->read_w(host, reg); - else - return readw(host->ioaddr + reg); -} - -static inline rt_uint8_t sdhci_readb(struct sdhci_host *host, int reg) -{ - if (host->ops->read_b) - return host->ops->read_b(host, reg); - else - return readb(host->ioaddr + reg); -} - -struct sdhci_host *sdhci_alloc_host(struct rt_device *dev, size_t priv_size); -void sdhci_free_host(struct sdhci_host *host); - -static inline void *sdhci_priv(struct sdhci_host *host) -{ - return host->private; -} - -void __sdhci_read_caps(struct sdhci_host *host, const rt_uint16_t *ver, - const rt_uint32_t *caps, const rt_uint32_t *caps1); -int sdhci_setup_host(struct sdhci_host *host); -void sdhci_cleanup_host(struct sdhci_host *host); -int __sdhci_add_host(struct sdhci_host *host); -int sdhci_add_host(struct sdhci_host *host); -void sdhci_remove_host(struct sdhci_host *host, int dead); - -static inline void sdhci_read_caps(struct sdhci_host *host) -{ - __sdhci_read_caps(host, NULL, NULL, NULL); -} - -rt_uint16_t sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, - unsigned int *actual_clock); -void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); -void sdhci_enable_clk(struct sdhci_host *host, rt_uint16_t clk); -void sdhci_set_power(struct sdhci_host *host, unsigned char mode, - unsigned short vdd); -void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, - unsigned char mode, - unsigned short vdd); -void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, - unsigned short vdd); -int sdhci_get_cd_nogpio(struct mmc_host *mmc); -void sdhci_request(struct mmc_host *mmc, struct rt_mmcsd_req *mrq); -int sdhci_request_atomic(struct mmc_host *mmc, struct rt_mmcsd_req *mrq); -void sdhci_set_bus_width(struct sdhci_host *host, int width); -void sdhci_reset(struct sdhci_host *host, rt_uint8_t mask); -void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); -int sdhci_execute_tuning(struct mmc_host *mmc, rt_uint32_t opcode); -int __sdhci_execute_tuning(struct sdhci_host *host, rt_uint32_t opcode); -void sdhci_set_ios(struct mmc_host *mmc, struct rt_mmcsd_io_cfg *ios); -int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct rt_mmcsd_io_cfg *ios); -void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); -void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, - rt_uint64_t addr, int len, unsigned int cmd); - -void sdhci_cqe_enable(struct mmc_host *mmc); -void sdhci_cqe_disable(struct mmc_host *mmc, rt_bool_t recovery); -rt_bool_t sdhci_cqe_irq(struct sdhci_host *host, rt_uint32_t intmask, int *cmd_error, - int *data_error); - -void sdhci_dumpregs(struct sdhci_host *host); -void sdhci_enable_v4_mode(struct sdhci_host *host); - -void sdhci_start_tuning(struct sdhci_host *host); -void sdhci_end_tuning(struct sdhci_host *host); -void sdhci_reset_tuning(struct sdhci_host *host); -void sdhci_send_tuning(struct sdhci_host *host, rt_uint32_t opcode); -void sdhci_abort_tuning(struct sdhci_host *host, rt_uint32_t opcode); -void sdhci_switch_external_dma(struct sdhci_host *host, rt_bool_t en); -void sdhci_set_data_timeout_irq(struct sdhci_host *host, rt_bool_t enable); -void __sdhci_set_timeout(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd); - -#endif /* __SDHCI_HW_H */ diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_dma.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_dma.h deleted file mode 100644 index 934e5c5bb1..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_dma.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#ifndef __SDHCI_DMA_H__ -#define __SDHCI_DMA_H__ - -#include "ioremap.h" -#include -enum dma_data_direction -{ - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; -#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL << (n)) - 1)) - -int dma_set_mask_and_coherent(struct rt_device *dev, rt_uint64_t mask); -unsigned long virt_to_phys(volatile void *address); -void *dma_alloc_coherent(struct rt_device *dev, size_t size, - rt_uint64_t *dma_handle); -void dma_free_coherent(struct rt_device *dev, size_t size, - void *cpu_addr, unsigned long dma_handle); - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_host.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_host.h deleted file mode 100644 index 23d3a1fc65..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_host.h +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#ifndef __SDHCI_MMC_H__ -#define __SDHCI_MMC_H__ - -#include -#include -#include -#include -#include "sdhci_dma.h" -#define mmc_dev(x) ((x)->parent) - -#define MMC_SEND_TUNING_BLOCK_HS200 SEND_TUNING_BLOCK_HS200 -#define MMC_SEND_TUNING_BLOCK SEND_TUNING_BLOCK -#define MMC_STOP_TRANSMISSION STOP_TRANSMISSION -#define MMC_BUS_TEST_R 14 /* adtc R1 */ -#define MMC_WRITE_MULTIPLE_BLOCK WRITE_MULTIPLE_BLOCK -#define MMC_READ_MULTIPLE_BLOCK READ_MULTIPLE_BLOCK - -#define MMC_TIMING_UHS_DDR50 MMCSD_TIMING_UHS_DDR50 -#define MMC_TIMING_UHS_SDR50 MMCSD_TIMING_UHS_SDR50 -#define MMC_TIMING_MMC_HS200 MMCSD_TIMING_MMC_HS200 -#define MMC_TIMING_MMC_HS400 MMCSD_TIMING_MMC_HS400 -#define MMC_TIMING_UHS_SDR104 MMCSD_TIMING_UHS_SDR104 -#define MMC_TIMING_UHS_SDR25 MMCSD_TIMING_UHS_SDR25 -#define MMC_TIMING_MMC_DDR52 MMCSD_TIMING_MMC_DDR52 -#define MMC_TIMING_UHS_SDR12 MMCSD_TIMING_UHS_SDR12 -#define MMC_TIMING_SD_HS MMCSD_TIMING_SD_HS -#define MMC_TIMING_MMC_HS MMCSD_TIMING_MMC_HS - -#define MMC_POWER_OFF MMCSD_POWER_OFF -#define MMC_POWER_UP MMCSD_POWER_UP -#define MMC_POWER_ON MMCSD_POWER_ON -#define MMC_POWER_UNDEFINED 3 - -#define MMC_SET_DRIVER_TYPE_B 0 -#define MMC_SET_DRIVER_TYPE_A 1 -#define MMC_SET_DRIVER_TYPE_C 2 -#define MMC_SET_DRIVER_TYPE_D 3 - -#define MMC_SIGNAL_VOLTAGE_330 0 -#define MMC_SIGNAL_VOLTAGE_180 1 -#define MMC_SIGNAL_VOLTAGE_120 2 - -#define MMC_RSP_PRESENT (1 << 16) -#define MMC_RSP_136 (1 << 17) /* 136 bit response */ -#define MMC_RSP_CRC (1 << 18) /* expect valid crc */ -#define MMC_RSP_BUSY (1 << 19) /* card may send busy */ -#define MMC_RSP_OPCODE (1 << 20) /* response contains opcode */ - -/* - * These are the native response types, and correspond to valid bit - * patterns of the above flags. One additional valid pattern - * is all zeros, which means we don't expect a response. - */ -#define MMC_RSP_NONE (0) -#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) -#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) -#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) -#define MMC_RSP_R3 (MMC_RSP_PRESENT) -#define MMC_RSP_R4 (MMC_RSP_PRESENT) -#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) -#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) -#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) - -#define MMC_CMD_ADTC CMD_ADTC - -#define MMC_BUS_WIDTH_8 MMCSD_BUS_WIDTH_8 -#define MMC_BUS_WIDTH_4 MMCSD_BUS_WIDTH_4 -#define MMC_BUS_WIDTH_1 MMCSD_BUS_WIDTH_1 - -#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ -#define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */ -enum mmc_blk_status -{ - MMC_BLK_SUCCESS = 0, - MMC_BLK_PARTIAL, - MMC_BLK_CMD_ERR, - MMC_BLK_RETRY, - MMC_BLK_ABORT, - MMC_BLK_DATA_ERR, - MMC_BLK_ECC_ERR, - MMC_BLK_NOMEDIUM, - MMC_BLK_NEW_REQUEST, -}; - -/************************************************************************************************ */ - -#define MMC_NUM_CLK_PHASES (MMC_TIMING_MMC_HS400 + 1) - -struct mmc_host; - -struct mmc_host_ops -{ - /* - * It is optional for the host to implement pre_req and post_req in - * order to support double buffering of requests (prepare one - * request while another request is active). - * pre_req() must always be followed by a post_req(). - * To undo a call made to pre_req(), call post_req() with - * a nonzero err condition. - */ - void (*post_req)(struct mmc_host *host, struct rt_mmcsd_req *req, - int err); - void (*pre_req)(struct mmc_host *host, struct rt_mmcsd_req *req); - void (*request)(struct mmc_host *host, struct rt_mmcsd_req *req); - - /* - * Avoid calling the next three functions too often or in a "fast - * path", since underlaying controller might implement them in an - * expensive and/or slow way. Also note that these functions might - * sleep, so don't call them in the atomic contexts! - */ - - /* - * Notes to the set_ios callback: - * ios->clock might be 0. For some controllers, setting 0Hz - * as any other frequency works. However, some controllers - * explicitly need to disable the clock. Otherwise e.g. voltage - * switching might fail because the SDCLK is not really quiet. - */ - void (*set_ios)(struct mmc_host *host, struct rt_mmcsd_io_cfg *ios); - - /* - * Return values for the get_ro callback should be: - * 0 for a read/write card - * 1 for a read-only card - * -ENOSYS when not supported (equal to NULL callback) - * or a negative errno value when something bad happened - */ - int (*get_ro)(struct mmc_host *host); - - /* - * Return values for the get_cd callback should be: - * 0 for a absent card - * 1 for a present card - * -ENOSYS when not supported (equal to NULL callback) - * or a negative errno value when something bad happened - */ - int (*get_cd)(struct mmc_host *host); - - void (*enable_sdio_irq)(struct mmc_host *host, int enable); - /* Mandatory callback when using MMC_CAP2_SDIO_IRQ_NOTHREAD. */ - void (*ack_sdio_irq)(struct mmc_host *host); - - int (*start_signal_voltage_switch)(struct mmc_host *host, struct rt_mmcsd_io_cfg *ios); - - /* Check if the card is pulling dat[0:3] low */ - int (*card_busy)(struct mmc_host *host); - - /* The tuning command opcode value is different for SD and eMMC cards */ - int (*execute_tuning)(struct mmc_host *host, unsigned opcode); - - /* Prepare HS400 target operating frequency depending host driver */ - int (*prepare_hs400_tuning)(struct mmc_host *host, struct rt_mmcsd_io_cfg *ios); - - /* Prepare switch to DDR during the HS400 init sequence */ - int (*hs400_prepare_ddr)(struct mmc_host *host); - - /* Prepare for switching from HS400 to HS200 */ - void (*hs400_downgrade)(struct mmc_host *host); - - /* Complete selection of HS400 */ - void (*hs400_complete)(struct mmc_host *host); - - /* Prepare enhanced strobe depending host driver */ - void (*hs400_enhanced_strobe)(struct mmc_host *host, - struct rt_mmcsd_io_cfg *ios); - - /* Reset the eMMC card via RST_n */ - void (*hw_reset)(struct mmc_host *host); - void (*card_event)(struct mmc_host *host); -}; - -struct regulator; -struct mmc_pwrseq; - -struct mmc_supply -{ - struct regulator *vmmc; /* Card power supply */ - struct regulator *vqmmc; /* Optional Vccq supply */ -}; - -struct mmc_ctx -{ - struct task_struct *task; -}; - -/* VDD voltage 3.3 ~ 3.4 */ -#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ -#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ - -#define MMC_CAP2_HS200_1_8V_SDR MMCSD_SUP_HS200_1V8 -#define MMC_CAP_4_BIT_DATA MMCSD_BUSWIDTH_4 -#define MMC_CAP_8_BIT_DATA MMCSD_BUSWIDTH_8 -#define MMC_CAP2_HS200 MMCSD_SUP_HS200 -#define MMC_CAP_MMC_HIGHSPEED MMCSD_SUP_HIGHSPEED -#define MMC_CAP_SD_HIGHSPEED MMCSD_SUP_HIGHSPEED -#define MMC_CAP_1_8V_DDR MMCSD_SUP_DDR_1V8 -#define MMC_CAP_3_3V_DDR MMCSD_SUP_DDR_3V3 -#define MMC_CAP_1_2V_DDR MMCSD_SUP_DDR_1V2 -#define MMC_CAP_NONREMOVABLE MMCSD_SUP_NONREMOVABLE - - -#define MMC_CAP_UHS_DDR50 0 -#define MMC_CAP2_HS400 0 -#define MMC_CAP_UHS_SDR50 0 -#define MMC_CAP_UHS_SDR25 0 -#define MMC_CAP_UHS_SDR12 0 -#define MMC_CAP_UHS_SDR104 0 -#define MMC_CAP_UHS 0 -#define MMC_CAP2_HSX00_1_8V 0 -#define MMC_CAP2_HS400_ES 0 -#define MMC_CAP_NEEDS_POLL 0 -#define MMC_CAP2_HSX00_1_2V 0 -#define MMC_CAP2_HS400_1_8V 0 -#define MMC_CAP_DRIVER_TYPE_D 0 -#define MMC_CAP_DRIVER_TYPE_C 0 -#define MMC_SET_DRIVER_TYPE_B 0 -#define MMC_CAP_DRIVER_TYPE_A 0 -#define MMC_CAP2_SDIO_IRQ_NOTHREAD 0 -#define MMC_CAP_CMD23 0 -#define MMC_CAP_SDIO_IRQ 0 - -#define MMC_CAP2_NO_SDIO (1 << 19) -#define MMC_CAP2_NO_SD (1 << 21) -#define MMC_CAP2_NO_MMC (1 << 22) -#define MMC_CAP2_CQE (1 << 23) - -#define MMC_VDD_165_195 VDD_165_195 -#define MMC_VDD_20_21 VDD_20_21 -#define MMC_VDD_29_30 VDD_29_30 -#define MMC_VDD_30_31 VDD_30_31 -#define MMC_VDD_32_33 VDD_32_33 -#define MMC_VDD_33_34 VDD_33_34 - - -struct mmc_host -{ - struct rt_mmcsd_host rthost; - struct rt_device *parent; - int index; - const struct mmc_host_ops *ops; - unsigned int f_min; - unsigned int f_max; - unsigned int f_init; - rt_uint32_t ocr_avail; - rt_uint32_t ocr_avail_sdio; /* SDIO-specific OCR */ - rt_uint32_t ocr_avail_sd; /* SD-specific OCR */ - rt_uint32_t ocr_avail_mmc; /* MMC-specific OCR */ - struct wakeup_source *ws; /* Enable consume of uevents */ - rt_uint32_t max_current_330; - rt_uint32_t max_current_300; - rt_uint32_t max_current_180; - rt_uint32_t caps; /* Host capabilities */ - - rt_uint32_t caps2; /* More host capabilities */ - - - /* host specific block data */ - unsigned int max_seg_size; /* see blk_queue_max_segment_size */ - unsigned short max_segs; /* see blk_queue_max_segments */ - unsigned short unused; - unsigned int max_req_size; /* maximum number of bytes in one req */ - unsigned int max_blk_size; /* maximum size of one mmc block */ - unsigned int max_blk_count; /* maximum number of blocks in one req */ - unsigned int max_busy_timeout; /* max busy timeout in ms */ - struct rt_mmcsd_io_cfg ios; /* current io bus settings */ - unsigned int retune_period; - /* group bitfields together to minimize padding */ - unsigned int use_spi_crc : 1; - unsigned int claimed : 1; /* host exclusively claimed */ - unsigned int doing_init_tune : 1; /* initial tuning in progress */ - unsigned int can_retune : 1; /* re-tuning can be used */ - unsigned int doing_retune : 1; /* re-tuning in progress */ - unsigned int retune_now : 1; /* do re-tuning at next req */ - unsigned int retune_paused : 1; /* re-tuning is temporarily disabled */ - unsigned int retune_crc_disable : 1; /* don't trigger retune upon crc */ - unsigned int can_dma_map_merge : 1; /* merging can be used */ - unsigned int vqmmc_enabled : 1; /* vqmmc regulator is enabled */ - - int need_retune; /* re-tuning is needed */ - int hold_retune; /* hold off re-tuning */ - rt_bool_t trigger_card_event; /* card_event necessary */ - unsigned int sdio_irqs; - rt_bool_t sdio_irq_pending; - - struct led_trigger *led; /* activity led */ - - struct mmc_supply supply; - - - /* Ongoing data transfer that allows commands during transfer */ - struct rt_mmcsd_req *ongoing_mrq; - - - unsigned int actual_clock; /* Actual HC clock rate */ - rt_uint32_t pm_caps; - unsigned long private[]; -}; - - -static inline int mmc_card_is_removable(struct mmc_host *host) -{ - return !(host->caps & MMC_CAP_NONREMOVABLE); -} - -struct device_node; - -struct mmc_host *mmc_alloc_host(int extra, struct rt_device *); -int mmc_add_host(struct mmc_host *); -void mmc_remove_host(struct mmc_host *); -void mmc_free_host(struct mmc_host *); -int mmc_of_parse(struct mmc_host *host); -int mmc_of_parse_voltage(struct mmc_host *host, rt_uint32_t *mask); - -static inline void *mmc_priv(struct mmc_host *host) -{ - return (void *)host->private; -} - - -#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI) - -#define mmc_dev(x) ((x)->parent) -#define mmc_classdev(x) (&(x)->class_dev) -#define mmc_hostname(x) (x->parent->parent.name) - -void mmc_detect_change(struct mmc_host *, unsigned long delay); -void mmc_request_done(struct mmc_host *, struct rt_mmcsd_req *); -void mmc_command_done(struct mmc_host *host, struct rt_mmcsd_req *mrq); - -void mmc_cqe_request_done(struct mmc_host *host, struct rt_mmcsd_req *mrq); - -/* - * May be called from host driver's system/runtime suspend/resume callbacks, - * to know if SDIO IRQs has been claimed. - */ -static inline rt_bool_t sdio_irq_claimed(struct mmc_host *host) -{ - return host->sdio_irqs > 0; -} - -static inline int mmc_regulator_set_ocr(struct mmc_host *mmc, - struct regulator *supply, - unsigned short vdd_bit) -{ - return 0; -} - -int mmc_regulator_get_supply(struct mmc_host *mmc); -int mmc_regulator_enable_vqmmc(struct mmc_host *mmc); -void mmc_regulator_disable_vqmmc(struct mmc_host *mmc); - -void mmc_retune_timer_stop(struct mmc_host *host); - -static inline void mmc_retune_needed(struct mmc_host *host) -{ - if (host->can_retune) - host->need_retune = 1; -} - -static inline rt_bool_t mmc_can_retune(struct mmc_host *host) -{ - return host->can_retune == 1; -} - -static inline rt_bool_t mmc_doing_retune(struct mmc_host *host) -{ - return host->doing_retune == 1; -} - -static inline rt_bool_t mmc_doing_tune(struct mmc_host *host) -{ - return host->doing_retune == 1 || host->doing_init_tune == 1; -} - -static inline int mmc_get_dma_dir(struct rt_mmcsd_data *data) -{ - return data->flags & DATA_DIR_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; -} - -static inline rt_bool_t mmc_op_multi(rt_uint32_t opcode) -{ - return opcode == MMC_WRITE_MULTIPLE_BLOCK || opcode == MMC_READ_MULTIPLE_BLOCK; -} - -static inline rt_bool_t mmc_op_tuning(rt_uint32_t opcode) -{ - return opcode == MMC_SEND_TUNING_BLOCK || opcode == MMC_SEND_TUNING_BLOCK_HS200; -} - -int mmc_gpio_get_cd(struct mmc_host *host); -void mmc_detect_change(struct mmc_host *host, unsigned long delay); -int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct rt_mmcsd_io_cfg *ios); -rt_bool_t mmc_can_gpio_ro(struct mmc_host *host); -int mmc_gpio_get_ro(struct mmc_host *host); - -int mmc_send_tuning(struct mmc_host *host, rt_uint32_t opcode, int *cmd_error); -int mmc_send_abort_tuning(struct mmc_host *host, rt_uint32_t opcode); -int mmc_of_parse(struct mmc_host *host); - - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_misc.h b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_misc.h deleted file mode 100644 index 2205b1bac3..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/include/sdhci_misc.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#ifndef __SDHCI_MISC_H__ -#define __SDHCI_MISC_H__ - -#include "sdhci_host.h" - -#define __BF_FIELD_CHECK(...) -#define __bf_shf(x) (__builtin_ffsll(x) - 1) -#define FIELD_GET(_mask, _reg) \ - ({ \ - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ - (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ - }) - -#define FIELD_PREP(_mask, _val) \ - ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ - ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ - }) - -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -#define min_t(type, x, y) (((type)x < (type)y) ? x : y) -#define max_t(type, x, y) (((type)x > (type)y) ? x : y) -#define min(x, y) ((x) < (y) ? (x) : (y)) - -#define from_timer(var, callback_timer, timer_fieldname) \ - container_of(callback_timer, typeof(*var), timer_fieldname) - - -#define le32_to_cpu(x) (x) -#define le16_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define cpu_to_le32(x) (x) -#define lower_32_bits(n) ((rt_uint32_t)((n) & 0xffffffff)) -#define upper_32_bits(n) ((rt_uint32_t)(((n) >> 16) >> 16)) - -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -#define do_div(n, base) ({ \ - uint32_t __base = (base); \ - uint32_t __rem; \ - __rem = ((uint64_t)(n)) % __base; \ - (n) = ((uint64_t)(n)) / __base; \ - __rem; \ -}) - -#define fallthrough \ - do { \ - } while (0) - -int regulator_is_supported_voltage(struct regulator *regulator, - int min_uV, int max_uV); -int regulator_enable(struct regulator *regulator); -rt_bool_t mmc_can_gpio_cd(struct mmc_host *host); - -struct regulator -{ - const char *supply_name; -}; - -int regulator_get_current_limit(struct regulator *regulator); - -int regulator_enable(struct regulator *regulator); - -void regulator_disable(struct regulator *regulator); - -#endif diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci-platform/sdhci-platform.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci-platform/sdhci-platform.c deleted file mode 100644 index 4272b24dea..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci-platform/sdhci-platform.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#include "sdhci-platform.h" - -static const struct sdhci_ops sdhci_pltfm_ops = { - .set_clock = sdhci_set_clock, - .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, -}; - -void sdhci_get_property(struct rt_platform_device *pdev) -{ - struct rt_device *dev = &pdev->parent; - struct sdhci_host *host = pdev->priv; - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - rt_uint32_t bus_width; - - if (rt_dm_dev_prop_read_bool(dev, "sdhci,auto-cmd12")) - host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - - if (rt_dm_dev_prop_read_bool(dev, "sdhci,1-bit-only") || (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) == 0 && bus_width == 1)) - host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; - - if (rt_dm_dev_prop_read_bool(dev, "broken-cd")) - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - - if (rt_dm_dev_prop_read_bool(dev, "no-1-8-v")) - host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; - - rt_dm_dev_prop_read_u32(dev, "clock-frequency", &pltfm_host->clock); - - if (rt_dm_dev_prop_read_bool(dev, "keep-power-in-suspend")) - host->mmc->pm_caps |= MMC_PM_KEEP_POWER; - - if (rt_dm_dev_prop_read_bool(dev, "wakeup-source") || rt_dm_dev_prop_read_bool(dev, "enable-sdio-wakeup")) /* legacy */ - host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; -} - -struct sdhci_host *sdhci_pltfm_init(struct rt_platform_device *pdev, - const struct sdhci_pltfm_data *pdata, - size_t priv_size) -{ - struct sdhci_host *host; - struct rt_device *dev = &pdev->parent; - void *ioaddr; - int irq; - - ioaddr = rt_dm_dev_iomap(dev, 0); - if (!ioaddr) - { - return RT_NULL; - } - - irq = rt_dm_dev_get_irq(dev, 0); - if (irq < 0) - { - return RT_NULL; - } - host = sdhci_alloc_host(dev, priv_size); - if (!host) - { - return RT_NULL; - } - host->irq = irq; - host->ioaddr = ioaddr; - host->hw_name = rt_dm_dev_get_name(dev); - - if (pdata && pdata->ops) - host->ops = pdata->ops; - else - host->ops = &sdhci_pltfm_ops; - if (pdata) - { - host->quirks = pdata->quirks; - host->quirks2 = pdata->quirks2; - } - - pdev->priv = host; - - return host; -} - -int sdhci_pltfm_init_and_add_host(struct rt_platform_device *pdev, - const struct sdhci_pltfm_data *pdata, - size_t priv_size) -{ - struct sdhci_host *host; - int ret = 0; - - host = sdhci_pltfm_init(pdev, pdata, priv_size); - if (!host) - return -RT_ERROR; - - sdhci_get_property(pdev); - - ret = sdhci_add_host(host); - if (ret) - sdhci_pltfm_free(pdev); - - return ret; -} - -void sdhci_pltfm_free(struct rt_platform_device *pdev) -{ - struct sdhci_host *host = pdev->priv; - - sdhci_free_host(host); -} - -void sdhci_pltfm_remove(struct rt_platform_device *pdev) -{ - struct sdhci_host *host = pdev->priv; - int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - - sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci.c deleted file mode 100644 index 7d5d85f50f..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/sdhci.c +++ /dev/null @@ -1,3606 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ - -#include -#include "sdhci.h" -#include -#define DBG_TAG "SDHCI" -#ifdef DRV_DEBUG -#define DBG_LVL DBG_LOG -#else -#define DBG_LVL DBG_INFO -#endif /* DRV_DEBUG */ -#include -static unsigned int debug_quirks = 0; -static unsigned int debug_quirks2; -/********************************************************* */ -/* cmd */ -/********************************************************* */ - - -void read_reg(struct sdhci_host *host) -{ - rt_kprintf("0x00 addddddddddddd = %x \n", sdhci_readl(host, 0x00)); - rt_kprintf("0x04 EMMC_BLOCKSIZE = %x \n", sdhci_readw(host, 0x04)); - rt_kprintf("0x06 EMMC_BLOCKCOUNT = %x \n", sdhci_readw(host, 0x06)); - rt_kprintf("0x08 SDHCI_ARGUMENT = %x \n", sdhci_readl(host, 0x08)); - rt_kprintf("0x0c EMMC_XFER_MODE = %x \n", sdhci_readw(host, 0x0c)); - rt_kprintf("0x0e SDHCI_COMMAND = %x \n", sdhci_readw(host, 0x0e)); - rt_kprintf("0x24 SDHCI_PRESENT_STATE = %x \n", sdhci_readl(host, 0x24)); - rt_kprintf("0x28 SDHCI_HOST_CONTROL = %x \n", sdhci_readb(host, 0x28)); - rt_kprintf("0x29 SDHCI_POWER_CONTROL = %x \n", sdhci_readb(host, 0x29)); - rt_kprintf("0x2a EMMC_BGAP_CTRL = %x \n", sdhci_readb(host, 0x2a)); - rt_kprintf("0x2c EMMC_CLK_CTRL = %x \n", sdhci_readw(host, 0x2c)); - rt_kprintf("0x2e EMMC_TOUT_CTRL = %x \n", sdhci_readb(host, 0x2e)); - rt_kprintf("0x2f EMMC_SW_RST = %x \n", sdhci_readb(host, 0x2f)); - rt_kprintf("0x30 SDHCI_INT_STATUS = %x \n", sdhci_readw(host, 0x30)); - rt_kprintf("0x32 SDHCI_ERR_INT_STATUS = %x \n", sdhci_readw(host, 0x32)); - rt_kprintf("0x34 SDHCI_INT_ENABLE = %x \n", sdhci_readw(host, 0x34)); - rt_kprintf("0x36 EMMC ERROR INT STATEN = %x \n", sdhci_readw(host, 0x36)); - rt_kprintf("0x38 EMMC NORMAL INT SIGNAL EN= %x \n", sdhci_readw(host, 0x38)); - rt_kprintf("0x3a EMMC ERROR INT SIGNAL EN = %x \n", sdhci_readw(host, 0x3a)); - rt_kprintf("0x3c EMMC_AUTO_CMD_STAT = %x \n", sdhci_readw(host, 0x3c)); - rt_kprintf("0x3e EMMC_HOST_CTRL2 = %x \n", sdhci_readw(host, 0x3e)); - rt_kprintf("0x40 EMMC_CAPABILITIES1 = %x \n", sdhci_readl(host, 0x40)); - rt_kprintf("0x44 EMMC_CAPABILITIES2 = %x \n", sdhci_readl(host, 0x44)); - rt_kprintf("0x52 EMMC_FORC_ERR_INT_STAT = %x \n", sdhci_readw(host, 0x52)); - rt_kprintf("0x54 EMMC_ADMA_ERR_STAT = %x \n", sdhci_readb(host, 0x54)); - rt_kprintf("0x58 EMMC_ADMA_SA = %x \n", sdhci_readl(host, 0x58)); - rt_kprintf("0x66 EMMC_PRESET_SDR12 = %x \n", sdhci_readw(host, 0x66)); - rt_kprintf("0x68 EMMC_PRESET_SDR25 = %x \n", sdhci_readw(host, 0x68)); - rt_kprintf("0x6a EMMC_PRESET_SDR50 = %x \n", sdhci_readw(host, 0x6a)); - rt_kprintf("0x6c EMMC_PRESET_SDR104 = %x \n", sdhci_readw(host, 0x6c)); - rt_kprintf("0x6e EMMC_PRESET_DDR50 = %x \n", sdhci_readw(host, 0x6e)); - rt_kprintf("0x78 EMMC_ADMA_ID = %x \n", sdhci_readl(host, 0x78)); - rt_kprintf("0xfe EMMC_HOST_CNTRL_VERS = %x \n", sdhci_readw(host, 0xfe)); - -} -static inline rt_bool_t sdhci_has_requests(struct sdhci_host *host) -{ - return host->cmd || host->data_cmd; -} - -static inline rt_bool_t sdhci_auto_cmd23(struct sdhci_host *host, - struct rt_mmcsd_req *mrq) -{ - return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23); -} - -static inline rt_bool_t sdhci_auto_cmd12(struct sdhci_host *host, - struct rt_mmcsd_req *mrq) -{ - return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) && !mrq->cap_cmd_during_tfr; -} - -static inline rt_bool_t sdhci_manual_cmd23(struct sdhci_host *host, - struct rt_mmcsd_req *mrq) -{ - return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23); -} - -static inline rt_bool_t sdhci_data_line_cmd(struct rt_mmcsd_cmd *cmd) -{ - return cmd->data || cmd->flags & MMC_RSP_BUSY; -} - -void sdhci_set_data_timeout_irq(struct sdhci_host *host, rt_bool_t enable) -{ - if (enable) - host->ier |= SDHCI_INT_DATA_TIMEOUT; - else - host->ier &= ~SDHCI_INT_DATA_TIMEOUT; - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -} - -void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) -{ - rt_uint16_t ctrl_2; - - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - /* Select Bus Speed Mode for host */ - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - if ((timing == MMC_TIMING_MMC_HS200) || (timing == MMC_TIMING_UHS_SDR104)) - ctrl_2 |= SDHCI_CTRL_UHS_SDR104; - else if (timing == MMC_TIMING_UHS_SDR12) - ctrl_2 |= SDHCI_CTRL_UHS_SDR12; - else if (timing == MMC_TIMING_UHS_SDR25) - ctrl_2 |= SDHCI_CTRL_UHS_SDR25; - else if (timing == MMC_TIMING_UHS_SDR50) - ctrl_2 |= SDHCI_CTRL_UHS_SDR50; - else if ((timing == MMC_TIMING_UHS_DDR50) || (timing == MMC_TIMING_MMC_DDR52)) - ctrl_2 |= SDHCI_CTRL_UHS_DDR50; - else if (timing == MMC_TIMING_MMC_HS400) - ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */ - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -} - -void sdhci_set_bus_width(struct sdhci_host *host, int width) -{ - rt_uint8_t ctrl; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - if (width == MMC_BUS_WIDTH_8) - { - ctrl &= ~SDHCI_CTRL_4BITBUS; - ctrl |= SDHCI_CTRL_8BITBUS; - } - else - { - if (host->mmc->caps & MMC_CAP_8_BIT_DATA) - ctrl &= ~SDHCI_CTRL_8BITBUS; - if (width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; - } - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} - -static inline rt_bool_t sdhci_can_64bit_dma(struct sdhci_host *host) -{ - /* - * According to SD Host Controller spec v4.10, bit[27] added from - * version 4.10 in Capabilities Register is used as 64-bit System - * Address support for V4 mode. - */ - if (host->version >= SDHCI_SPEC_410 && host->v4_mode) - return host->caps & SDHCI_CAN_64BIT_V4; - - return host->caps & SDHCI_CAN_64BIT; -} - -static void sdhci_do_enable_v4_mode(struct sdhci_host *host) -{ - rt_uint16_t ctrl2; - - ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ctrl2 & SDHCI_CTRL_V4_MODE) - return; - - ctrl2 |= SDHCI_CTRL_V4_MODE; - sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); -} - -void sdhci_cleanup_host(struct sdhci_host *host) -{ - struct mmc_host *mmc = host->mmc; - - if (host->sdhci_core_to_disable_vqmmc) - regulator_disable(mmc->supply.vqmmc); - - if (host->align_buffer) - dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + host->adma_table_sz, host->align_buffer, - host->align_addr); - - host->adma_table = NULL; - host->align_buffer = NULL; -} - -static void sdhci_set_default_irqs(struct sdhci_host *host) -{ - host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; - - if (host->tuning_mode == SDHCI_TUNING_MODE_2 || host->tuning_mode == SDHCI_TUNING_MODE_3) - host->ier |= SDHCI_INT_RETUNE; - - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -} - - -static inline void sdhci_auto_cmd_select(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd, - rt_uint16_t *mode) -{ - rt_bool_t use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) && (cmd->cmd_code != SD_IO_RW_EXTENDED); - rt_bool_t use_cmd23 = sdhci_auto_cmd23(host, cmd->mrq); - rt_uint16_t ctrl2; - - /* - * In case of Version 4.10 or later, use of 'Auto CMD Auto - * Select' is recommended rather than use of 'Auto CMD12 - * Enable' or 'Auto CMD23 Enable'. We require Version 4 Mode - * here because some controllers (e.g sdhci-of-dwmshc) expect it. - */ - if (host->version >= SDHCI_SPEC_410 && host->v4_mode && (use_cmd12 || use_cmd23)) - { - *mode |= SDHCI_TRNS_AUTO_SEL; - - ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (use_cmd23) - ctrl2 |= SDHCI_CMD23_ENABLE; - else - ctrl2 &= ~SDHCI_CMD23_ENABLE; - sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); - - return; - } - - /* - * If we are sending CMD23, CMD12 never gets sent - * on successful completion (so no Auto-CMD12). - */ - if (use_cmd12) - *mode |= SDHCI_TRNS_AUTO_CMD12; - else if (use_cmd23) - *mode |= SDHCI_TRNS_AUTO_CMD23; -} - - -static rt_bool_t sdhci_present_error(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd, rt_bool_t present) -{ - if (!present || host->flags & SDHCI_DEVICE_DEAD) - { - cmd->err = -ENOMEDIUM; - return RT_TRUE; - } - - return RT_FALSE; -} - -static rt_uint16_t sdhci_get_preset_value(struct sdhci_host *host) -{ - rt_uint16_t preset = 0; - - switch (host->timing) - { - case MMC_TIMING_MMC_HS: - case MMC_TIMING_SD_HS: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED); - break; - case MMC_TIMING_UHS_SDR12: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); - break; - case MMC_TIMING_UHS_SDR25: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25); - break; - case MMC_TIMING_UHS_SDR50: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50); - break; - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_MMC_HS200: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); - break; - case MMC_TIMING_UHS_DDR50: - case MMC_TIMING_MMC_DDR52: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); - break; - case MMC_TIMING_MMC_HS400: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400); - break; - default: - preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12); - break; - } - return preset; -} - -static void sdhci_set_card_detection(struct sdhci_host *host, rt_bool_t enable) -{ - rt_uint32_t present; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || !mmc_card_is_removable(host->mmc)) - return; - - if (enable) - { - present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; - - host->ier |= present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; - } - else - { - host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); - } - - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -} - -static void sdhci_enable_card_detection(struct sdhci_host *host) -{ - sdhci_set_card_detection(host, RT_TRUE); -} - -static inline int sdhci_external_dma_init(struct sdhci_host *host) -{ - return -EOPNOTSUPP; -} - -static inline void sdhci_external_dma_release(struct sdhci_host *host) -{ -} - -static inline void sdhci_external_dma_prepare_data(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd) -{ - /* This should never happen */ -} - -static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd) -{ -} - -static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host, - struct rt_mmcsd_data *data) -{ - return NULL; -} - -/********************************************************* */ -/* reset */ -/********************************************************* */ -enum sdhci_reset_reason -{ - SDHCI_RESET_FOR_INIT, - SDHCI_RESET_FOR_REQUEST_ERROR, - SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY, - SDHCI_RESET_FOR_TUNING_ABORT, - SDHCI_RESET_FOR_CARD_REMOVED, - SDHCI_RESET_FOR_CQE_RECOVERY, -}; - -static rt_bool_t sdhci_needs_reset(struct sdhci_host *host, struct rt_mmcsd_req *mrq) -{ - return (!(host->flags & SDHCI_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->err) || (mrq->sbc && mrq->sbc->err) || (mrq->data && mrq->data->stop && mrq->data->stop->err) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); -} - -static rt_bool_t sdhci_do_reset(struct sdhci_host *host, rt_uint8_t mask) -{ - if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) - { - struct mmc_host *mmc = host->mmc; - - if (!mmc->ops->get_cd(mmc)) - return RT_FALSE; - } - if (host->ops->reset) - { - host->ops->reset(host, mask); - } - return RT_TRUE; -} - -static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason) -{ - if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) - { - sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - return; - } - - switch (reason) - { - case SDHCI_RESET_FOR_INIT: - sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - break; - case SDHCI_RESET_FOR_REQUEST_ERROR: - case SDHCI_RESET_FOR_TUNING_ABORT: - case SDHCI_RESET_FOR_CARD_REMOVED: - case SDHCI_RESET_FOR_CQE_RECOVERY: - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - break; - case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY: - sdhci_do_reset(host, SDHCI_RESET_DATA); - break; - } -} - -#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r) - -static void sdhci_reset_for_all(struct sdhci_host *host) -{ - if (sdhci_do_reset(host, SDHCI_RESET_ALL)) - { - if (host->flags & (SDHCI_USE_SDMA)) - { - if (host->ops->enable_dma) - host->ops->enable_dma(host); - } - /* Resetting the controller clears many */ - host->preset_enabled = RT_FALSE; - } -} - - -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) -{ - if (host->bus_on) - return; - host->bus_on = RT_TRUE; -} - -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) -{ - if (!host->bus_on) - return; - host->bus_on = RT_FALSE; -} - -void sdhci_reset(struct sdhci_host *host, rt_uint8_t mask) -{ - ssize_t timeout; - - sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); - - if (mask & SDHCI_RESET_ALL) - { - host->clock = 0; - /* Reset-all turns off SD Bus Power */ - if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) - sdhci_runtime_pm_bus_off(host); - } - - timeout = rt_tick_from_millisecond(150); - while (1) - { - timeout = timeout - rt_tick_get(); - - - if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)) - break; - if (timeout < 0) - { - rt_kprintf("%s: Reset 0x%x never completed.\n", - mmc_hostname(host->mmc), (int)mask); - sdhci_dumpregs(host); - return; - } - rt_hw_us_delay(10); - } -} - -/********************************************************* */ -/* data */ -/********************************************************* */ -static void sdhci_initialize_data(struct sdhci_host *host, - struct rt_mmcsd_data *data) -{ - /* Sanity checks */ - LOG_D(data->blksize * data->blks > 524288); - LOG_D(data->blksize > host->mmc->max_blk_size); - LOG_D(data->blks > 65535); - - host->data = data; - host->data_early = 0; - host->data->bytes_xfered = 0; -} - -static rt_ubase_t sdhci_sdma_address(struct sdhci_host *host) -{ - return (rt_ubase_t)rt_kmem_v2p(host->data->buf); -} - -static void sdhci_set_adma_addr(struct sdhci_host *host, rt_uint32_t addr) -{ - sdhci_writel(host, lower_32_bits(addr), SDHCI_ADMA_ADDRESS); - if (host->flags & SDHCI_USE_64_BIT_DMA) - sdhci_writel(host, upper_32_bits(addr), SDHCI_ADMA_ADDRESS_HI); -} - -static void sdhci_set_sdma_addr(struct sdhci_host *host, rt_uint32_t addr) -{ - if (host->v4_mode) - sdhci_set_adma_addr(host, addr); - else - sdhci_writel(host, addr, SDHCI_DMA_ADDRESS); -} - -static void sdhci_config_dma(struct sdhci_host *host) -{ - rt_uint8_t ctrl; - rt_uint16_t ctrl2; - - if (host->version < SDHCI_SPEC_200) - return; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - /* - * Always adjust the DMA selection as some controllers - * (e.g. JMicron) can't do PIO properly when the selection - * is ADMA. - */ - ctrl &= ~SDHCI_CTRL_DMA_MASK; - if (!(host->flags & SDHCI_REQ_USE_DMA)) - goto out; - - /* Note if DMA Select is zero then SDMA is selected */ - if (host->flags & SDHCI_USE_64_BIT_DMA) - { - /* - * If v4 mode, all supported DMA can be 64-bit addressing if - * controller supports 64-bit system address, otherwise only - * ADMA can support 64-bit addressing. - */ - if (host->v4_mode) - { - ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl2 |= SDHCI_CTRL_64BIT_ADDR; - sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); - } - } - -out: - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} - -static inline void sdhci_set_block_info(struct sdhci_host *host, - struct rt_mmcsd_data *data) -{ - /* Set the DMA boundary value and block size */ - sdhci_writew(host, - SDHCI_MAKE_BLKSZ(7, data->blksize), - SDHCI_BLOCK_SIZE); - /* - * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count - * can be supported, in that case 16-bit block count register must be 0. - */ - if (host->version >= SDHCI_SPEC_410 && host->v4_mode && (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) - { - if (sdhci_readw(host, SDHCI_BLOCK_COUNT)) - sdhci_writew(host, 0, SDHCI_BLOCK_COUNT); - sdhci_writew(host, data->blks, SDHCI_32BIT_BLK_CNT); - } - else - { - sdhci_writew(host, data->blks, SDHCI_BLOCK_COUNT); - } -} - -static void sdhci_set_transfer_irqs(struct sdhci_host *host) -{ - rt_uint32_t pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; - rt_uint32_t dma_irqs = SDHCI_INT_DMA_END; - - if (host->flags & SDHCI_REQ_USE_DMA) - host->ier = (host->ier & ~pio_irqs) | dma_irqs; - else - host->ier = (host->ier & ~dma_irqs) | pio_irqs; - - if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12)) - host->ier |= SDHCI_INT_AUTO_CMD_ERR; - else - host->ier &= ~SDHCI_INT_AUTO_CMD_ERR; - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -} - -static void sdhci_prepare_data(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd) -{ - struct rt_mmcsd_data *data = cmd->data; - - sdhci_initialize_data(host, data); - - if (host->flags & SDHCI_USE_SDMA) - { - unsigned int length_mask, offset_mask; - - host->flags |= SDHCI_REQ_USE_DMA; - - /* - * FIXME: This doesn't account for merging when mapping the - * scatterlist. - * - * The assumption here being that alignment and lengths are - * the same after DMA mapping to device address space. - */ - length_mask = 0; - offset_mask = 0; - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) - length_mask = 3; - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) - offset_mask = 3; - - - if (length_mask | offset_mask) - { - host->flags &= ~SDHCI_REQ_USE_DMA; - } - } - - sdhci_config_dma(host); - - if (host->flags & SDHCI_REQ_USE_DMA) - { - if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) - rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf, data->blks * data->blksize); - else - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data->buf, data->blks * data->blksize); - - sdhci_set_sdma_addr(host, sdhci_sdma_address(host)); - } - - if (!(host->flags & SDHCI_REQ_USE_DMA)) - { - host->blocks = data->blks; - } - - sdhci_set_transfer_irqs(host); - - sdhci_set_block_info(host, data); -} - -static void sdhci_set_mrq_done(struct sdhci_host *host, struct rt_mmcsd_req *mrq) -{ - int i; - - for (i = 0; i < SDHCI_MAX_MRQS; i++) - { - if (host->mrqs_done[i] == mrq) - { - LOG_D(1); - return; - } - } - - for (i = 0; i < SDHCI_MAX_MRQS; i++) - { - if (!host->mrqs_done[i]) - { - host->mrqs_done[i] = mrq; - break; - } - } - - LOG_D(i >= SDHCI_MAX_MRQS); -} - -static inline rt_bool_t sdhci_defer_done(struct sdhci_host *host, - struct rt_mmcsd_req *mrq) -{ - struct rt_mmcsd_data *data = mrq->data; - - return host->pending_reset || host->always_defer_done || ((host->flags & SDHCI_REQ_USE_DMA) && data && data->host_cookie == COOKIE_MAPPED); -} - - -/********************************************************* */ -/* pio */ -/********************************************************* */ - -static void sdhci_read_block_pio(struct sdhci_host *host,void **buf) -{ - rt_uint32_t scratch; - size_t len; - rt_uint32_t blksize = host->data->blksize; - while (blksize) - { - len = min(4U, blksize); - - scratch = sdhci_readl(host, SDHCI_BUFFER); - rt_memcpy(*buf, &scratch, len); - - *buf += len; - blksize -= len; - } -} - -static void sdhci_write_block_pio(struct sdhci_host *host,void **buf) -{ - size_t blksize, len; - rt_uint32_t scratch; - LOG_D("PIO writing\n"); - - blksize = host->data->blksize; - scratch = 0; - while (blksize) - { - len = min(4U, blksize); - rt_memcpy(&scratch, *buf, len); - *buf += len; - blksize -= len; - sdhci_writel(host, scratch, SDHCI_BUFFER); - } -} - -static void sdhci_transfer_pio(struct sdhci_host *host) -{ - rt_uint32_t mask; - - if (host->blocks == 0) - return; - - if (host->data->flags & DATA_DIR_READ) - mask = SDHCI_DATA_AVAILABLE; - else - mask = SDHCI_SPACE_AVAILABLE; - - /* - * Some controllers (JMicron JMB38x) mess up the buffer bits - * for transfers < 4 bytes. As long as it is just one block, - * we can ignore the bits. - */ - if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) && (host->data->blks == 1)) - { - mask = ~0; - } - void *buf = (void *)host->data->buf; - while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) - { - if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY) - rt_hw_us_delay(100); - - if (host->data->flags & DATA_DIR_READ) - sdhci_read_block_pio(host,&buf); - else - sdhci_write_block_pio(host,&buf); - - host->data->blks--; - if (host->data->blks == 0) - break; - - /* host->data->buf += host->data->blksize;*/ - } -} - -/********************************************************* */ -/* config */ -/********************************************************* */ - - -static rt_bool_t sdhci_timing_has_preset(unsigned char timing) -{ - switch (timing) - { - case MMC_TIMING_UHS_SDR12: - case MMC_TIMING_UHS_SDR25: - case MMC_TIMING_UHS_SDR50: - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_UHS_DDR50: - case MMC_TIMING_MMC_DDR52: - return RT_TRUE; - } - return RT_FALSE; -} - -static rt_bool_t sdhci_preset_needed(struct sdhci_host *host, unsigned char timing) -{ - return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) && sdhci_timing_has_preset(timing); -} - -static rt_bool_t sdhci_presetable_values_change(struct sdhci_host *host, struct rt_mmcsd_io_cfg *ios) -{ - /* - * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK - * Frequency. Check if preset values need to be enabled, or the Driver - * Strength needs updating. Note, clock changes are handled separately. - */ - return !host->preset_enabled && (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type); -} - - -static void sdhci_enable_preset_value(struct sdhci_host *host, rt_bool_t enable) -{ - /* Host Controller v3.00 defines preset value registers */ - if (host->version < SDHCI_SPEC_300) - return; - - /* - * We only enable or disable Preset Value if they are not already - * enabled or disabled respectively. Otherwise, we bail out. - */ - if (host->preset_enabled != enable) - { - rt_uint16_t ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - if (enable) - ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; - else - ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; - - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - if (enable) - host->flags |= SDHCI_PV_ENABLED; - else - host->flags &= ~SDHCI_PV_ENABLED; - - host->preset_enabled = enable; - } -} - -static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode, - unsigned short vdd) -{ - struct mmc_host *mmc = host->mmc; - - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); - - if (mode != MMC_POWER_OFF) - sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL); - else - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); -} - -void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, - unsigned short vdd) -{ - rt_uint8_t pwr = 0; - - if (mode != MMC_POWER_OFF) - { - switch (1 << vdd) - { - case MMC_VDD_165_195: - /* - * Without a regulator, SDHCI does not support 2.0v - * so we only get here if the driver deliberately - * added the 2.0v range to ocr_avail. Map it to 1.8v - * for the purpose of turning on the power. - */ - case MMC_VDD_20_21: - pwr = SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - pwr = SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - /* - * 3.4 ~ 3.6V are valid only for those platforms where it's - * known that the voltage range is supported by hardware. - */ - case MMC_VDD_34_35: - case MMC_VDD_35_36: - pwr = SDHCI_POWER_330; - break; - default: - break; - } - } - - if (host->pwr == pwr) - return; - - host->pwr = pwr; - - if (pwr == 0) - { - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) - sdhci_runtime_pm_bus_off(host); - } - else - { - /* - * Spec says that we should clear the power reg before setting - * a new value. Some controllers don't seem to like this though. - */ - if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - - /* - * At least the Marvell CaFe chip gets confused if we set the - * voltage and set turn on power at the same time, so set the - * voltage first. - */ - if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - pwr |= SDHCI_POWER_ON; - - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - - if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON) - sdhci_runtime_pm_bus_on(host); - - /* - * Some controllers need an extra 10ms delay of 10ms before - * they can apply clock after applying power - */ - if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) - rt_thread_mdelay(10); - } -} - -void sdhci_set_power(struct sdhci_host *host, unsigned char mode, - unsigned short vdd) -{ - if (!host->mmc->supply.vmmc) - sdhci_set_power_noreg(host, mode, vdd); - else - sdhci_set_power_reg(host, mode, vdd); -} - - -int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct rt_mmcsd_io_cfg *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_uint16_t ctrl; - int ret; - - /* - * Signal Voltage Switching is only applicable for Host Controllers - * v3.00 and above. - */ - if (host->version < SDHCI_SPEC_300) - return 0; - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - switch (ios->signal_voltage) - { - case MMC_SIGNAL_VOLTAGE_330: - if (!(host->flags & SDHCI_SIGNALING_330)) - return -EINVAL; - /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ - ctrl &= ~SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - if (!mmc->supply.vqmmc) - { - ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret < 0) - { - return -EIO; - } - } - /* Wait for 5ms */ - rt_thread_mdelay(5); - /* 3.3V regulator output should be stable within 5 ms */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_VDD_180)) - return 0; - return -EAGAIN; - case MMC_SIGNAL_VOLTAGE_180: - if (!(host->flags & SDHCI_SIGNALING_180)) - return -EINVAL; - if (!mmc->supply.vqmmc) - { - ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret < 0) - { - LOG_D("%s: Switching to 1.8V signalling voltage failed\n", - mmc_hostname(mmc)); - return -EIO; - } - } - - /* - * Enable 1.8V Signal Enable in the Host Control2 - * register - */ - ctrl |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* Some controller need to do more when switching */ - if (host->ops->voltage_switch) - host->ops->voltage_switch(host); - - /* 1.8V regulator output should be stable within 5 ms */ - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (ctrl & SDHCI_CTRL_VDD_180) - return 0; - - LOG_D("%s: 1.8V regulator output did not become stable\n", - mmc_hostname(mmc)); - - return -EAGAIN; - case MMC_SIGNAL_VOLTAGE_120: - if (!(host->flags & SDHCI_SIGNALING_120)) - return -EINVAL; - if (!mmc->supply.vqmmc) - { - ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret < 0) - { - LOG_D("%s: Switching to 1.2V signalling voltage failed\n", - mmc_hostname(mmc)); - return -EIO; - } - } - return 0; - default: - /* No signal voltage switch required */ - return 0; - } -} - - -static int sdhci_get_cd(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - int gpio_cd = mmc_gpio_get_cd(mmc); - - if (host->flags & SDHCI_DEVICE_DEAD) - return 0; - - /* If nonremovable, assume that the card is always present. */ - if (!mmc_card_is_removable(mmc)) - return 1; - - /* - * Try slot gpio detect, if defined it take precedence - * over build in controller functionality - */ - if (gpio_cd >= 0) - return !!gpio_cd; - - /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - return 1; - - /* Host native card detect */ - return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); -} - -static int sdhci_check_ro(struct sdhci_host *host) -{ - int is_readonly; - rt_base_t flags; - flags = rt_spin_lock_irqsave(&host->lock); - - if (host->flags & SDHCI_DEVICE_DEAD) - is_readonly = 0; - else if (host->ops->get_ro) - is_readonly = host->ops->get_ro(host); - else if (mmc_can_gpio_ro(host->mmc)) - is_readonly = mmc_gpio_get_ro(host->mmc); - else - is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) - & SDHCI_WRITE_PROTECT); - - rt_spin_unlock_irqrestore(&host->lock, flags); - - /* This quirk needs to be replaced by a callback-function later */ - return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? !is_readonly : is_readonly; -} - -#define SAMPLE_COUNT 5 -static int sdhci_get_ro(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - int i, ro_count; - - if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) - return sdhci_check_ro(host); - - ro_count = 0; - for (i = 0; i < SAMPLE_COUNT; i++) - { - if (sdhci_check_ro(host)) - { - if (++ro_count > SAMPLE_COUNT / 2) - return 1; - } - rt_thread_mdelay(30); - } - return 0; -} - -static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) -{ - if (!(host->flags & SDHCI_DEVICE_DEAD)) - { - if (enable) - host->ier |= SDHCI_INT_CARD_INT; - else - host->ier &= ~SDHCI_INT_CARD_INT; - - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - } -} - -static void sdhci_ack_sdio_irq(struct mmc_host *mmc) -{ - rt_base_t flags; - struct sdhci_host *host = mmc_priv(mmc); - flags = rt_spin_lock_irqsave(&host->lock); - sdhci_enable_sdio_irq_nolock(host, RT_TRUE); - rt_spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_del_timer(struct sdhci_host *host, struct rt_mmcsd_req *mrq) -{ - if (sdhci_data_line_cmd(mrq->cmd)) - rt_timer_stop(&host->data_timer); - else - rt_timer_stop(&host->timer); -} - -static unsigned int sdhci_target_timeout(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd, - struct rt_mmcsd_data *data) -{ - unsigned int target_timeout; - - /* timeout in us */ - if (!data) - { - target_timeout = cmd->busy_timeout * 1000; - } - else - { - target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); - if (host->clock && data->timeout_clks) - { - rt_uint32_t val; - - /* - * data->timeout_clks is in units of clock cycles. - * host->clock is in Hz. target_timeout is in us. - * Hence, us = 1000000 * cycles / Hz. Round up. - */ - val = 1000000ULL * data->timeout_clks; - if (do_div(val, host->clock)) - target_timeout++; - target_timeout += val; - } - } - - return target_timeout; -} - -static rt_uint8_t sdhci_calc_timeout(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd, - rt_bool_t *too_big) -{ - rt_uint8_t count; - struct rt_mmcsd_data *data; - unsigned target_timeout, current_timeout; - - *too_big = RT_FALSE; - - /* - * If the host controller provides us with an incorrect timeout - * value, just skip the check and use the maximum. The hardware may take - * longer to time out, but that's much better than having a too-short - * timeout value. - */ - if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) - return host->max_timeout_count; - - /* Unspecified command, assume max */ - if (cmd == NULL) - return host->max_timeout_count; - - data = cmd->data; - /* Unspecified timeout, assume max */ - if (!data && !cmd->busy_timeout) - return host->max_timeout_count; - - /* timeout in us */ - target_timeout = sdhci_target_timeout(host, cmd, data); - - /* - * Figure out needed cycles. - * We do this in steps in order to fit inside a 32 bit int. - * The first step is the minimum timeout, which will have a - * minimum resolution of 6 bits: - * (1) 2^13*1000 > 2^22, - * (2) host->timeout_clk < 2^16 - * => - * (1) / (2) > 2^6 - */ - count = 0; - current_timeout = (1 << 13) * 1000 / host->timeout_clk; - while (current_timeout < target_timeout) - { - count++; - current_timeout <<= 1; - if (count > host->max_timeout_count) - { - if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) - LOG_D("Too large timeout 0x%x requested for CMD%d!\n", - count, cmd->cmd_code); - count = host->max_timeout_count; - *too_big = RT_TRUE; - break; - } - } - - return count; -} - -static void sdhci_calc_sw_timeout(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd) -{ - struct rt_mmcsd_data *data = cmd->data; - struct mmc_host *mmc = host->mmc; - struct rt_mmcsd_io_cfg *ios = &mmc->ios; - unsigned char bus_width = 1 << ios->bus_width; - unsigned int blksz; - unsigned int freq; - rt_uint64_t target_timeout; - rt_uint64_t transfer_time; - - target_timeout = sdhci_target_timeout(host, cmd, data); - target_timeout *= 1000L; - - if (data) - { - blksz = data->blksize; - freq = mmc->actual_clock ?: host->clock; - transfer_time = (rt_uint64_t)blksz * 1000000000L * (8 / bus_width); - do_div(transfer_time, freq); - /* multiply by '2' to account for any unknowns */ - transfer_time = transfer_time * 2; - /* calculate timeout for the entire data */ - host->data_timeout = data->blks * target_timeout + transfer_time; - } - else - { - host->data_timeout = target_timeout; - } - - if (host->data_timeout) - host->data_timeout += MMC_CMD_TRANSFER_TIME; -} - - -void __sdhci_set_timeout(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd) -{ - rt_bool_t too_big = RT_FALSE; - rt_uint8_t count = sdhci_calc_timeout(host, cmd, &too_big); - - if (too_big && host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) - { - sdhci_calc_sw_timeout(host, cmd); - sdhci_set_data_timeout_irq(host, RT_FALSE); - } - else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) - { - sdhci_set_data_timeout_irq(host, RT_FALSE); - } - - sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); -} - -static void sdhci_set_timeout(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd) -{ - if (host->ops->set_timeout) - host->ops->set_timeout(host, cmd); - else - __sdhci_set_timeout(host, cmd); -} - -static void sdhci_mod_timer(struct sdhci_host *host, struct rt_mmcsd_req *mrq, - unsigned long timeout) -{ - if (sdhci_data_line_cmd(mrq->cmd)) - { - rt_tick_t tick = rt_tick_get(); - - if (timeout < tick) - { - timeout = tick; - } - tick = timeout - tick; - - rt_timer_stop(&host->data_timer); - rt_timer_control(&host->data_timer, RT_TIMER_CTRL_SET_TIME, &tick); - rt_timer_start(&host->data_timer); - } - else - { - rt_tick_t tick = rt_tick_get(); - - if (timeout < tick) - { - timeout = tick; - } - tick = timeout - tick; - - rt_timer_stop(&host->timer); - rt_timer_control(&host->timer, RT_TIMER_CTRL_SET_TIME, &tick); - rt_timer_start(&host->timer); - } -} - -static void __sdhci_finish_mrq(struct sdhci_host *host, struct rt_mmcsd_req *mrq) -{ - if (host->cmd && host->cmd->mrq == mrq) - host->cmd = NULL; - - if (host->data_cmd && host->data_cmd->mrq == mrq) - host->data_cmd = NULL; - - if (host->deferred_cmd && host->deferred_cmd->mrq == mrq) - host->deferred_cmd = NULL; - - if (host->data && host->data->mrq == mrq) - host->data = NULL; - - if (sdhci_needs_reset(host, mrq)) - host->pending_reset = RT_TRUE; - - sdhci_set_mrq_done(host, mrq); - - sdhci_del_timer(host, mrq); -} - -static void sdhci_finish_mrq(struct sdhci_host *host, struct rt_mmcsd_req *mrq) -{ - __sdhci_finish_mrq(host, mrq); - - rt_workqueue_submit_work(host->complete_wq, &host->complete_work, 0); -} - -static void sdhci_error_out_mrqs(struct sdhci_host *host, int err) -{ - if (host->data_cmd) - { - host->data_cmd->err = err; - sdhci_finish_mrq(host, host->data_cmd->mrq); - } - - if (host->cmd) - { - host->cmd->err = err; - sdhci_finish_mrq(host, host->cmd->mrq); - } -} - -static void sdhci_card_event(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_uint32_t flags; - int present; - - /* First check if client has provided their own card event */ - if (host->ops->card_event) - host->ops->card_event(host); - - present = mmc->ops->get_cd(mmc); - - flags = rt_spin_lock_irqsave(&host->lock); - - /* Check sdhci_has_requests() first in case we are runtime suspended */ - if (sdhci_has_requests(host) && !present) - { - rt_kprintf("%s: Card removed during transfer!\n", - mmc_hostname(mmc)); - rt_kprintf("%s: Resetting controller.\n", - mmc_hostname(mmc)); - - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - sdhci_error_out_mrqs(host, -ENOMEDIUM); - } - - rt_spin_unlock_irqrestore(&host->lock, flags); -} - -static int sdhci_card_busy(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_uint32_t present_state; - - /* Check whether DAT[0] is 0 */ - present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - - return !(present_state & SDHCI_DATA_0_LVL_MASK); -} - - -static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_uint32_t flags; - - flags = rt_spin_lock_irqsave(&host->lock); - host->flags |= SDHCI_HS400_TUNING; - rt_spin_unlock_irqrestore(&host->lock, flags); - - return 0; -} - - -static void sdhci_set_transfer_mode(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd) -{ - rt_uint16_t mode = 0; - struct rt_mmcsd_data *data = cmd->data; - - if (data == NULL) - { - if (host->quirks2 & SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) - { - /* must not clear SDHCI_TRANSFER_MODE when tuning */ - if (!mmc_op_tuning(cmd->cmd_code)) - sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); - } - else - { - /* clear Auto CMD settings for no data CMDs */ - mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); - sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE); - } - return; - } - - - if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) - mode = SDHCI_TRNS_BLK_CNT_EN; - - if (mmc_op_multi(cmd->cmd_code) || data->blks > 1) - { - mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI; - sdhci_auto_cmd_select(host, cmd, &mode); - if (sdhci_auto_cmd23(host, cmd->mrq)) - sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2); - } - - if (data->flags & DATA_DIR_READ) - mode |= SDHCI_TRNS_READ; - if (host->flags & SDHCI_REQ_USE_DMA) - mode |= SDHCI_TRNS_DMA; - - sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); -} - -static rt_bool_t sdhci_send_command(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd) -{ - int flags; - rt_uint32_t mask; - unsigned long timeout; - /* Initially, a command has no error */ - cmd->err = 0; - - if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && cmd->cmd_code == MMC_STOP_TRANSMISSION) - cmd->flags |= MMC_RSP_BUSY; - - mask = SDHCI_CMD_INHIBIT; - if (sdhci_data_line_cmd(cmd)) - mask |= SDHCI_DATA_INHIBIT; - - /* We shouldn't wait for data inihibit for stop commands, even - though they might use busy signaling */ - if (cmd->mrq->data && (cmd == cmd->mrq->data->stop)) - mask &= ~SDHCI_DATA_INHIBIT; - - if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) - return RT_FALSE; - - host->cmd = cmd; - host->data_timeout = 0; - if (sdhci_data_line_cmd(cmd)) - { - host->data_cmd = cmd; - sdhci_set_timeout(host, cmd); - } - - if (cmd->data) - { - if (host->use_external_dma) - sdhci_external_dma_prepare_data(host, cmd); - else - sdhci_prepare_data(host, cmd); - } - sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); - - sdhci_set_transfer_mode(host, cmd); - - if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) - { - /* - * This does not happen in practice because 136-bit response - * commands never have busy waiting, so rather than complicate - * the error path, just remove busy waiting and continue. - */ - cmd->flags &= ~MMC_RSP_BUSY; - } - - if (!(cmd->flags & MMC_RSP_PRESENT)) - flags = SDHCI_CMD_RESP_NONE; - else if (cmd->flags & MMC_RSP_136) - flags = SDHCI_CMD_RESP_LONG; - else if (cmd->flags & MMC_RSP_BUSY) - flags = SDHCI_CMD_RESP_SHORT_BUSY; - else - flags = SDHCI_CMD_RESP_SHORT; - - if (cmd->flags & MMC_RSP_CRC) - flags |= SDHCI_CMD_CRC; - if (cmd->flags & MMC_RSP_OPCODE) - flags |= SDHCI_CMD_INDEX; - - /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || mmc_op_tuning(cmd->cmd_code)) - flags |= SDHCI_CMD_DATA; - - timeout = rt_tick_get(); - if (host->data_timeout) - timeout += rt_tick_from_millisecond(host->data_timeout * 1000); - else if (!cmd->data && cmd->busy_timeout > 9000) - timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * RT_TICK_PER_SECOND + RT_TICK_PER_SECOND; - else - timeout += 10 * RT_TICK_PER_SECOND; - sdhci_mod_timer(host, cmd->mrq, timeout); - - if (host->use_external_dma) - sdhci_external_dma_pre_transfer(host, cmd); - - sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmd_code, flags), SDHCI_COMMAND); - return RT_TRUE; -} - -/********************************************************* */ -/* dma */ -/********************************************************* */ -static void __sdhci_finish_data(struct sdhci_host *host, rt_bool_t sw_data_timeout) -{ - struct rt_mmcsd_cmd *data_cmd = host->data_cmd; - struct rt_mmcsd_data *data = host->data; - - host->data = NULL; - host->data_cmd = NULL; - - /* - * The controller needs a reset of internal state machines upon error - * conditions. - */ - if (data->err) - { - if (!host->cmd || host->cmd == data_cmd) - sdhci_reset_for(host, REQUEST_ERROR); - else - sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY); - } - - /* - * The specification states that the block count register must - * be updated, but it does not specify at what point in the - * data flow. That makes the register entirely useless to read - * back so we have to assume that nothing made it to the card - * in the event of an error. - */ - if (data->err) - { - data->bytes_xfered = 0; - } - else - { - data->bytes_xfered = data->blksize * data->blks; - } - /* - * Need to send CMD12 if - - * a) open-ended multiblock transfer not using auto CMD12 (no CMD23) - * b) error in multiblock transfer - */ - if (data->stop && ((!data->mrq->sbc && !sdhci_auto_cmd12(host, data->mrq)) || data->err)) - { - /* - * 'cap_cmd_during_tfr' request must not use the command line - * after mmc_command_done() has been called. It is upper layer's - * responsibility to send the stop command if required. - */ - if (data->mrq->cap_cmd_during_tfr) - { - __sdhci_finish_mrq(host, data->mrq); - } - else - { - /* Avoid triggering warning in sdhci_send_command() */ - host->cmd = NULL; - if (!sdhci_send_command(host, data->stop)) - { - if (sw_data_timeout) - { - /* - * This is anyway a sw data timeout, so - * give up now. - */ - data->stop->err = -EIO; - __sdhci_finish_mrq(host, data->mrq); - } - else - { - host->deferred_cmd = data->stop; - } - } - } - } - else - { - __sdhci_finish_mrq(host, data->mrq); - } -} - -static void sdhci_finish_data(struct sdhci_host *host) -{ - __sdhci_finish_data(host, RT_FALSE); -} - - -/********************************************************* */ -/* irq */ -/********************************************************* */ -static void sdhci_data_irq(struct sdhci_host *host, rt_uint32_t intmask) -{ - rt_uint32_t command; - /* - * CMD19 generates _only_ Buffer Read Ready interrupt if - * use sdhci_send_tuning. - * Need to exclude this case: PIO mode and use mmc_send_tuning, - * If not, sdhci_transfer_pio will never be called, make the - * SDHCI_INT_DATA_AVAIL always there, stuck in irq storm. - */ - if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) - { - command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); - if (command == MMC_SEND_TUNING_BLOCK || command == MMC_SEND_TUNING_BLOCK_HS200) - { - host->tuning_done = 1; - rt_wqueue_wakeup(&host->buf_ready_int, 0); - return; - } - } - - if (!host->data) - { - struct rt_mmcsd_cmd *data_cmd = host->data_cmd; - - /* - * The "data complete" interrupt is also used to - * indicate that a busy state has ended. See comment - * above in sdhci_cmd_irq(). - */ - if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) - { - if (intmask & SDHCI_INT_DATA_TIMEOUT) - { - host->data_cmd = NULL; - data_cmd->err = -ETIMEDOUT; - __sdhci_finish_mrq(host, data_cmd->mrq); - return; - } - if (intmask & SDHCI_INT_DATA_END) - { - host->data_cmd = NULL; - /* - * Some cards handle busy-end interrupt - * before the command completed, so make - * sure we do things in the proper order. - */ - if (host->cmd == data_cmd) - return; - - __sdhci_finish_mrq(host, data_cmd->mrq); - return; - } - } - - /* - * SDHCI recovers from errors by resetting the cmd and data - * circuits. Until that is done, there very well might be more - * interrupts, so ignore them in that case. - */ - if (host->pending_reset) - return; - rt_kprintf("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - sdhci_dumpregs(host); - - return; - } - - if (intmask & SDHCI_INT_DATA_TIMEOUT) - host->data->err = -ETIMEDOUT; - else if (intmask & SDHCI_INT_DATA_END_BIT) - host->data->err = -EILSEQ; - else if ((intmask & SDHCI_INT_DATA_CRC) && SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) != MMC_BUS_TEST_R) - { - host->data->err = -EILSEQ; - } - if (host->data->err) - { - sdhci_finish_data(host); - } - else - { - if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) - sdhci_transfer_pio(host); - - /* - * We currently don't do anything fancy with DMA - * boundaries, but as we can't disable the feature - * we need to at least restart the transfer. - * - * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS) - * should return a valid address to continue from, but as - * some controllers are faulty, don't trust them. - */ - if (intmask & SDHCI_INT_DMA_END) - { - rt_uint32_t dmastart, dmanow; - - dmastart = sdhci_sdma_address(host); - dmanow = dmastart + host->data->bytes_xfered; - /* - * Force update to the next DMA block boundary. - */ - dmanow = (dmanow & ~((rt_uint32_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + SDHCI_DEFAULT_BOUNDARY_SIZE; - host->data->bytes_xfered = dmanow - dmastart; - LOG_D("DMA base %pad, transferred 0x%06x bytes, next %pad\n", - &dmastart, host->data->bytes_xfered, &dmanow); - sdhci_set_sdma_addr(host, dmanow); - } - - if (intmask & SDHCI_INT_DATA_END) - { - if (host->cmd == host->data_cmd) - { - /* - * Data managed to finish before the - * command completed. Make sure we do - * things in the proper order. - */ - host->data_early = 1; - } - else - { - sdhci_finish_data(host); - } - } - } -} - -static void sdhci_read_rsp_136(struct sdhci_host *host, struct rt_mmcsd_cmd *cmd) -{ - int i, reg; - - for (i = 0; i < 4; i++) - { - reg = SDHCI_RESPONSE + (3 - i) * 4; - cmd->resp[i] = sdhci_readl(host, reg); - } - - if (host->quirks2 & SDHCI_QUIRK2_RSP_136_HAS_CRC) - return; - - /* CRC is stripped so we need to do some shifting */ - for (i = 0; i < 4; i++) - { - cmd->resp[i] <<= 8; - if (i != 3) - cmd->resp[i] |= cmd->resp[i + 1] >> 24; - } -} - -static void sdhci_finish_command(struct sdhci_host *host) -{ - struct rt_mmcsd_cmd *cmd = host->cmd; - - host->cmd = NULL; - - if (cmd->flags & MMC_RSP_PRESENT) - { - if (cmd->flags & MMC_RSP_136) - { - sdhci_read_rsp_136(host, cmd); - } - else - { - cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); - } - } - /* - * The host can send and interrupt when the busy state has - * ended, allowing us to wait without wasting CPU cycles. - * The busy signal uses DAT0 so this is similar to waiting - * for data to complete. - * - * Note: The 1.0 specification is a bit ambiguous about this - * feature so there might be some problems with older - * controllers. - */ - if (cmd->flags & MMC_RSP_BUSY) - { - if (cmd->data) - { - LOG_D("Cannot wait for busy signal when also doing a data transfer"); - } - else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && cmd == host->data_cmd) - { - /* Command complete before busy is ended */ - return; - } - } - - /* Finished CMD23, now send actual command. */ - if (cmd == cmd->mrq->sbc) - { - if (!sdhci_send_command(host, cmd->mrq->cmd)) - { - host->deferred_cmd = cmd->mrq->cmd; - } - } - else - { - /* Processed actual command. */ - if (host->data && host->data_early) - sdhci_finish_data(host); - - if (!cmd->data) - __sdhci_finish_mrq(host, cmd->mrq); - } -} - - -static void sdhci_cmd_irq(struct sdhci_host *host, rt_uint32_t intmask, rt_uint32_t *intmask_p) -{ - /* Handle auto-CMD12 error */ - if (intmask & SDHCI_INT_AUTO_CMD_ERR && host->data_cmd) - { - struct rt_mmcsd_req *mrq = host->data_cmd->mrq; - rt_uint16_t auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS); - int data_err_bit = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ? SDHCI_INT_DATA_TIMEOUT : SDHCI_INT_DATA_CRC; - - /* Treat auto-CMD12 error the same as data error */ - if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) - { - *intmask_p |= data_err_bit; - return; - } - } - - if (!host->cmd) - { - /* - * SDHCI recovers from errors by resetting the cmd and data - * circuits. Until that is done, there very well might be more - * interrupts, so ignore them in that case. - */ - if (host->pending_reset) - return; - rt_kprintf("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - sdhci_dumpregs(host); - return; - } - if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) - { - if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->err = -ETIMEDOUT; - else - host->cmd->err = -EILSEQ; - - /* Treat data command CRC error the same as data CRC error */ - if (host->cmd->data && (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) == SDHCI_INT_CRC) - { - host->cmd = NULL; - *intmask_p |= SDHCI_INT_DATA_CRC; - return; - } - - __sdhci_finish_mrq(host, host->cmd->mrq); - return; - } - - /* Handle auto-CMD23 error */ - if (intmask & SDHCI_INT_AUTO_CMD_ERR) - { - struct rt_mmcsd_req *mrq = host->cmd->mrq; - rt_uint16_t auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_STATUS); - int err = (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT) ? -ETIMEDOUT : -EILSEQ; - - if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) - { - mrq->sbc->err = err; - __sdhci_finish_mrq(host, mrq); - return; - } - } - - if (intmask & SDHCI_INT_RESPONSE) - sdhci_finish_command(host); -} - -static void sdhci_irq(int irq, void *dev_id) -{ - struct rt_mmcsd_req *mrqs_done[SDHCI_MAX_MRQS] = {0}; - struct sdhci_host *host = dev_id; - rt_uint32_t intmask, mask, unexpected = 0; - int max_loops = 16; - int i, result; - rt_spin_lock(&host->lock); - - if (host->runtime_suspended) - { - rt_spin_unlock(&host->lock); - } - - intmask = sdhci_readl(host, SDHCI_INT_STATUS); - if (!intmask || intmask == 0xffffffff) - { - result = 0; - goto out; - } - - do { - LOG_D("IRQ status 0x%08x\n", intmask); - - if (host->ops->irq) - { - intmask = host->ops->irq(host, intmask); - if (!intmask) - goto cont; - } - - /* Clear selected interrupts. */ - mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | SDHCI_INT_BUS_POWER); - sdhci_writel(host, mask, SDHCI_INT_STATUS); - - if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) - { - rt_uint32_t present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; - - /* - * There is a observation on i.mx esdhc. INSERT - * bit will be immediately set again when it gets - * cleared, if a card is inserted. We have to mask - * the irq to prevent interrupt storm which will - * freeze the system. And the REMOVE gets the - * same situation. - * - * More testing are needed here to ensure it works - * for other platforms though. - */ - host->ier &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); - host->ier |= present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - - sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); - - host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); - result = RT_EOK; - } - - if (intmask & SDHCI_INT_CMD_MASK) - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask); - - if (intmask & SDHCI_INT_DATA_MASK) - sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); - - if (intmask & SDHCI_INT_BUS_POWER) - rt_kprintf("%s: Card is consuming too much power!\n", - mmc_hostname(host->mmc)); - - intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT); - - if (intmask) - { - unexpected |= intmask; - sdhci_writel(host, intmask, SDHCI_INT_STATUS); - } - cont: - intmask = sdhci_readl(host, SDHCI_INT_STATUS); - } while (intmask && --max_loops); - - /* Determine if mrqs can be completed immediately */ - for (i = 0; i < SDHCI_MAX_MRQS; i++) - { - struct rt_mmcsd_req *mrq = host->mrqs_done[i]; - - if (!mrq) - continue; - - if (sdhci_defer_done(host, mrq)) - { - result = RT_EOK; - } - else - { - mrqs_done[i] = mrq; - host->mrqs_done[i] = NULL; - } - } -out: - if (host->deferred_cmd) - result = RT_EOK; - - rt_spin_unlock(&host->lock); - - /* Process mrqs ready for immediate completion */ - for (i = 0; i < SDHCI_MAX_MRQS; i++) - { - if (!mrqs_done[i]) - continue; - - if (host->ops->request_done) - host->ops->request_done(host, mrqs_done[i]); - else - mmc_request_done(host->mmc, mrqs_done[i]); - } - - if (unexpected) - { - sdhci_dumpregs(host); - } - - if (result == RT_EOK) - { - rt_workqueue_submit_work(host->irq_wq, &host->irq_work, 0); - } -} - -static rt_bool_t sdhci_send_command_retry(struct sdhci_host *host, - struct rt_mmcsd_cmd *cmd, - unsigned long flags) -{ - struct rt_mmcsd_cmd *deferred_cmd = host->deferred_cmd; - int timeout = 10; /* Approx. 10 ms */ - rt_bool_t present; - while (!sdhci_send_command(host, cmd)) - { - if (!timeout--) - { - rt_kprintf("%s: Controller never released inhibit bit(s).\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - cmd->err = -EIO; - return RT_FALSE; - } - - rt_spin_unlock_irqrestore(&host->lock, flags); - - rt_thread_mdelay(1); - - present = host->mmc->ops->get_cd(host->mmc); - - flags = rt_spin_lock_irqsave(&host->lock); - - /* A deferred command might disappear, handle that */ - if (cmd == deferred_cmd && cmd != host->deferred_cmd) - return RT_TRUE; - - if (sdhci_present_error(host, cmd, present)) - return RT_FALSE; - } - - if (cmd == host->deferred_cmd) - host->deferred_cmd = NULL; - - return RT_TRUE; -} - -static rt_bool_t sdhci_request_done(struct sdhci_host *host) -{ - rt_base_t flags; - struct rt_mmcsd_req *mrq; - int i; - - flags = rt_spin_lock_irqsave(&host->lock); - - for (i = 0; i < SDHCI_MAX_MRQS; i++) - { - mrq = host->mrqs_done[i]; - if (mrq) - break; - } - - if (!mrq) - { - rt_spin_unlock_irqrestore(&host->lock, flags); - return RT_TRUE; - } - - /* - * The controller needs a reset of internal state machines - * upon error conditions. - */ - if (sdhci_needs_reset(host, mrq)) - { - /* - * Do not finish until command and data lines are available for - * reset. Note there can only be one other mrq, so it cannot - * also be in mrqs_done, otherwise host->cmd and host->data_cmd - * would both be null. - */ - if (host->cmd || host->data_cmd) - { - rt_spin_unlock_irqrestore(&host->lock, flags); - return RT_TRUE; - } - - /* Some controllers need this kick or reset won't work here */ - if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) - /* This is to force an update */ - host->ops->set_clock(host, host->clock); - - sdhci_do_reset(host, SDHCI_RESET_CMD); - sdhci_do_reset(host, SDHCI_RESET_DATA); - - host->pending_reset = RT_FALSE; - } - - /* - * Always unmap the data buffers if they were mapped by - * sdhci_prepare_data() whenever we finish with a request. - * This avoids leaking DMA mappings on error. - */ - if (host->flags & SDHCI_REQ_USE_DMA) - { - struct rt_mmcsd_data *data = mrq->data; - - if (host->use_external_dma && data && (mrq->cmd->err || data->err)) - { - host->mrqs_done[i] = NULL; - sdhci_set_mrq_done(host, mrq); - } - } - - host->mrqs_done[i] = NULL; - - rt_spin_unlock_irqrestore(&host->lock, flags); - - if (host->ops->request_done) - host->ops->request_done(host, mrq); - else - mmc_request_done(host->mmc, mrq); - - return RT_FALSE; -} - - -static void sdhci_thread_irq(struct rt_work *work, void *work_data) -{ - struct sdhci_host *host = work_data; - struct rt_mmcsd_cmd *cmd; - rt_base_t flags; - rt_uint32_t isr; - - while (!sdhci_request_done(host)); - - flags = rt_spin_lock_irqsave(&host->lock); - - isr = host->thread_isr; - host->thread_isr = 0; - - cmd = host->deferred_cmd; - if (cmd && !sdhci_send_command_retry(host, cmd, flags)) - sdhci_finish_mrq(host, cmd->mrq); - - rt_spin_unlock_irqrestore(&host->lock, flags); - - if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) - { - struct mmc_host *mmc = host->mmc; - - mmc->ops->card_event(mmc); - } -} - - -void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_uint32_t flags; - - flags = rt_spin_lock_irqsave(&host->lock); - sdhci_enable_sdio_irq_nolock(host, enable); - rt_spin_unlock_irqrestore(&host->lock, flags); -} - - -/********************************************************* */ -/* request */ -/********************************************************* */ - -void sdhci_request(struct mmc_host *mmc, struct rt_mmcsd_req *mrq) -{ - struct sdhci_host *host = mmc_priv(mmc); - struct rt_mmcsd_cmd *cmd; - rt_base_t flags; - rt_bool_t present; - - /* Firstly check card presence */ - present = mmc->ops->get_cd(mmc); - - flags = rt_spin_lock_irqsave(&host->lock); - - if (sdhci_present_error(host, mrq->cmd, present)) - goto out_finish; - - cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd; - - if (!sdhci_send_command_retry(host, cmd, flags)) - goto out_finish; - - rt_spin_unlock_irqrestore(&host->lock, flags); - - return; - -out_finish: - sdhci_finish_mrq(host, mrq); - rt_spin_unlock_irqrestore(&host->lock, flags); -} - - -static void sdhci_complete_work(struct rt_work *work, void *work_data) -{ - struct sdhci_host *host = work_data; - - while (!sdhci_request_done(host)); -} - - -/********************************************************* */ -/* timer */ -/********************************************************* */ -static void sdhci_timeout_timer(void *parameter) -{ - struct sdhci_host *host = parameter; - rt_base_t flags; - - flags = rt_spin_lock_irqsave(&host->lock); - - if (host->cmd && !sdhci_data_line_cmd(host->cmd)) - { - rt_kprintf("%s: Timeout waiting for hardware cmd interrupt.\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - - host->cmd->err = -ETIMEDOUT; - sdhci_finish_mrq(host, host->cmd->mrq); - } - - rt_spin_unlock_irqrestore(&host->lock, flags); -} - -static void sdhci_timeout_data_timer(void *parameter) -{ - struct sdhci_host *host = parameter; - rt_base_t flags; - - flags = rt_spin_lock_irqsave(&host->lock); - - if (host->data || host->data_cmd || (host->cmd && sdhci_data_line_cmd(host->cmd))) - { - rt_kprintf("%s: Timeout waiting for hardware interrupt.\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - - if (host->data) - { - host->data->err = -ETIMEDOUT; - __sdhci_finish_data(host, RT_TRUE); - rt_workqueue_submit_work(host->complete_wq, &host->complete_work, 0); - } - else if (host->data_cmd) - { - host->data_cmd->err = -ETIMEDOUT; - sdhci_finish_mrq(host, host->data_cmd->mrq); - } - else - { - host->cmd->err = -ETIMEDOUT; - sdhci_finish_mrq(host, host->cmd->mrq); - } - } - - rt_spin_unlock_irqrestore(&host->lock, flags); -} - - -/********************************************************* */ -/* tuning */ -/********************************************************* */ -int sdhci_execute_tuning(struct mmc_host *mmc, rt_uint32_t opcode) -{ - struct sdhci_host *host = mmc_priv(mmc); - int err = 0; - unsigned int tuning_count = 0; - rt_bool_t hs400_tuning; - - hs400_tuning = host->flags & SDHCI_HS400_TUNING; - - if (host->tuning_mode == SDHCI_TUNING_MODE_1) - tuning_count = host->tuning_count; - - /* - * The Host Controller needs tuning in case of SDR104 and DDR50 - * mode, and for SDR50 mode when Use Tuning for SDR50 is set in - * the Capabilities register. - * If the Host Controller supports the HS200 mode then the - * tuning function has to be executed. - */ - switch (host->timing) - { - /* HS400 tuning is done in HS200 mode */ - case MMC_TIMING_MMC_HS400: - err = -EINVAL; - goto out; - - case MMC_TIMING_MMC_HS200: - /* - * Periodic re-tuning for HS400 is not expected to be needed, so - * disable it here. - */ - if (hs400_tuning) - tuning_count = 0; - break; - - case MMC_TIMING_UHS_SDR104: - case MMC_TIMING_UHS_DDR50: - break; - - case MMC_TIMING_UHS_SDR50: - if (host->flags & SDHCI_SDR50_NEEDS_TUNING) - break; - fallthrough; - - default: - goto out; - } - - if (host->ops->platform_execute_tuning) - { - err = host->ops->platform_execute_tuning(host, opcode); - goto out; - } - - mmc->retune_period = tuning_count; - - if (host->tuning_delay < 0) - host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK; - - sdhci_start_tuning(host); - - host->tuning_err = __sdhci_execute_tuning(host, opcode); - - sdhci_end_tuning(host); -out: - host->flags &= ~SDHCI_HS400_TUNING; - - return err; -} - -int __sdhci_execute_tuning(struct sdhci_host *host, rt_uint32_t opcode) -{ - int i; - - /* - * Issue opcode repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches tuning loop count. - */ - for (i = 0; i < host->tuning_loop_count; i++) - { - rt_uint16_t ctrl; - - sdhci_send_tuning(host, opcode); - - if (!host->tuning_done) - { - sdhci_abort_tuning(host, opcode); - return -ETIMEDOUT; - } - - /* Spec does not require a delay between tuning cycles */ - if (host->tuning_delay > 0) - rt_thread_mdelay(host->tuning_delay); - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) - { - if (ctrl & SDHCI_CTRL_TUNED_CLK) - return 0; /* Success! */ - break; - } - } - - LOG_D("%s: Tuning failed, falling back to fixed sampling clock\n", - mmc_hostname(host->mmc)); - sdhci_reset_tuning(host); - return -EAGAIN; -} - -void sdhci_start_tuning(struct sdhci_host *host) -{ - rt_uint16_t ctrl; - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl |= SDHCI_CTRL_EXEC_TUNING; - if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) - ctrl |= SDHCI_CTRL_TUNED_CLK; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); - - /* - * As per the Host Controller spec v3.00, tuning command - * generates Buffer Read Ready interrupt, so enable that. - * - * Note: The spec clearly says that when tuning sequence - * is being performed, the controller does not generate - * interrupts other than Buffer Read Ready interrupt. But - * to make sure we don't hit a controller bug, we _only_ - * enable Buffer Read Ready interrupt here. - */ - sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); - sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); -} - -void sdhci_end_tuning(struct sdhci_host *host) -{ - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -} - -void sdhci_abort_tuning(struct sdhci_host *host, rt_uint32_t opcode) -{ - sdhci_reset_tuning(host); - - sdhci_reset_for(host, TUNING_ABORT); - - sdhci_end_tuning(host); -} - -void sdhci_send_tuning(struct sdhci_host *host, rt_uint32_t opcode) -{ - struct mmc_host *mmc = host->mmc; - struct rt_mmcsd_cmd cmd = {}; - struct rt_mmcsd_req mrq = {}; - unsigned long flags; - rt_uint32_t b = host->sdma_boundary; - - flags = rt_spin_lock_irqsave(&host->lock); - - cmd.cmd_code = opcode; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - cmd.mrq = &mrq; - - mrq.cmd = &cmd; - /* - * In response to CMD19, the card sends 64 bytes of tuning - * block to the Host Controller. So we set the block size - * to 64 here. - */ - if (cmd.cmd_code == MMC_SEND_TUNING_BLOCK_HS200 && mmc->ios.bus_width == MMC_BUS_WIDTH_8) - sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 128), SDHCI_BLOCK_SIZE); - else - sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 64), SDHCI_BLOCK_SIZE); - - /* - * The tuning block is sent by the card to the host controller. - * So we set the TRNS_READ bit in the Transfer Mode register. - * This also takes care of setting DMA Enable and Multi Block - * Select in the same register to 0. - */ - sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); - - if (!sdhci_send_command_retry(host, &cmd, flags)) - { - rt_spin_unlock_irqrestore(&host->lock, flags); - host->tuning_done = 0; - return; - } - - host->cmd = NULL; - - sdhci_del_timer(host, &mrq); - - host->tuning_done = 0; - - rt_spin_unlock_irqrestore(&host->lock, flags); -} - -void sdhci_reset_tuning(struct sdhci_host *host) -{ - rt_uint16_t ctrl; - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl &= ~SDHCI_CTRL_TUNED_CLK; - ctrl &= ~SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); -} - - -/********************************************************* */ -/* error */ -/********************************************************* */ - -void sdhci_dumpregs(struct sdhci_host *host) -{ -#define SDHCI_DUMP rt_kprintf - SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n"); - - SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n", - sdhci_readl(host, SDHCI_DMA_ADDRESS), - sdhci_readw(host, SDHCI_HOST_VERSION)); - SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n", - sdhci_readw(host, SDHCI_BLOCK_SIZE), - sdhci_readw(host, SDHCI_BLOCK_COUNT)); - SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n", - sdhci_readl(host, SDHCI_ARGUMENT), - sdhci_readw(host, SDHCI_TRANSFER_MODE)); - SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n", - sdhci_readl(host, SDHCI_PRESENT_STATE), - sdhci_readb(host, SDHCI_HOST_CONTROL)); - SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n", - sdhci_readb(host, SDHCI_POWER_CONTROL), - sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n", - sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), - sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n", - sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), - sdhci_readl(host, SDHCI_INT_STATUS)); - SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n", - sdhci_readl(host, SDHCI_INT_ENABLE), - sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n", - sdhci_readw(host, SDHCI_AUTO_CMD_STATUS), - sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n", - sdhci_readl(host, SDHCI_CAPABILITIES), - sdhci_readl(host, SDHCI_CAPABILITIES_1)); - SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n", - sdhci_readw(host, SDHCI_COMMAND), - sdhci_readl(host, SDHCI_MAX_CURRENT)); - SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n", - sdhci_readl(host, SDHCI_RESPONSE), - sdhci_readl(host, SDHCI_RESPONSE + 4)); - SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n", - sdhci_readl(host, SDHCI_RESPONSE + 8), - sdhci_readl(host, SDHCI_RESPONSE + 12)); - SDHCI_DUMP("Host ctl2: 0x%08x\n", - sdhci_readw(host, SDHCI_HOST_CONTROL2)); - - - if (host->ops->dump_vendor_regs) - host->ops->dump_vendor_regs(host); - - SDHCI_DUMP("============================================\n"); -} - - -static const struct mmc_host_ops sdhci_ops = { - .request = sdhci_request, - .set_ios = sdhci_set_ios, - .get_cd = sdhci_get_cd, - .get_ro = sdhci_get_ro, - .enable_sdio_irq = sdhci_enable_sdio_irq, - .ack_sdio_irq = sdhci_ack_sdio_irq, - .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, - .prepare_hs400_tuning = sdhci_prepare_hs400_tuning, - .execute_tuning = sdhci_execute_tuning, - .card_event = sdhci_card_event, - .card_busy = sdhci_card_busy, -}; - - -void sdhci_remove_host(struct sdhci_host *host, int dead) -{ - struct mmc_host *mmc = host->mmc; - unsigned long flags; - - if (dead) - { - flags = rt_spin_lock_irqsave(&host->lock); - - host->flags |= SDHCI_DEVICE_DEAD; - - if (sdhci_has_requests(host)) - { - rt_kprintf("%s: Controller removed during " - " transfer!\n", - mmc_hostname(mmc)); - sdhci_error_out_mrqs(host, -ENOMEDIUM); - } - - rt_spin_unlock_irqrestore(&host->lock, flags); - } - - sdhci_set_card_detection(host, RT_FALSE); - - mmc_remove_host(mmc); - - - if (!dead) - sdhci_reset_for_all(host); - - sdhci_writel(host, 0, SDHCI_INT_ENABLE); - sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - - rt_timer_delete(&host->timer); - rt_timer_delete(&host->data_timer); - - rt_workqueue_destroy(host->complete_wq); - - if (host->use_external_dma) - sdhci_external_dma_release(host); - - host->align_buffer = NULL; -} - -rt_uint16_t sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, - unsigned int *actual_clock) -{ - int div = 0; /* Initialized for compiler warning */ - int real_div = div, clk_mul = 1; - rt_uint16_t clk = 0; - rt_bool_t switch_base_clk = RT_FALSE; - - if (host->version >= SDHCI_SPEC_300) - { - if (host->preset_enabled) - { - rt_uint16_t pre_val; - - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - pre_val = sdhci_get_preset_value(host); - div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val); - if (host->clk_mul && (pre_val & SDHCI_PRESET_CLKGEN_SEL)) - { - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div + 1; - clk_mul = host->clk_mul; - } - else - { - real_div = max_t(int, 1, div << 1); - } - goto clock_set; - } - - /* - * Check if the Host Controller supports Programmable Clock - * Mode. - */ - if (host->clk_mul) - { - for (div = 1; div <= 1024; div++) - { - if ((host->max_clk * host->clk_mul / div) - <= clock) - break; - } - if ((host->max_clk * host->clk_mul / div) <= clock) - { - /* - * Set Programmable Clock Mode in the Clock - * Control register. - */ - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; - div--; - } - else - { - /* - * Divisor can be too small to reach clock - * speed requirement. Then use the base clock. - */ - switch_base_clk = RT_TRUE; - } - } - - if (!host->clk_mul || switch_base_clk) - { - /* Version 3.00 divisors must be a multiple of 2. */ - if (host->max_clk <= clock) - div = 1; - else - { - for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; - div += 2) - { - if ((host->max_clk / div) <= clock) - break; - } - } - real_div = div; - div >>= 1; - if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN) - && !div && host->max_clk <= 25000000) - div = 1; - } - } - else - { - /* Version 2.00 divisors must be a power of 2. */ - for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) - { - if ((host->max_clk / div) <= clock) - break; - } - real_div = div; - div >>= 1; - } - -clock_set: - if (real_div) - *actual_clock = (host->max_clk * clk_mul) / real_div; - clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; - clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) - << SDHCI_DIVIDER_HI_SHIFT; - - return clk; -} - -void sdhci_enable_clk(struct sdhci_host *host, rt_uint16_t clk) -{ - long timeout; - - clk |= SDHCI_CLOCK_INT_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 150 ms */ - timeout = rt_tick_from_millisecond(150); - while (1) - { - timeout = timeout - rt_tick_get(); - - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - if (clk & SDHCI_CLOCK_INT_STABLE) - break; - if (timeout < 0) - { - rt_kprintf("%s: Internal clock never stabilised.\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - return; - } - rt_hw_us_delay(10); - } - - if (host->version >= SDHCI_SPEC_410 && host->v4_mode) - { - clk |= SDHCI_CLOCK_PLL_EN; - clk &= ~SDHCI_CLOCK_INT_STABLE; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - /* Wait max 150 ms */ - timeout = rt_tick_from_millisecond(150); - while (1) - { - timeout = timeout - rt_tick_get(); - - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - if (clk & SDHCI_CLOCK_INT_STABLE) - break; - if (timeout < 0) - { - rt_kprintf("%s: PLL clock never stabilised.\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - return; - } - rt_hw_us_delay(10); - } - } - - clk |= SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -} - -void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -{ - rt_uint16_t clk; - - host->mmc->actual_clock = 0; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - - if (clock == 0) - return; - - clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); - sdhci_enable_clk(host, clk); -} - -void __sdhci_read_caps(struct sdhci_host *host, const rt_uint16_t *ver, - const rt_uint32_t *caps, const rt_uint32_t *caps1) -{ - rt_uint16_t v; - rt_uint64_t dt_caps_mask = 0; - rt_uint64_t dt_caps = 0; - - if (host->read_caps) - return; - - host->read_caps = RT_TRUE; - - if (debug_quirks) - host->quirks = debug_quirks; - - if (debug_quirks2) - host->quirks2 = debug_quirks2; - - sdhci_reset_for_all(host); - - if (host->v4_mode) - sdhci_do_enable_v4_mode(host); -#ifdef RT_USING_OFW - rt_ofw_prop_read_u64(mmc_dev(host->mmc)->ofw_node, - "sdhci-caps-mask", &dt_caps_mask); - rt_ofw_prop_read_u64(mmc_dev(host->mmc)->ofw_node, - "sdhci-caps", &dt_caps); -#endif - v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION); - host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; - - if (caps) - { - host->caps = *caps; - } - else - { - host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); - host->caps &= ~lower_32_bits(dt_caps_mask); - host->caps |= lower_32_bits(dt_caps); - } - - if (host->version < SDHCI_SPEC_300) - return; - - if (caps1) - { - host->caps1 = *caps1; - } - else - { - host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - host->caps1 &= ~upper_32_bits(dt_caps_mask); - host->caps1 |= upper_32_bits(dt_caps); - } -} - -struct sdhci_host *sdhci_alloc_host(struct rt_device *dev, - size_t priv_size) -{ - struct mmc_host *mmc; - struct sdhci_host *host; - - mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); - if (!mmc) - return NULL; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->mmc_host_ops = sdhci_ops; - mmc->ops = &host->mmc_host_ops; - - host->flags = SDHCI_SIGNALING_330; - - host->cqe_ier = SDHCI_CQE_INT_MASK; - host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK; - - host->tuning_delay = -1; - host->tuning_loop_count = MAX_TUNING_LOOP; - - host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG; - - /* - * The DMA table descriptor count is calculated as the maximum - * number of segments times 2, to allow for an alignment - * descriptor for each segment, plus 1 for a nop end descriptor. - */ - - host->max_timeout_count = 0xE; - - return host; -} - -int sdhci_setup_host(struct sdhci_host *host) -{ - struct mmc_host *mmc; - size_t max_current_caps; - unsigned int ocr_avail; - unsigned int override_timeout_clk; - size_t max_clk; - int ret = 0; - bool enable_vqmmc = RT_FALSE; - - RT_ASSERT(host != NULL); - - - mmc = host->mmc; - - /* - * If there are external regulators, get them. Note this must be done - * early before resetting the host and reading the capabilities so that - * the host can take the appropriate action if regulators are not - * available. - */ - if (!mmc->supply.vqmmc) - { - if (ret) - return ret; - enable_vqmmc = RT_TRUE; - } - - LOG_D("Version: 0x%08x | Present: 0x%08x\n", - sdhci_readw(host, SDHCI_HOST_VERSION), - sdhci_readl(host, SDHCI_PRESENT_STATE)); - LOG_D("Caps: 0x%08x | Caps_1: 0x%08x\n", - sdhci_readl(host, SDHCI_CAPABILITIES), - sdhci_readl(host, SDHCI_CAPABILITIES_1)); - - sdhci_read_caps(host); - - override_timeout_clk = host->timeout_clk; - - if (host->version > SDHCI_SPEC_420) - { - rt_kprintf("%s: Unknown controller version (%d). You may experience problems.\n", - mmc_hostname(mmc), host->version); - } - - if (host->quirks & SDHCI_QUIRK_FORCE_DMA) - host->flags |= SDHCI_USE_SDMA; - else if (!(host->caps & SDHCI_CAN_DO_SDMA)) - LOG_D("Controller doesn't have SDMA capability\n"); - else - host->flags |= SDHCI_USE_SDMA; - - if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) && (host->flags & SDHCI_USE_SDMA)) - { - LOG_D("Disabling DMA as it is marked broken\n"); - host->flags &= ~SDHCI_USE_SDMA; - } - - if (sdhci_can_64bit_dma(host)) - host->flags |= SDHCI_USE_64_BIT_DMA; - - if (host->flags & SDHCI_USE_SDMA) - { - if (host->ops->set_dma_mask) - ret = host->ops->set_dma_mask(host); - - if (!ret && host->ops->enable_dma) - ret = host->ops->enable_dma(host); - - if (ret) - { - rt_kprintf("%s: No suitable DMA available - falling back to PIO\n", - mmc_hostname(mmc)); - host->flags &= ~SDHCI_USE_SDMA; - - ret = 0; - } - } - - /* SDMA does not support 64-bit DMA if v4 mode not set */ - if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode) - host->flags &= ~SDHCI_USE_SDMA; - /* - * If we use DMA, then it's up to the caller to set the DMA - * mask, but PIO does not need the hw shim so we set a new - * mask here in that case. - */ - - if (!(host->flags & SDHCI_USE_SDMA)) - { - host->dma_mask = DMA_BIT_MASK(64); - } - if (host->version >= SDHCI_SPEC_300) - host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps); - else - host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps); - - host->max_clk *= 1000000; - if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) - { - if (!host->ops->get_max_clock) - { - rt_kprintf("%s: Hardware doesn't specify base clock frequency. %p \n", - mmc_hostname(mmc), host->ops->get_max_clock); - ret = -ENODEV; - goto undma; - } - host->max_clk = host->ops->get_max_clock(host); - } - - /* - * In case of Host Controller v3.00, find out whether clock - * multiplier is supported. - */ - host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1); - - /* - * In case the value in Clock Multiplier is 0, then programmable - * clock mode is not supported, otherwise the actual clock - * multiplier is one more than the value of Clock Multiplier - * in the Capabilities Register. - */ - if (host->clk_mul) - host->clk_mul += 1; - - /* - * Set host parameters. - */ - max_clk = host->max_clk; - - if (host->ops->get_min_clock) - mmc->f_min = host->ops->get_min_clock(host); - else if (host->version >= SDHCI_SPEC_300) - { - if (host->clk_mul) - max_clk = host->max_clk * host->clk_mul; - /* - * Divided Clock Mode minimum clock rate is always less than - * Programmable Clock Mode minimum clock rate. - */ - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; - } - else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; - - if (!mmc->f_max || mmc->f_max > max_clk) - mmc->f_max = max_clk; - - if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) - { - host->timeout_clk = FIELD_GET(SDHCI_TIMEOUT_CLK_MASK, host->caps); - - if (host->caps & SDHCI_TIMEOUT_CLK_UNIT) - host->timeout_clk *= 1000; - - if (host->timeout_clk == 0) - { - if (!host->ops->get_timeout_clock) - { - rt_kprintf("%s: Hardware doesn't specify timeout clock frequency.\n", - mmc_hostname(mmc)); - ret = -ENODEV; - goto undma; - } - - host->timeout_clk = - DIV_ROUND_UP(host->ops->get_timeout_clock(host), - 1000); - } - - if (override_timeout_clk) - host->timeout_clk = override_timeout_clk; - - mmc->max_busy_timeout = host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27; - mmc->max_busy_timeout /= host->timeout_clk; - } - - if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT && !host->ops->get_max_timeout_count) - mmc->max_busy_timeout = 0; - - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23; - mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; - - if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) - host->flags |= SDHCI_AUTO_CMD12; - - /* - * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO. - * For v4 mode, SDMA may use Auto-CMD23 as well. - */ - if ((host->version >= SDHCI_SPEC_300) && (!(host->flags & SDHCI_USE_SDMA) || host->v4_mode) && !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) - { - host->flags |= SDHCI_AUTO_CMD23; - LOG_D("Auto-CMD23 available\n"); - } - else - { - LOG_D("Auto-CMD23 unavailable\n"); - } - - /* - * A controller may support 8-bit width, but the board itself - * might not have the pins brought out. Boards that support - * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in - * their platform code before calling sdhci_add_host(), and we - * won't assume 8-bit width for hosts without that CAP. - */ - if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) - mmc->caps |= MMC_CAP_4_BIT_DATA; - - if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23) - mmc->caps &= ~MMC_CAP_CMD23; - - if (host->caps & SDHCI_CAN_DO_HISPD) - mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; - if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && mmc_card_is_removable(mmc) && mmc_gpio_get_cd(mmc) < 0) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - if (mmc->supply.vqmmc) - { - if (enable_vqmmc) - { - host->sdhci_core_to_disable_vqmmc = !ret; - } - - /* If vqmmc provides no 1.8V signalling, then there's no UHS */ - if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000, - 1950000)) - host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); - - /* In eMMC case vqmmc might be a fixed 1.8V regulator */ - if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 2700000, - 3600000)) - host->flags &= ~SDHCI_SIGNALING_330; - - if (ret) - { - rt_kprintf("%s: Failed to enable vqmmc regulator: %d\n", - mmc_hostname(mmc), ret); - mmc->supply.vqmmc = (void *)-EINVAL; - } - } - if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) - { - host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); - /* - * The SDHCI controller in a SoC might support HS200/HS400 - * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property), - * but if the board is modeled such that the IO lines are not - * connected to 1.8v then HS200/HS400 cannot be supported. - * Disable HS200/HS400 if the board does not have 1.8v connected - * to the IO lines. (Applicable for other modes in 1.8v) - */ - mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES); - mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS); - } - - /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ - if (host->caps1 & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50)) - mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; - - /* SDR104 supports also implies SDR50 support */ - if (host->caps1 & SDHCI_SUPPORT_SDR104) - { - mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50; - /* SD3.0: SDR104 is supported so (for eMMC) the caps2 - * field can be promoted to support HS200. - */ - if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) - mmc->caps2 |= MMC_CAP2_HS200; - } - else if (host->caps1 & SDHCI_SUPPORT_SDR50) - { - mmc->caps |= MMC_CAP_UHS_SDR50; - } - - if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 && (host->caps1 & SDHCI_SUPPORT_HS400)) - mmc->caps2 |= MMC_CAP2_HS400; - if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && (!mmc->supply.vqmmc || !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000, 1300000))) - mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V; - if ((host->caps1 & SDHCI_SUPPORT_DDR50) && !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) - mmc->caps |= MMC_CAP_UHS_DDR50; - - /* Does the host need tuning for SDR50? */ - if (host->caps1 & SDHCI_USE_SDR50_TUNING) - host->flags |= SDHCI_SDR50_NEEDS_TUNING; - - /* Driver Type(s) (A, C, D) supported by the host */ - if (host->caps1 & SDHCI_DRIVER_TYPE_A) - mmc->caps |= MMC_CAP_DRIVER_TYPE_A; - if (host->caps1 & SDHCI_DRIVER_TYPE_C) - mmc->caps |= MMC_CAP_DRIVER_TYPE_C; - if (host->caps1 & SDHCI_DRIVER_TYPE_D) - mmc->caps |= MMC_CAP_DRIVER_TYPE_D; - - /* Initial value for re-tuning timer count */ - host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK, - host->caps1); - - /* - * In case Re-tuning Timer is not disabled, the actual value of - * re-tuning timer will be 2 ^ (n - 1). - */ - if (host->tuning_count) - host->tuning_count = 1 << (host->tuning_count - 1); - - /* Re-tuning mode supported by the Host Controller */ - host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1); - - ocr_avail = 0; - - /* - * According to SD Host Controller spec v3.00, if the Host System - * can afford more than 150mA, Host Driver should set XPC to 1. Also - * the value is meaningful only if Voltage Support in the Capabilities - * register is set. The actual current value is 4 times the register - * value. - */ - max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); - - if (!max_current_caps && mmc->supply.vmmc) - { - int curr = regulator_get_current_limit(mmc->supply.vmmc); - if (curr > 0) - { - /* convert to SDHCI_MAX_CURRENT format */ - curr = curr / 1000; /* convert to mA */ - curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER; - - curr = min_t(rt_uint32_t, curr, SDHCI_MAX_CURRENT_LIMIT); - max_current_caps = - FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, curr) | FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, curr) | FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, curr); - } - } - - if (host->caps & SDHCI_CAN_VDD_330) - { - ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; - - mmc->max_current_330 = FIELD_GET(SDHCI_MAX_CURRENT_330_MASK, - max_current_caps) - * SDHCI_MAX_CURRENT_MULTIPLIER; - } - if (host->caps & SDHCI_CAN_VDD_300) - { - ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; - - mmc->max_current_300 = FIELD_GET(SDHCI_MAX_CURRENT_300_MASK, - max_current_caps) - * SDHCI_MAX_CURRENT_MULTIPLIER; - } - if (host->caps & SDHCI_CAN_VDD_180) - { - ocr_avail |= MMC_VDD_165_195; - - mmc->max_current_180 = FIELD_GET(SDHCI_MAX_CURRENT_180_MASK, - max_current_caps) - * SDHCI_MAX_CURRENT_MULTIPLIER; - } - - /* If OCR set by host, use it instead. */ - if (host->ocr_mask) - ocr_avail = host->ocr_mask; - - /* If OCR set by external regulators, give it highest prio. */ - if (mmc->ocr_avail) - ocr_avail = mmc->ocr_avail; - - mmc->ocr_avail = ocr_avail; - mmc->ocr_avail_sdio = ocr_avail; - if (host->ocr_avail_sdio) - mmc->ocr_avail_sdio &= host->ocr_avail_sdio; - mmc->ocr_avail_sd = ocr_avail; - if (host->ocr_avail_sd) - mmc->ocr_avail_sd &= host->ocr_avail_sd; - else /* normal SD controllers don't support 1.8V */ - mmc->ocr_avail_sd &= ~MMC_VDD_165_195; - mmc->ocr_avail_mmc = ocr_avail; - if (host->ocr_avail_mmc) - mmc->ocr_avail_mmc &= host->ocr_avail_mmc; - - if (mmc->ocr_avail == 0) - { - rt_kprintf("%s: Hardware doesn't report any support voltages.\n", - mmc_hostname(mmc)); - ret = -ENODEV; - goto unreg; - } - - if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) || (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) - host->flags |= SDHCI_SIGNALING_180; - - if (mmc->caps2 & MMC_CAP2_HSX00_1_2V) - host->flags |= SDHCI_SIGNALING_120; - - rt_spin_lock_init(&host->lock); - - /* - * Maximum number of sectors in one transfer. Limited by SDMA boundary - * size (512KiB). Note some tuning modes impose a 4MiB limit, but this - * is less anyway. - */ - mmc->max_req_size = 524288; - - /* - * Maximum number of segments. Depends on if the hardware - * can do scatter/gather or not. - */ - if (host->flags & SDHCI_USE_SDMA) - { - mmc->max_segs = 1; - } - else - { /* PIO */ - mmc->max_segs = SDHCI_MAX_SEGS; - } - /* - * Maximum segment size. Could be one segment with the maximum number - * of bytes. When doing hardware scatter/gather, each entry cannot - * be larger than 64 KiB though. - */ - mmc->max_seg_size = mmc->max_req_size; - - /* - * Maximum block size. This varies from controller to controller and - * is specified in the capabilities register. - */ - if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) - { - mmc->max_blk_size = 2; - } - else - { - mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; - if (mmc->max_blk_size >= 3) - { - rt_kprintf("%s: Invalid maximum block size, assuming 512 bytes\n", - mmc_hostname(mmc)); - mmc->max_blk_size = 0; - } - } - - mmc->max_blk_size = 512 << mmc->max_blk_size; - - /* - * Maximum block count. - */ - mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; - return 0; - -unreg: -undma: - return ret; -} - -static void sdhci_init(struct sdhci_host *host, int soft) -{ - struct mmc_host *mmc = host->mmc; - rt_base_t flags; - - if (soft) - { - sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - } - else - { - sdhci_do_reset(host, SDHCI_RESET_ALL); - } - if (host->v4_mode) - { - sdhci_do_enable_v4_mode(host); - } - flags = rt_spin_lock_irqsave(&host->lock); - sdhci_set_default_irqs(host); - rt_spin_unlock_irqrestore(&host->lock, flags); - - host->cqe_on = RT_FALSE; - - if (soft) - { - /* force clock reconfiguration */ - host->clock = 0; - host->reinit_uhs = RT_TRUE; - mmc->ops->set_ios(mmc, &mmc->ios); - } -} - -static void sdhci_reinit(struct sdhci_host *host) -{ - rt_uint32_t cd = host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); - - sdhci_init(host, 0); - sdhci_enable_card_detection(host); - - /* - * A change to the card detect bits indicates a change in present state, - * refer sdhci_set_card_detection(). A card detect interrupt might have - * been missed while the host controller was being reset, so trigger a - * rescan to check. - */ - if (cd != (host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT))) - mmc_detect_change(host->mmc, rt_tick_from_millisecond(200)); -} - -int __sdhci_add_host(struct sdhci_host *host) -{ - struct mmc_host *mmc = host->mmc; - int ret; - - if ((mmc->caps2 & MMC_CAP2_CQE) && (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) - { - mmc->caps2 &= ~MMC_CAP2_CQE; - } - - host->complete_wq = rt_workqueue_create("sdhci", 4096, 20); - if (!host->complete_wq) - return -ENOMEM; - - rt_work_init(&host->complete_work, sdhci_complete_work, host); - - rt_timer_init(&host->timer, "sdhci_timer", sdhci_timeout_timer, host, 0, RT_TIMER_FLAG_SOFT_TIMER); - rt_timer_init(&host->data_timer, "sdhci_data_timer", sdhci_timeout_data_timer, host, 0, RT_TIMER_FLAG_SOFT_TIMER); - - rt_wqueue_init(&host->buf_ready_int); - - sdhci_init(host, 0); - - host->irq_wq = rt_workqueue_create("sdhci_irq", 8192, 1); - rt_work_init(&host->irq_work, sdhci_thread_irq, host); - rt_hw_interrupt_install(host->irq, sdhci_irq, host, mmc_hostname(mmc)); - rt_pic_irq_unmask(host->irq); - ret = mmc_add_host(mmc); - if (ret) - goto unirq; - - rt_kprintf("%s: SDHCI controller on %s [%s] using %s\n", - mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->parent.name, - (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); - - sdhci_enable_card_detection(host); - - return 0; - -unirq: - sdhci_reset_for_all(host); - sdhci_writel(host, 0, SDHCI_INT_ENABLE); - sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - - return ret; -} - -int sdhci_add_host(struct sdhci_host *host) -{ - int ret; - ret = sdhci_setup_host(host); - if (ret) - return ret; - - ret = __sdhci_add_host(host); - if (ret) - goto cleanup; - - return 0; - -cleanup: - sdhci_cleanup_host(host); - - return ret; -} - -void sdhci_set_ios(struct mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - rt_bool_t reinit_uhs = host->reinit_uhs; - rt_bool_t turning_on_clk = RT_FALSE; - rt_uint8_t ctrl; - - host->reinit_uhs = RT_FALSE; - - if (ios->power_mode == MMC_POWER_UNDEFINED) - return; - - if (host->flags & SDHCI_DEVICE_DEAD) - { - if (mmc->supply.vmmc && ios->power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - return; - } - - /* - * Reset the chip on each power off. - * Should clear out any weird states. - */ - if (ios->power_mode == MMC_POWER_OFF) - { - sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); - sdhci_reinit(host); - } - - if (host->version >= SDHCI_SPEC_300 && (ios->power_mode == MMC_POWER_UP) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) - sdhci_enable_preset_value(host, RT_FALSE); - - if (!ios->clock || ios->clock != host->clock) - { - turning_on_clk = ios->clock && !host->clock; - - host->ops->set_clock(host, ios->clock); - host->clock = ios->clock; - - if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && host->clock) - { - host->timeout_clk = mmc->actual_clock ? mmc->actual_clock / 1000 : host->clock / 1000; - mmc->max_busy_timeout = - host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27; - mmc->max_busy_timeout /= host->timeout_clk; - } - } - - if (host->ops->set_power) - host->ops->set_power(host, ios->power_mode, ios->vdd); - else - sdhci_set_power(host, ios->power_mode, ios->vdd); - - if (host->ops->platform_send_init_74_clocks) - host->ops->platform_send_init_74_clocks(host, ios->power_mode); - - host->ops->set_bus_width(host, ios->bus_width); - - /* - * Special case to avoid multiple clock changes during voltage - * switching. - */ - if (!reinit_uhs && turning_on_clk && host->timing == ios->timing && host->version >= SDHCI_SPEC_300 && !sdhci_presetable_values_change(host, ios)) - return; - - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) - { - if (ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS || ios->timing == MMC_TIMING_MMC_HS400 || ios->timing == MMC_TIMING_MMC_HS200 || ios->timing == MMC_TIMING_MMC_DDR52 || ios->timing == MMC_TIMING_UHS_SDR50 || ios->timing == MMC_TIMING_UHS_SDR104 || ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_UHS_SDR25) - ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; - } - - if (host->version >= SDHCI_SPEC_300) - { - rt_uint16_t clk, ctrl_2; - - /* - * According to SDHCI Spec v3.00, if the Preset Value - * Enable in the Host Control 2 register is set, we - * need to reset SD Clock Enable before changing High - * Speed Enable to avoid generating clock glitches. - */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - if (clk & SDHCI_CLOCK_CARD_EN) - { - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - } - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - if (!host->preset_enabled) - { - /* - * We only need to set Driver Strength if the - * preset value enable is not set. - */ - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK; - if (ios->drv_type == MMC_SET_DRIVER_TYPE_A) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A; - else if (ios->drv_type == MMC_SET_DRIVER_TYPE_B) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B; - else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C; - else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D) - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D; - else - { - LOG_D("%s: invalid driver type, default to driver type B\n", - mmc_hostname(mmc)); - ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B; - } - - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); - host->drv_type = ios->drv_type; - } - - host->ops->set_uhs_signaling(host, ios->timing); - host->timing = ios->timing; - - if (sdhci_preset_needed(host, ios->timing)) - { - rt_uint16_t preset; - - sdhci_enable_preset_value(host, RT_TRUE); - preset = sdhci_get_preset_value(host); - ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK, - preset); - host->drv_type = ios->drv_type; - } - - /* Re-enable SD Clock */ - host->ops->set_clock(host, host->clock); - } - else - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); -} -void sdhci_free_host(struct sdhci_host *host) -{ - sdhci_cleanup_host(host); - rt_free(host); -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/fit-mmc.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/fit-mmc.c deleted file mode 100644 index 7c9eea3ba5..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/fit-mmc.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#include -#include "sdhci.h" -#include -#include -#include - - -static void plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req) -{ - struct mmc_host *mmc = (struct mmc_host *)host; - rt_uint32_t flags = req->cmd->flags; - - switch (flags & RESP_MASK) - { - case RESP_NONE: - flags |= MMC_RSP_NONE; - break; - case RESP_R1: - flags |= MMC_RSP_R1; - break; - case RESP_R1B: - flags |= MMC_RSP_R1B; - break; - case RESP_R2: - flags |= MMC_RSP_R2; - break; - case RESP_R3: - flags |= MMC_RSP_R3; - break; - case RESP_R4: - flags |= MMC_RSP_R4; - break; - case RESP_R5: - flags |= MMC_RSP_R5; - break; - case RESP_R6: - flags |= MMC_RSP_R6; - break; - case RESP_R7: - flags |= MMC_RSP_R7; - break; - } - if (req->data) - { - if ((rt_uint64_t)rt_kmem_v2p(req->data->buf) > 0xffffffff) - { - void *dma_buffer = rt_malloc(ARCH_PAGE_SIZE); - void *req_buf = NULL; - - if (req->data->blks * req->data->blksize > ARCH_PAGE_SIZE) - { - dma_buffer = rt_realloc(dma_buffer, req->data->blks * req->data->blksize); - } - - if (req->data->flags & DATA_DIR_WRITE) - { - rt_memcpy(dma_buffer, req->data->buf, req->data->blks * req->data->blksize); - req->data->buf = dma_buffer; - } - else if (req->data->flags & DATA_DIR_READ) - { - req_buf = req->data->buf; - req->data->buf = dma_buffer; - } - req->cmd->flags |= flags; - mmc->ops->request(mmc, req); - - rt_sem_take(&host->sem_ack, RT_WAITING_FOREVER); - - if (req->data->flags & DATA_DIR_READ) - { - rt_memcpy(req_buf, dma_buffer, req->data->blksize * req->data->blks); - req->data->buf = req_buf; - } - - rt_free(dma_buffer); - rt_sem_release(&host->sem_ack); - } - else - { - req->cmd->flags |= flags; - mmc->ops->request(mmc, req); - } - } - else - { - req->cmd->flags |= flags; - mmc->ops->request(mmc, req); - } -} - -static void plat_set_ioconfig(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *iocfg) -{ - struct mmc_host *mmc = (struct mmc_host *)host; - - LOG_D("clock:%d,width:%d,power:%d,vdd:%d,timing:%d\n", - iocfg->clock, iocfg->bus_width, - iocfg->power_mode, iocfg->vdd, iocfg->timing); - - mmc->ops->set_ios(mmc, iocfg); -} - -static rt_int32_t plat_get_card_status(struct rt_mmcsd_host *host) -{ - struct mmc_host *mmc = (struct mmc_host *)host; - - return mmc->ops->get_cd(mmc); -} - -static rt_int32_t plat_execute_tuning(struct rt_mmcsd_host *host, rt_int32_t opcode) -{ - struct mmc_host *mmc = (struct mmc_host *)host; - - return mmc->ops->execute_tuning(mmc, opcode); -} - -static void plat_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en) -{ - struct mmc_host *mmc = (struct mmc_host *)host; - - return mmc->ops->enable_sdio_irq(mmc, en); -} - - -static const struct rt_mmcsd_host_ops rt_mmcsd_ops = { - .request = plat_request, - .set_iocfg = plat_set_ioconfig, - .get_card_status = plat_get_card_status, - .enable_sdio_irq = plat_enable_sdio_irq, - .execute_tuning = plat_execute_tuning, -}; - - -void mmc_request_done(struct mmc_host *host, struct rt_mmcsd_req *mrq) -{ - mmcsd_req_complete(&host->rthost); -} - -/*add host in rtt while sdhci complete*/ -int mmc_add_host(struct mmc_host *mmc) -{ - mmc->rthost.ops = &rt_mmcsd_ops; - mmc->rthost.flags = mmc->caps; - mmc->rthost.freq_max = mmc->f_max; - mmc->rthost.freq_min = 400000; - mmc->rthost.max_dma_segs = mmc->max_segs; - mmc->rthost.max_seg_size = mmc->max_seg_size; - mmc->rthost.max_blk_size = mmc->max_blk_size; - mmc->rthost.max_blk_count = mmc->max_blk_count; - mmc->rthost.valid_ocr = VDD_33_34 | VDD_32_33 | VDD_31_32 | VDD_30_31 | VDD_165_195 | VDD_20_21; - - - mmcsd_change(&mmc->rthost); - return 0; -} - -struct mmc_host *mmc_alloc_host(int extra, struct rt_device *dev) -{ - struct mmc_host *mmc; - - mmc = rt_malloc(sizeof(*mmc) + extra); - if (mmc) - { - rt_memset(mmc, 0, sizeof(*mmc) + extra); - mmc->parent = dev; - mmcsd_host_init(&mmc->rthost); - } - - return mmc; -} - -void mmc_remove_host(struct mmc_host *host) -{ - rt_free(host); -} - -int mmc_abort_tuning(struct mmc_host *host, rt_uint32_t opcode) -{ - return 0; -} - - -int mmc_gpio_get_cd(struct mmc_host *host) -{ - return -ENOSYS; -} - -void mmc_detect_change(struct mmc_host *host, unsigned long delay) -{ -} - - -int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct rt_mmcsd_io_cfg *ios) -{ - return 0; -} - -rt_bool_t mmc_can_gpio_ro(struct mmc_host *host) -{ - return RT_FALSE; -} - -int mmc_gpio_get_ro(struct mmc_host *host) -{ - return 0; -} - -int mmc_send_abort_tuning(struct mmc_host *host, rt_uint32_t opcode) -{ - return 0; -} -int mmc_of_parse(struct mmc_host *host) -{ - struct rt_device *dev = host->parent; - rt_uint32_t bus_width; - - if (!dev || !dev->ofw_node) - return 0; - - /* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */ - if (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) < 0) - { - bus_width = 1; - } - - switch (bus_width) - { - case 8: - host->caps |= MMC_CAP_8_BIT_DATA; - break; /* Hosts capable of 8-bit can also do 4 bits */ - case 4: - host->caps |= MMC_CAP_4_BIT_DATA; - break; - case 1: - break; - default: - return -EINVAL; - } - - /* f_max is obtained from the optional "max-frequency" property */ - rt_dm_dev_prop_read_u32(dev, "max-frequency", &host->f_max); - - if (rt_dm_dev_prop_read_bool(dev, "cap-mmc-highspeed")) - { - host->caps |= MMC_CAP_MMC_HIGHSPEED; - } - - if (rt_dm_dev_prop_read_bool(dev, "mmc-hs200-1_8v")) - { - host->caps |= MMC_CAP2_HS200_1_8V_SDR; - } - - if (rt_dm_dev_prop_read_bool(dev, "non-removable")) - { - host->caps |= MMC_CAP_NONREMOVABLE; - } - - if (rt_dm_dev_prop_read_bool(dev, "no-sdio")) - { - host->caps2 |= MMC_CAP2_NO_SDIO; - } - - if (rt_dm_dev_prop_read_bool(dev, "no-sd")) - { - host->caps2 |= MMC_CAP2_NO_SD; - } - - if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-3_3v")) - { - host->caps |= MMC_CAP_3_3V_DDR; - } - - if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_8v")) - { - host->caps |= MMC_CAP_1_8V_DDR; - } - - if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_2v")) - { - host->caps |= MMC_CAP_1_2V_DDR; - } - - return 0; -} - - -void mmc_free_host(struct mmc_host *host) -{ -} - -rt_bool_t mmc_can_gpio_cd(struct mmc_host *host) -{ - return RT_FALSE; -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_dma.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_dma.c deleted file mode 100644 index 29d296f9de..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_dma.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#include "sdhci.h" -#include - - -int dma_set_mask_and_coherent(struct rt_device *dev, rt_uint64_t mask) -{ - return 0; -} - -unsigned long virt_to_phys(volatile void *address) -{ - return (unsigned long)((rt_uint64_t)address + PV_OFFSET); -} -void *dma_alloc_coherent(struct rt_device *dev, size_t size, - rt_uint64_t *dma_handle) -{ - void *v; - - v = rt_malloc_align(size, 2048); - rt_kprintf("v = %p \n", v); - if (v) - { - *dma_handle = virt_to_phys(v); - v = rt_ioremap((void *)*dma_handle, size); - rt_kprintf("v = %p *dma_handle = %p \n", v, *dma_handle); - } - - return v; -} - -void dma_free_coherent(struct rt_device *dev, size_t size, - void *cpu_addr, unsigned long dma_handle) -{ - rt_free(cpu_addr); -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_voltage.c b/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_voltage.c deleted file mode 100644 index 44ed683db9..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/drivers/sdhci/src/sdhci_voltage.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2006-2024 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-08-16 zhujiale first version - */ -#include "sdhci.h" - -int mmc_regulator_get_supply(struct mmc_host *mmc) -{ - mmc->supply.vmmc = -RT_NULL; - mmc->supply.vqmmc = -RT_NULL; - - return 0; -} -int regulator_get_current_limit(struct regulator *regulator) -{ - return 0; -} - -int regulator_is_supported_voltage(struct regulator *regulator, - - int min_uV, int max_uV) -{ - return 0; -} - -int regulator_enable(struct regulator *regulator) -{ - return 0; -} -void regulator_disable(struct regulator *regulator) -{ -} diff --git a/bsp/raspberry-pi/raspi-dm2.0/qemu.sh b/bsp/raspberry-pi/raspi-dm2.0/qemu.sh deleted file mode 100644 index b795a9bcb5..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/qemu.sh +++ /dev/null @@ -1,9 +0,0 @@ -if [ ! -f "sd.bin" ]; then - dd if=/dev/zero of=sd.bin bs=1024 count=65536 -fi - -qemu-system-aarch64 -M raspi4b -serial stdio \ - -kernel rtthread.bin \ - -drive if=sd,file=sd.bin \ - -dtb bcm2711-rpi-4-b.dtb \ - -append 'printk.time=0 earlycon=pl011,0xfe201000 console=ttyAMA0 root=ram0 rw' diff --git a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.py b/bsp/raspberry-pi/raspi-dm2.0/rtconfig.py deleted file mode 100644 index 106618e010..0000000000 --- a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.py +++ /dev/null @@ -1,54 +0,0 @@ -import os - -# toolchains options -ARCH ='aarch64' -CPU ='cortex-a' -CROSS_TOOL ='gcc' - -if os.getenv('RTT_ROOT'): - RTT_ROOT = os.getenv('RTT_ROOT') -else: - RTT_ROOT = r'../../..' - -if os.getenv('RTT_CC'): - CROSS_TOOL = os.getenv('RTT_CC') - -PLATFORM = 'gcc' -EXEC_PATH = r'/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-elf/bin/' - -if os.getenv('RTT_EXEC_PATH'): - EXEC_PATH = os.getenv('RTT_EXEC_PATH') - -BUILD = 'debug' - -if PLATFORM == 'gcc': - # toolchains - PREFIX = os.getenv('RTT_CC_PREFIX') or 'aarch64-none-elf-' - CC = PREFIX + 'gcc' - CPP = PREFIX + 'g++' - AS = PREFIX + 'gcc' - AR = PREFIX + 'ar' - LINK = PREFIX + 'gcc' - TARGET_EXT = 'elf' - SIZE = PREFIX + 'size' - OBJDUMP = PREFIX + 'objdump' - OBJCPY = PREFIX + 'objcopy' - - DEVICE = ' -march=armv8-a -mtune=cortex-a72 -fdiagnostics-color=always' - CPPFLAGS = ' -E -P -x assembler-with-cpp' - CFLAGS = DEVICE + ' -Wall -Wno-cpp -D_POSIX_SOURCE' - AFLAGS = ' -c' + ' -x assembler-with-cpp -D__ASSEMBLY__' - LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds' - CPATH = '' - LPATH = '' - - if BUILD == 'debug': - CFLAGS += ' -O0 -ggdb' - AFLAGS += ' -ggdb' - else: - CFLAGS += ' -O2' - - CXXFLAGS = CFLAGS - -DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' -POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' diff --git a/bsp/raspberry-pi/raspi3-64/.config b/bsp/raspberry-pi/raspi3-64/.config index 7c75cd4eea..909cdedd1b 100644 --- a/bsp/raspberry-pi/raspi3-64/.config +++ b/bsp/raspberry-pi/raspi3-64/.config @@ -11,18 +11,8 @@ # rt_vsnprintf options # # CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y -# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6 -CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9 -CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 +# CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set # end of rt_vsnprintf options # @@ -116,13 +106,13 @@ CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 # end of rt_strnlen options # end of klibc options -CONFIG_RT_NAME_MAX=12 +CONFIG_RT_NAME_MAX=24 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set # CONFIG_RT_USING_NANO is not set # CONFIG_RT_USING_SMART is not set # CONFIG_RT_USING_AMP is not set -# CONFIG_RT_USING_SMP is not set -CONFIG_RT_CPUS_NR=1 +CONFIG_RT_USING_SMP=y +CONFIG_RT_CPUS_NR=4 CONFIG_RT_ALIGN_SIZE=8 # CONFIG_RT_THREAD_PRIORITY_8 is not set CONFIG_RT_THREAD_PRIORITY_32=y @@ -136,11 +126,13 @@ CONFIG_RT_HOOK_USING_FUNC_PTR=y CONFIG_RT_USING_IDLE_HOOK=y CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 CONFIG_IDLE_THREAD_STACK_SIZE=8192 +CONFIG_SYSTEM_THREAD_STACK_SIZE=8192 CONFIG_RT_USING_TIMER_SOFT=y CONFIG_RT_TIMER_THREAD_PRIO=4 -CONFIG_RT_TIMER_THREAD_STACK_SIZE=4096 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=8192 # CONFIG_RT_USING_TIMER_ALL_SOFT is not set -# CONFIG_RT_USING_CPU_USAGE_TRACER is not set +CONFIG_RT_USING_CPU_USAGE_TRACER=y +CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 # # kservice options @@ -153,6 +145,8 @@ CONFIG_RT_DEBUGING_ASSERT=y CONFIG_RT_DEBUGING_COLOR=y CONFIG_RT_DEBUGING_CONTEXT=y # CONFIG_RT_DEBUGING_AUTO_INIT is not set +# CONFIG_RT_DEBUGING_SPINLOCK is not set +# CONFIG_RT_DEBUGING_CRITICAL is not set # CONFIG_RT_USING_CI_ACTION is not set # @@ -188,14 +182,14 @@ CONFIG_RT_USING_HEAP=y CONFIG_RT_USING_DEVICE=y CONFIG_RT_USING_DEVICE_OPS=y -# CONFIG_RT_USING_INTERRUPT_INFO is not set +CONFIG_RT_USING_INTERRUPT_INFO=y # CONFIG_RT_USING_THREADSAFE_PRINTF is not set CONFIG_RT_USING_CONSOLE=y CONFIG_RT_CONSOLEBUF_SIZE=512 CONFIG_RT_CONSOLE_DEVICE_NAME="uart1" CONFIG_RT_USING_CONSOLE_OUTPUT_CTL=y CONFIG_RT_VER_NUM=0x50300 -# CONFIG_RT_USING_STDC_ATOMIC is not set +CONFIG_RT_USING_STDC_ATOMIC=y CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32 # end of RT-Thread Kernel @@ -206,7 +200,7 @@ CONFIG_ARCH_TEXT_OFFSET=0x200000 CONFIG_ARCH_RAM_OFFSET=0 CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -# CONFIG_ARCH_USING_GENERIC_CPUID is not set +CONFIG_ARCH_USING_GENERIC_CPUID=y CONFIG_ARCH_HEAP_SIZE=0x4000000 CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 # end of AArch64 Architecture Configuration @@ -219,6 +213,7 @@ CONFIG_ARCH_ARM=y CONFIG_ARCH_ARM_MMU=y CONFIG_ARCH_ARMV8=y CONFIG_ARCH_USING_ASID=y +CONFIG_ARCH_USING_HW_THREAD_SELF=y CONFIG_ARCH_USING_IRQ_CTX_LIST=y # @@ -226,7 +221,7 @@ CONFIG_ARCH_USING_IRQ_CTX_LIST=y # CONFIG_RT_USING_COMPONENTS_INIT=y CONFIG_RT_USING_USER_MAIN=y -CONFIG_RT_MAIN_THREAD_STACK_SIZE=4096 +CONFIG_RT_MAIN_THREAD_STACK_SIZE=8192 CONFIG_RT_MAIN_THREAD_PRIORITY=10 # CONFIG_RT_USING_LEGACY is not set CONFIG_RT_USING_MSH=y @@ -234,7 +229,7 @@ CONFIG_RT_USING_FINSH=y CONFIG_FINSH_USING_MSH=y CONFIG_FINSH_THREAD_NAME="tshell" CONFIG_FINSH_THREAD_PRIORITY=20 -CONFIG_FINSH_THREAD_STACK_SIZE=4096 +CONFIG_FINSH_THREAD_STACK_SIZE=8192 CONFIG_FINSH_USING_HISTORY=y CONFIG_FINSH_HISTORY_LINES=5 # CONFIG_FINSH_USING_WORD_OPERATION is not set @@ -254,12 +249,9 @@ CONFIG_FINSH_USING_OPTION_COMPLETION=y CONFIG_RT_USING_DFS=y CONFIG_DFS_USING_POSIX=y CONFIG_DFS_USING_WORKDIR=y -# CONFIG_RT_USING_DFS_MNTTABLE is not set CONFIG_DFS_FD_MAX=16 -CONFIG_RT_USING_DFS_V1=y -# CONFIG_RT_USING_DFS_V2 is not set -CONFIG_DFS_FILESYSTEMS_MAX=2 -CONFIG_DFS_FILESYSTEM_TYPES_MAX=2 +# CONFIG_RT_USING_DFS_V1 is not set +CONFIG_RT_USING_DFS_V2=y CONFIG_RT_USING_DFS_ELMFAT=y # @@ -287,11 +279,8 @@ CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 # end of elm-chan's FatFs, Generic FAT Filesystem Module CONFIG_RT_USING_DFS_DEVFS=y -# CONFIG_RT_USING_DFS_9PFS is not set -# CONFIG_RT_USING_DFS_ISO9660 is not set # CONFIG_RT_USING_DFS_ROMFS is not set # CONFIG_RT_USING_DFS_CROMFS is not set -# CONFIG_RT_USING_DFS_RAMFS is not set # CONFIG_RT_USING_DFS_TMPFS is not set # CONFIG_RT_USING_DFS_MQUEUE is not set # end of DFS: device virtual file system @@ -301,62 +290,154 @@ CONFIG_RT_USING_DFS_DEVFS=y # # Device Drivers # -# CONFIG_RT_USING_DM is not set +CONFIG_RT_USING_DM=y # CONFIG_RT_USING_DEV_BUS is not set CONFIG_RT_USING_DEVICE_IPC=y CONFIG_RT_UNAMED_PIPE_NUMBER=64 -# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 CONFIG_RT_USING_SERIAL=y CONFIG_RT_USING_SERIAL_V1=y # CONFIG_RT_USING_SERIAL_V2 is not set # CONFIG_RT_SERIAL_USING_DMA is not set CONFIG_RT_SERIAL_RB_BUFSZ=64 -# CONFIG_RT_USING_SERIAL_BYPASS is not set +CONFIG_RT_USING_SERIAL_BYPASS=y +# CONFIG_RT_SERIAL_EARLY_HVC is not set +CONFIG_RT_SERIAL_PL011=y +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +CONFIG_RT_SERIAL_8250_BCM2835AUX=y # CONFIG_RT_USING_CAN is not set +# CONFIG_RT_USING_ADC is not set CONFIG_RT_USING_CLOCK_TIME=y +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_RT_CLOCK_TIME_ARM_ARCH=y +CONFIG_RT_CLOCK_TIME_BCM2835=y +# CONFIG_RT_USING_ETHERNET is not set CONFIG_RT_USING_I2C=y CONFIG_RT_I2C_DEBUG=y -CONFIG_RT_USING_I2C_BITOPS=y -# CONFIG_RT_I2C_BITOPS_DEBUG is not set +# CONFIG_RT_USING_I2C_BITOPS is not set # CONFIG_RT_USING_SOFT_I2C is not set +CONFIG_RT_I2C_BCM2835=y +# CONFIG_RT_I2C_BRCMSTB is not set # CONFIG_RT_USING_PHY is not set # CONFIG_RT_USING_PHY_V2 is not set -# CONFIG_RT_USING_ADC is not set # CONFIG_RT_USING_DAC is not set -# CONFIG_RT_USING_NULL is not set -# CONFIG_RT_USING_ZERO is not set -# CONFIG_RT_USING_RANDOM is not set -# CONFIG_RT_USING_PWM is not set +CONFIG_RT_USING_NULL=y +CONFIG_RT_USING_ZERO=y +CONFIG_RT_USING_RANDOM=y +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_BCM2835=y +# CONFIG_RT_PWM_BRCMSTB is not set +# CONFIG_RT_PWM_RP1 is not set # CONFIG_RT_USING_PULSE_ENCODER is not set # CONFIG_RT_USING_INPUT_CAPTURE is not set -# CONFIG_RT_USING_MTD_NOR is not set +CONFIG_RT_USING_MTD_NOR=y +# CONFIG_RT_USING_MTD_NOR_CFI is not set +CONFIG_RT_USING_MTD_NOR_SPI=y # CONFIG_RT_USING_MTD_NAND is not set # CONFIG_RT_USING_PM is not set -# CONFIG_RT_USING_RTC is not set +CONFIG_RT_USING_RTC=y +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=8192 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_DS1302 is not set +CONFIG_RT_RTC_DS1307=y +# CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +# CONFIG_RT_RTC_PCF8523 is not set +# CONFIG_RT_RTC_PCF8563 is not set +# CONFIG_RT_RTC_PL031 is not set +# CONFIG_RT_RTC_RX8010 is not set +# CONFIG_RT_RTC_RPI is not set CONFIG_RT_USING_SDIO=y -CONFIG_RT_SDIO_STACK_SIZE=2048 +CONFIG_RT_SDIO_STACK_SIZE=8192 CONFIG_RT_SDIO_THREAD_PRIORITY=15 -CONFIG_RT_MMCSD_STACK_SIZE=4096 +CONFIG_RT_MMCSD_STACK_SIZE=8192 CONFIG_RT_MMCSD_THREAD_PRIORITY=22 CONFIG_RT_MMCSD_MAX_PARTITION=16 -CONFIG_RT_SDIO_DEBUG=y -# CONFIG_RT_USING_SDHCI is not set +# CONFIG_RT_SDIO_DEBUG is not set +CONFIG_RT_USING_SDHCI=y +# CONFIG_RT_SDIO_DW_MMC is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +# CONFIG_RT_SDIO_SDHCI_BRCMSTB is not set +CONFIG_RT_SDIO_SDHCI_IPROC=y CONFIG_RT_USING_SPI=y CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SPI_BITOPS is not set # CONFIG_RT_USING_SOFT_SPI is not set # CONFIG_RT_USING_QSPI is not set # CONFIG_RT_USING_SPI_MSD is not set -# CONFIG_RT_USING_SFUD is not set +CONFIG_RT_USING_SFUD=y +CONFIG_RT_SFUD_USING_SFDP=y +CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y +# CONFIG_RT_SFUD_USING_QSPI is not set +CONFIG_RT_SFUD_SPI_MAX_HZ=50000000 +# CONFIG_RT_DEBUG_SFUD is not set # CONFIG_RT_USING_ENC28J60 is not set # CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_BCM2835=y +# CONFIG_RT_SPI_BCM2835AUX is not set CONFIG_RT_USING_WDT=y -# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_WDT_DW is not set +CONFIG_RT_WDT_BCM2835=y +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=2 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=2048 +CONFIG_RT_AUDIO_BCM2835_I2S=y # CONFIG_RT_USING_SENSOR is not set # CONFIG_RT_USING_TOUCH is not set -# CONFIG_RT_USING_LCD is not set -# CONFIG_RT_USING_HWCRYPTO is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +# CONFIG_RT_GRAPHIC_BACKLIGHT is not set +CONFIG_RT_GRAPHIC_FB=y +# CONFIG_RT_GRAPHIC_FB_ILI9486 is not set +# CONFIG_RT_GRAPHIC_FB_SIMPLE is not set +CONFIG_RT_GRAPHIC_FB_BCM2708=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224=y +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH="../dm/graphic/logo/logo-raspi-clut224.ppm" +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +# CONFIG_RT_HWCRYPTO_USING_AES is not set +# CONFIG_RT_HWCRYPTO_USING_DES is not set +# CONFIG_RT_HWCRYPTO_USING_3DES is not set +# CONFIG_RT_HWCRYPTO_USING_RC4 is not set +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set +CONFIG_RT_HWCRYPTO_RNG_BCM2835=y +# CONFIG_RT_HWCRYPTO_RNG_IPROC_RNG200 is not set # CONFIG_RT_USING_WIFI is not set +# CONFIG_RT_USING_PTP is not set +CONFIG_RT_USING_LED=y +CONFIG_RT_LED_GPIO=y +# CONFIG_RT_LED_PWM is not set +# CONFIG_RT_LED_SYSCON is not set +# CONFIG_RT_USING_INPUT is not set +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_PIC is not set +CONFIG_RT_MBOX_BCM2835=y +# CONFIG_RT_USING_HWSPINLOCK is not set +# CONFIG_RT_USING_RPMSG is not set +CONFIG_RT_USING_PHYE=y +CONFIG_RT_PHYE_GENERIC_USB=y +# CONFIG_RT_USING_ATA is not set +# CONFIG_RT_USING_NVME is not set CONFIG_RT_USING_BLK=y # @@ -366,11 +447,93 @@ CONFIG_RT_BLK_PARTITION_DFS=y CONFIG_RT_BLK_PARTITION_EFI=y # end of Partition Types -# CONFIG_RT_USING_REGULATOR is not set +# CONFIG_RT_USING_SCSI is not set +CONFIG_RT_USING_FIRMWARE=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set +# CONFIG_RT_FIRMWARE_ARM_SCMI is not set +CONFIG_RT_FIRMWARE_RASPBERRYPI=y +# CONFIG_RT_USING_TEE is not set +# CONFIG_RT_USING_HWCACHE is not set +# CONFIG_RT_USING_DVFS is not set +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_FAN53555 is not set +CONFIG_RT_REGULATOR_FIXED=y +CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set +CONFIG_RT_USING_RESET=y +# CONFIG_RT_RESET_SIMPLE is not set +# CONFIG_RT_RESET_BRCMSTB_RESCAL is not set +# CONFIG_RT_RESET_BRCMSTB is not set +# CONFIG_RT_RESET_RASPBERRYPI is not set + +# +# Power Management (PM) Domains device drivers +# +CONFIG_RT_PMDOMAIN_BCM2835=y +CONFIG_RT_PMDOMAIN_RASPBERRYPI=y +# end of Power Management (PM) Domains device drivers + +# CONFIG_RT_USING_POWER_RESET is not set # CONFIG_RT_USING_POWER_SUPPLY is not set +CONFIG_RT_USING_THERMAL=y + +# +# Thermal Sensors Drivers +# +CONFIG_RT_THERMAL_BCM2835=y +# CONFIG_RT_THERMAL_BCM2711 is not set + +# +# Thermal Cool Drivers +# +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set +# CONFIG_RT_THERMAL_COOL_PWM_FAN is not set # CONFIG_RT_USING_VIRTIO is not set +CONFIG_RT_USING_NVMEM=y +CONFIG_RT_NVMEM_RASPBERRYPI_OTP=y +CONFIG_RT_USING_DMA=y +# CONFIG_RT_DMA_PL330 is not set +# CONFIG_RT_DMA_DW_AXI_DMAC is not set +CONFIG_RT_DMA_BCM2835=y +CONFIG_RT_USING_MFD=y +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_BCM2835_PM=y +# CONFIG_RT_MFD_RPI_SENSE is not set +CONFIG_RT_USING_OFW=y +# CONFIG_RT_USING_BUILTIN_FDT is not set +CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 +CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 +# CONFIG_RT_USING_PCI is not set +CONFIG_RT_USING_PIC=y +# CONFIG_RT_USING_PIC_STATISTICS is not set +CONFIG_MAX_HANDLERS=256 +# CONFIG_RT_PIC_ARM_GIC is not set +# CONFIG_RT_PIC_ARM_GIC_V3 is not set +CONFIG_RT_PIC_BCM2835_INTC=y +CONFIG_RT_PIC_BCM2836_L1_INTC=y +# CONFIG_RT_PIC_BRCMSTB_L2_IRQ is not set CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_BCM_VIRT=y +# CONFIG_RT_PIN_BRCMSTB is not set +CONFIG_RT_PIN_RASPBERRYPI_EXP=y +CONFIG_RT_USING_PINCTRL=y +# CONFIG_RT_PINCTRL_SINGLE is not set +# CONFIG_RT_PINCTRL_BCM2712 is not set +CONFIG_RT_PINCTRL_BCM2835=y +# CONFIG_RT_PINCTRL_RP1 is not set +CONFIG_RT_USING_CLK=y +# CONFIG_RT_CLK_BCM2711_DVP is not set +CONFIG_RT_CLK_BCM2835=y +CONFIG_RT_CLK_RASPBERRYPI=y +# CONFIG_RT_CLK_RP1 is not set # CONFIG_RT_USING_CHERRYUSB is not set + +# +# SoC (System on Chip) Drivers +# +CONFIG_RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR=y +# end of SoC (System on Chip) Drivers # end of Device Drivers # @@ -395,10 +558,20 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # # POSIX (Portable Operating System Interface) layer # -# CONFIG_RT_USING_POSIX_FS is not set -# CONFIG_RT_USING_POSIX_DELAY is not set -# CONFIG_RT_USING_POSIX_CLOCK is not set -# CONFIG_RT_USING_POSIX_TIMER is not set +CONFIG_RT_USING_POSIX_FS=y +CONFIG_RT_USING_POSIX_DEVIO=y +CONFIG_RT_USING_POSIX_STDIO=y +CONFIG_RT_USING_POSIX_POLL=y +# CONFIG_RT_USING_POSIX_SELECT is not set +# CONFIG_RT_USING_POSIX_EVENTFD is not set +# CONFIG_RT_USING_POSIX_TIMERFD is not set +# CONFIG_RT_USING_POSIX_SOCKET is not set +CONFIG_RT_USING_POSIX_TERMIOS=y +# CONFIG_RT_USING_POSIX_AIO is not set +# CONFIG_RT_USING_POSIX_MMAN is not set +CONFIG_RT_USING_POSIX_DELAY=y +CONFIG_RT_USING_POSIX_CLOCK=y +CONFIG_RT_USING_POSIX_TIMER=y # CONFIG_RT_USING_PTHREADS is not set # CONFIG_RT_USING_MODULE is not set @@ -421,9 +594,90 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # # Network # -# CONFIG_RT_USING_SAL is not set -# CONFIG_RT_USING_NETDEV is not set -# CONFIG_RT_USING_LWIP is not set +CONFIG_RT_USING_SAL=y +CONFIG_SAL_INTERNET_CHECK=y +CONFIG_SOCKET_TABLE_STEP_LEN=4 + +# +# Docking with protocol stacks +# +CONFIG_SAL_USING_LWIP=y +# CONFIG_SAL_USING_AT is not set +# CONFIG_SAL_USING_TLS is not set +# end of Docking with protocol stacks + +CONFIG_SAL_USING_POSIX=y +CONFIG_RT_USING_NETDEV=y +CONFIG_NETDEV_USING_IFCONFIG=y +CONFIG_NETDEV_USING_PING=y +CONFIG_NETDEV_USING_NETSTAT=y +CONFIG_NETDEV_USING_AUTO_DEFAULT=y +# CONFIG_NETDEV_USING_LINK_STATUS_CALLBACK is not set +# CONFIG_NETDEV_USING_IPV6 is not set +CONFIG_NETDEV_IPV4=1 +CONFIG_NETDEV_IPV6=0 +CONFIG_RT_USING_LWIP=y +# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set +# CONFIG_RT_USING_LWIP141 is not set +# CONFIG_RT_USING_LWIP203 is not set +CONFIG_RT_USING_LWIP212=y +# CONFIG_RT_USING_LWIP_LATEST is not set +CONFIG_RT_USING_LWIP_VER_NUM=0x20102 +# CONFIG_RT_USING_LWIP_IPV6 is not set +CONFIG_RT_LWIP_MEM_ALIGNMENT=8 +CONFIG_RT_LWIP_IGMP=y +CONFIG_RT_LWIP_ICMP=y +# CONFIG_RT_LWIP_SNMP is not set +CONFIG_RT_LWIP_DNS=y +CONFIG_RT_LWIP_DHCP=y +CONFIG_IP_SOF_BROADCAST=1 +CONFIG_IP_SOF_BROADCAST_RECV=1 + +# +# Static IPv4 Address +# +CONFIG_RT_LWIP_IPADDR="192.168.1.30" +CONFIG_RT_LWIP_GWADDR="192.168.1.1" +CONFIG_RT_LWIP_MSKADDR="255.255.255.0" +# end of Static IPv4 Address + +CONFIG_RT_LWIP_UDP=y +CONFIG_RT_LWIP_TCP=y +CONFIG_RT_LWIP_RAW=y +# CONFIG_RT_LWIP_PPP is not set +CONFIG_RT_MEMP_NUM_NETCONN=8 +CONFIG_RT_LWIP_PBUF_NUM=16 +CONFIG_RT_LWIP_RAW_PCB_NUM=4 +CONFIG_RT_LWIP_UDP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_SEG_NUM=40 +CONFIG_RT_LWIP_TCP_SND_BUF=8196 +CONFIG_RT_LWIP_TCP_WND=8196 +CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10 +CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8 +CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=16384 +CONFIG_LWIP_NO_RX_THREAD=y +CONFIG_LWIP_NO_TX_THREAD=y +CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12 +CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192 +CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8 +# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set +CONFIG_LWIP_NETIF_STATUS_CALLBACK=1 +CONFIG_LWIP_NETIF_LINK_CALLBACK=1 +CONFIG_RT_LWIP_NETIF_NAMESIZE=6 +CONFIG_SO_REUSE=1 +CONFIG_LWIP_SO_RCVTIMEO=1 +CONFIG_LWIP_SO_SNDTIMEO=1 +CONFIG_LWIP_SO_RCVBUF=1 +CONFIG_LWIP_SO_LINGER=0 +# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=0 +# CONFIG_RT_LWIP_STATS is not set +# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set +CONFIG_RT_LWIP_USING_PING=y +# CONFIG_LWIP_USING_DHCPD is not set +# CONFIG_RT_LWIP_ENABLE_USER_HOOKS is not set +# CONFIG_RT_LWIP_DEBUG is not set # CONFIG_RT_USING_AT is not set # end of Network @@ -441,7 +695,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0 # CONFIG_RT_USING_ULOG is not set # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set -# CONFIG_RT_USING_RESOURCE_ID is not set +CONFIG_RT_USING_RESOURCE_ID=y CONFIG_RT_USING_ADT=y CONFIG_RT_USING_ADT_AVL=y CONFIG_RT_USING_ADT_BITMAP=y @@ -456,7 +710,8 @@ CONFIG_RT_USING_ADT_REF=y # CONFIG_RT_PAGE_MPR_SIZE_DYNAMIC is not set CONFIG_RT_PAGE_AFFINITY_BLOCK_SIZE=0x1000 CONFIG_RT_PAGE_MAX_ORDER=11 -# CONFIG_RT_USING_MEMBLOCK is not set +CONFIG_RT_USING_MEMBLOCK=y +CONFIG_RT_INIT_MEMORY_REGIONS=128 # # Debugging @@ -475,6 +730,7 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # end of Using USB legacy version # CONFIG_RT_USING_FDT is not set +# CONFIG_RT_USING_LEGACY_VIRTIO is not set # CONFIG_RT_USING_RUST is not set # end of RT-Thread Components @@ -677,7 +933,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_U8G2 is not set # end of u8g2: a monochrome graphic library -# CONFIG_PKG_USING_NES_SIMULATOR is not set # CONFIG_PKG_USING_OPENMV is not set # CONFIG_PKG_USING_MUPDF is not set # CONFIG_PKG_USING_STEMWIN is not set @@ -702,9 +957,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # tools packages # -# CONFIG_PKG_USING_VECTOR is not set -# CONFIG_PKG_USING_SORCH is not set -# CONFIG_PKG_USING_DICT is not set # CONFIG_PKG_USING_CMBACKTRACE is not set # CONFIG_PKG_USING_MCOREDUMP is not set # CONFIG_PKG_USING_EASYFLASH is not set @@ -753,9 +1005,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_RVBACKTRACE is not set # CONFIG_PKG_USING_HPATCHLITE is not set # CONFIG_PKG_USING_THREAD_METRIC is not set -# CONFIG_PKG_USING_UORB is not set -# CONFIG_PKG_USING_RT_TUNNEL is not set -# CONFIG_PKG_USING_VIRTUAL_TERMINAL is not set # end of tools packages # @@ -850,9 +1099,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_R_RHEALSTONE is not set # CONFIG_PKG_USING_HEARTBEAT is not set # CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set -# CONFIG_PKG_USING_CHERRYECAT is not set -# CONFIG_PKG_USING_EVENT_LOOP is not set -# CONFIG_PKG_USING_THREAD_MANAGER is not set # end of system packages # @@ -998,7 +1244,9 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # NUVOTON Drivers # +# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set # CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set # end of NUVOTON Drivers # @@ -1006,24 +1254,7 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set # CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32_RISCV_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32VW55X_WIFI is not set # end of GD32 Drivers - -# -# HPMicro SDK -# -# CONFIG_PKG_USING_HPM_SDK is not set -# end of HPMicro SDK - -# -# FT32 HAL & SDK Drivers -# -# CONFIG_PKG_USING_FT32F0_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F0_CMSIS_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_CMSIS_DRIVER is not set -# end of FT32 HAL & SDK Drivers # end of HAL & SDK Drivers # @@ -1069,11 +1300,9 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_RT3020 is not set # CONFIG_PKG_USING_MLX90632 is not set # CONFIG_PKG_USING_MLX90382 is not set -# CONFIG_PKG_USING_MLX90384 is not set # CONFIG_PKG_USING_MLX90393 is not set # CONFIG_PKG_USING_MLX90392 is not set # CONFIG_PKG_USING_MLX90394 is not set -# CONFIG_PKG_USING_MLX90396 is not set # CONFIG_PKG_USING_MLX90397 is not set # CONFIG_PKG_USING_MS5611 is not set # CONFIG_PKG_USING_MAX31865 is not set @@ -1102,7 +1331,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_P3T1755 is not set # CONFIG_PKG_USING_QMI8658 is not set # CONFIG_PKG_USING_ICM20948 is not set -# CONFIG_PKG_USING_SCD4X is not set # end of sensors drivers # @@ -1120,7 +1348,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_CST812T is not set # end of touch drivers -# CONFIG_PKG_USING_LCD_SPI_DRIVER is not set # CONFIG_PKG_USING_REALTEK_AMEBA is not set # CONFIG_PKG_USING_BUTTON is not set # CONFIG_PKG_USING_PCF8574 is not set @@ -1200,13 +1427,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_IC74HC165 is not set # CONFIG_PKG_USING_IST8310 is not set # CONFIG_PKG_USING_ST7789_SPI is not set -# CONFIG_PKG_USING_CAN_UDS is not set -# CONFIG_PKG_USING_ISOTP_C is not set -# CONFIG_PKG_USING_IKUNLED is not set -# CONFIG_PKG_USING_INS5T8025 is not set -# CONFIG_PKG_USING_IRUART is not set -# CONFIG_PKG_USING_ST7305 is not set -# CONFIG_PKG_USING_TM1668 is not set # CONFIG_PKG_USING_SPI_TOOLS is not set # end of peripheral libraries and drivers @@ -1546,41 +1766,4 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # end of Arduino libraries # end of RT-Thread online packages -CONFIG_BCM2836_SOC=y CONFIG_SOC_BCM283x=y - -# -# Hardware Drivers Config -# - -# -# BCM Peripheral Drivers -# -CONFIG_BSP_USING_UART=y -# CONFIG_RT_USING_UART0 is not set -CONFIG_RT_USING_UART1=y -CONFIG_BSP_USING_PIN=y -CONFIG_BSP_USING_CORETIMER=y -CONFIG_BSP_USING_SYSTIMER=y -CONFIG_RT_USING_SYSTIMER1=y -CONFIG_RT_USING_SYSTIMER3=y -CONFIG_BSP_USING_I2C=y -# CONFIG_BSP_USING_I2C0 is not set -CONFIG_BSP_USING_I2C1=y -CONFIG_BSP_USING_SPI=y -CONFIG_BSP_USING_SPI0_BUS=y -CONFIG_BSP_USING_SPI0_DEVICE0=y -# CONFIG_BSP_USING_SPI0_DEVICE1 is not set -CONFIG_BSP_USING_WDT=y -# CONFIG_BSP_USING_RTC is not set -CONFIG_BSP_USING_SDIO=y -CONFIG_BSP_USING_SDIO0=y -# end of BCM Peripheral Drivers - -# -# Board Peripheral Drivers -# -CONFIG_BSP_USING_HDMI=y -CONFIG_BSP_USING_HDMI_DISPLAY=y -# end of Board Peripheral Drivers -# end of Hardware Drivers Config diff --git a/bsp/raspberry-pi/raspi3-64/Kconfig b/bsp/raspberry-pi/raspi3-64/Kconfig index 7a1dfd12f0..7e344d89b9 100644 --- a/bsp/raspberry-pi/raspi3-64/Kconfig +++ b/bsp/raspberry-pi/raspi3-64/Kconfig @@ -6,21 +6,18 @@ RTT_DIR := ../../.. PKGS_DIR := packages +SOC_DM_DIR := $BSP_DIR/../dm/ + +source "$(SOC_DM_DIR)/Kconfig" source "$(RTT_DIR)/Kconfig" osource "$PKGS_DIR/Kconfig" -config BCM2836_SOC +config SOC_BCM283x bool select ARCH_ARMV8 select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN select ARCH_CPU_64BIT select RT_USING_CACHE - select SOC_BCM283x + select RT_USING_STDC_ATOMIC default y - -config SOC_BCM283x - bool - default y - -rsource "driver/Kconfig" diff --git a/bsp/raspberry-pi/raspi3-64/SConscript b/bsp/raspberry-pi/raspi3-64/SConscript index c7ef7659ec..40e1864cf6 100644 --- a/bsp/raspberry-pi/raspi3-64/SConscript +++ b/bsp/raspberry-pi/raspi3-64/SConscript @@ -11,4 +11,6 @@ for d in list: if os.path.isfile(os.path.join(path, 'SConscript')): objs = objs + SConscript(os.path.join(d, 'SConscript')) +objs = objs + SConscript(cwd + '/../dm/SConscript', variant_dir = 'dm', duplicate = 0) + Return('objs') diff --git a/bsp/raspberry-pi/raspi3-64/SConstruct b/bsp/raspberry-pi/raspi3-64/SConstruct index 33f65e4109..ec6fe0187f 100644 --- a/bsp/raspberry-pi/raspi3-64/SConstruct +++ b/bsp/raspberry-pi/raspi3-64/SConstruct @@ -27,4 +27,3 @@ objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) # make a building DoBuilding(TARGET, objs) - diff --git a/bsp/raspberry-pi/raspi3-64/applications/SConscript b/bsp/raspberry-pi/raspi3-64/applications/SConscript old mode 100644 new mode 100755 index fdf93d4235..c583d3016e --- a/bsp/raspberry-pi/raspi3-64/applications/SConscript +++ b/bsp/raspberry-pi/raspi3-64/applications/SConscript @@ -1,7 +1,7 @@ from building import * cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') + Glob('test/*.c') +src = Glob('*.c') + Glob('*.cpp') CPPPATH = [cwd] group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) diff --git a/bsp/raspberry-pi/raspi3-64/applications/main.c b/bsp/raspberry-pi/raspi3-64/applications/main.c index bd7c917e64..77d2df96c0 100644 --- a/bsp/raspberry-pi/raspi3-64/applications/main.c +++ b/bsp/raspberry-pi/raspi3-64/applications/main.c @@ -9,53 +9,10 @@ */ #include -#include -#include -#include "mbox.h" - -void set_led(int state) //set state LED nyala atau mati -{ - if (state==1) //LED nyala - { - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = 0x00038041; // get serial number command - mbox[3] = 8; // buffer size - mbox[4] = 0; - mbox[5] = 130; // clear output buffer - mbox[6] = 1; - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - } - else if (state==0) //LED mati - { - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = 0x00038041; // get serial number command - mbox[3] = 8; // buffer size - mbox[4] = 0; - mbox[5] = 130; // clear output buffer - mbox[6] = 0; - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - } -} int main(int argc, char** argv) { - int count = 1; - rt_kprintf("Hi, this is RT-Thread!!\n"); - while (count++) - { - set_led(1); - rt_thread_mdelay(500); - set_led(0); - rt_thread_mdelay(500); - } - return RT_EOK; } diff --git a/bsp/raspberry-pi/raspi3-64/applications/mnt.c b/bsp/raspberry-pi/raspi3-64/applications/mnt.c deleted file mode 100644 index 01e97b325b..0000000000 --- a/bsp/raspberry-pi/raspi3-64/applications/mnt.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017-5-30 bernard the first version - */ - -#include - -#ifdef BSP_USING_SDIO0 -#include - -int mnt_init(void) -{ - rt_thread_delay(RT_TICK_PER_SECOND); - if (dfs_mount("sd0", "/", "elm", 0, 0) == 0) - { - rt_kprintf("file system initialization done!\n"); - } - - return 0; -} -INIT_ENV_EXPORT(mnt_init); -#endif - diff --git a/bsp/raspberry-pi/raspi3-64/applications/test/gpio.h b/bsp/raspberry-pi/raspi3-64/applications/test/gpio.h deleted file mode 100644 index 52fa671d0f..0000000000 --- a/bsp/raspberry-pi/raspi3-64/applications/test/gpio.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#define MMIO_BASE 0x3F000000 - -#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) -#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) -#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) -#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) -#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) -#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) -#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) -#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) -#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) -#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) -#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) -#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) -#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) -#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) -#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) -#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) -#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) -#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) diff --git a/bsp/raspberry-pi/raspi3-64/applications/test/uart.c b/bsp/raspberry-pi/raspi3-64/applications/test/uart.c deleted file mode 100644 index b3dd4da7ea..0000000000 --- a/bsp/raspberry-pi/raspi3-64/applications/test/uart.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "gpio.h" - -/* Auxilary mini UART registers */ -#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) -#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) -#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) -#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) -#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) -#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) -#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) -#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) -#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) -#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) -#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) -#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) - -/** - * Set baud rate and characteristics (115200 8N1) and map to GPIO - */ -void uart_init() -{ - register unsigned int r; - - /* initialize UART */ - *AUX_ENABLE |=1; // enable UART1, AUX mini uart - *AUX_MU_CNTL = 0; - *AUX_MU_LCR = 3; // 8 bits - *AUX_MU_MCR = 0; - *AUX_MU_IER = 0; - *AUX_MU_IIR = 0xc6; // disable interrupts - *AUX_MU_BAUD = 270; // 115200 baud - /* map UART1 to GPIO pins */ - r=*GPFSEL1; - r&=~((7<<12)|(7<<15)); // gpio14, gpio15 - r|=(2<<12)|(2<<15); // alt5 - *GPFSEL1 = r; - *GPPUD = 0; // enable pins 14 and 15 - r=150; while(r--) { asm volatile("nop"); } - *GPPUDCLK0 = (1<<14)|(1<<15); - r=150; while(r--) { asm volatile("nop"); } - *GPPUDCLK0 = 0; // flush GPIO setup - *AUX_MU_CNTL = 3; // enable Tx, Rx -} - -/** - * Send a character - */ -void uart_send(unsigned int c) { - /* wait until we can send */ - do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); - /* write the character to the buffer */ - *AUX_MU_IO=c; -} - -/** - * Receive a character - */ -char uart_getc() { - char r; - /* wait until something is in the buffer */ - do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); - /* read it and return */ - r=(char)(*AUX_MU_IO); - /* convert carrige return to newline */ - return r=='\r'?'\n':r; -} - -/** - * Display a string - */ -void uart_puts(char *s) { - while(*s) { - /* convert newline to carrige return + newline */ - if(*s=='\n') - uart_send('\r'); - uart_send(*s++); - } -} diff --git a/bsp/raspberry-pi/raspi3-64/applications/test/uart.h b/bsp/raspberry-pi/raspi3-64/applications/test/uart.h deleted file mode 100644 index 72f8e3151f..0000000000 --- a/bsp/raspberry-pi/raspi3-64/applications/test/uart.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -void uart_init(); -void uart_send(unsigned int c); -char uart_getc(); -void uart_puts(char *s); diff --git a/bsp/raspberry-pi/raspi3-64/driver/Kconfig b/bsp/raspberry-pi/raspi3-64/driver/Kconfig deleted file mode 100644 index 5632f72462..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/Kconfig +++ /dev/null @@ -1,116 +0,0 @@ -menu "Hardware Drivers Config" - menu "BCM Peripheral Drivers" - menuconfig BSP_USING_UART - bool "Using UART" - select RT_USING_SERIAL - default y - - if BSP_USING_UART - config RT_USING_UART0 - bool "Enabel UART 0" - default y - - config RT_USING_UART1 - bool "Enabel UART 1" - default n - endif - - config BSP_USING_PIN - bool "Using PIN" - select RT_USING_PIN - default y - - config BSP_USING_CORETIMER - bool "Using core timer" - select RT_USING_CORETIMER - default y - - menuconfig BSP_USING_SYSTIMER - bool "Enable SYSTIMER" - select RT_USING_CLOCK_TIME - default n - - if BSP_USING_SYSTIMER - config RT_USING_SYSTIMER1 - bool "Enable sys timer1" - default n - config RT_USING_SYSTIMER3 - bool "Enable sys timer3" - 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" - default n - config BSP_USING_I2C1 - bool "Enable I2C1" - default n - endif - - menuconfig BSP_USING_SPI - bool "Enable SPI" - select RT_USING_SPI - default n - - if BSP_USING_SPI - config BSP_USING_SPI0_BUS - bool "Enable SPI0 BUS" - default n - config BSP_USING_SPI0_DEVICE0 - bool "Enable SPI0 DEVICE0" - select BSP_USING_SPI0_BUS - default n - config BSP_USING_SPI0_DEVICE1 - bool "Enable SPI0 DEVICE1" - select BSP_USING_SPI0_BUS - default n - endif - - config BSP_USING_WDT - bool "Enable WDT" - select RT_USING_WDT - default n - - menuconfig BSP_USING_RTC - bool "Enable RTC" - select RT_USING_RTC - default n - - if BSP_USING_RTC - config BSP_USING_ALARM - bool "Enable Alarm" - select RT_USING_ALARM - default n - endif - - menuconfig BSP_USING_SDIO - bool "Enable SDIO" - select RT_USING_SDIO - default n - - if BSP_USING_SDIO - config BSP_USING_SDIO0 - bool "Enable SDIO0" - select RT_USING_SDIO - default n - endif - endmenu - - menu "Board Peripheral Drivers" - menuconfig BSP_USING_HDMI - bool "Enable HDMI" - default n - - if BSP_USING_HDMI - config BSP_USING_HDMI_DISPLAY - bool "HDMI DISPLAY" - default n - endif - endmenu -endmenu diff --git a/bsp/raspberry-pi/raspi3-64/driver/SConscript b/bsp/raspberry-pi/raspi3-64/driver/SConscript index c51b2c42bf..f7e8f47ce8 100644 --- a/bsp/raspberry-pi/raspi3-64/driver/SConscript +++ b/bsp/raspberry-pi/raspi3-64/driver/SConscript @@ -3,29 +3,10 @@ from building import * cwd = GetCurrentDir() -src = Split(''' -board.c -drv_uart.c -mbox.c -''') +src = Glob('*.c') CPPPATH = [cwd] +objs = [] -if GetDepend('BSP_USING_SYSTIMER'): - src += ['drv_timer.c'] -if GetDepend('BSP_USING_PIN'): - src += ['drv_gpio.c'] -if GetDepend('BSP_USING_I2C'): - src += ['drv_i2c.c'] -if GetDepend('BSP_USING_WDT'): - src += ['drv_wdt.c'] -if GetDepend('BSP_USING_SPI'): - src += ['drv_spi.c'] -if GetDepend('BSP_USING_SDIO'): - src += ['drv_sdio.c'] -if GetDepend('BSP_USING_RTC'): - src += ['drv_rtc.c'] -if GetDepend('BSP_USING_HDMI'): - src += ['drv_fb.c'] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/raspberry-pi/raspi3-64/driver/board.c b/bsp/raspberry-pi/raspi3-64/driver/board.c index 614a349973..2519d7ddc2 100644 --- a/bsp/raspberry-pi/raspi3-64/driver/board.c +++ b/bsp/raspberry-pi/raspi3-64/driver/board.c @@ -9,175 +9,10 @@ * 2021-12-28 GuEe-GUI add smp support */ -#include -#include +#include +#include -#include "board.h" -#include "drv_uart.h" -#include "drv_timer.h" - -#include "gtimer.h" -#include "cpuport.h" -#include "interrupt.h" -#include "mmu.h" -#include "raspi.h" - -struct mem_desc platform_mem_desc[] = -{ - {0, 0x6400000, 0, NORMAL_MEM}, - {0xc00000, 0xc01000, 0xc00000, DEVICE_MEM}, /* mbox */ - {0x3f000000, 0x3f200000, 0x3f000000, DEVICE_MEM}, /* timer */ - {0x3f200000, 0x3f216000, 0x3f200000, DEVICE_MEM}, /* uart */ - {0x40000000, 0x40200000, 0x40000000, DEVICE_MEM}, /* core timer */ - {0x3F300000, 0x3F301000, 0x3F300000, DEVICE_MEM}, /* sdio */ - {0x3f804000, 0x3f805000, 0x3f804000, DEVICE_MEM}, /* i2c0 */ - {0x3f205000, 0x3f206000, 0x3f205000, DEVICE_MEM}, /* i2c1 */ -}; - -const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc)/sizeof(platform_mem_desc[0]); - -#if defined(BSP_USING_CORETIMER) || defined(RT_USING_SMP) -static volatile rt_uint64_t timer_step; -#define BSP_USING_CORETIMER -#endif - -void rt_hw_timer_isr(int vector, void *parameter) -{ -#ifdef BSP_USING_CORETIMER - rt_hw_set_gtimer_val(timer_step); -#else - ARM_TIMER_IRQCLR = 0; -#endif - rt_tick_increase(); -} - -rt_uint8_t core_timer_flag; - -void rt_hw_timer_init(void) -{ - rt_hw_interrupt_install(IRQ_ARM_TIMER, rt_hw_timer_isr, RT_NULL, "tick"); - rt_hw_interrupt_umask(IRQ_ARM_TIMER); -#ifdef BSP_USING_CORETIMER - rt_hw_isb(); - timer_step = rt_hw_get_gtimer_frq(); - rt_hw_dsb(); - timer_step /= RT_TICK_PER_SECOND; - - rt_hw_gtimer_enable(); - rt_hw_set_gtimer_val(timer_step); -#ifdef RT_USING_SMP - core_timer_enable(rt_hw_cpu_id()); -#else - core_timer_enable(0); -#endif -#else - __DSB(); - /* timer_clock = apb_clock/(pre_divider + 1) */ - ARM_TIMER_PREDIV = (250 - 1); - - ARM_TIMER_RELOAD = 0; - ARM_TIMER_LOAD = 0; - ARM_TIMER_IRQCLR = 0; - ARM_TIMER_CTRL = 0; - - ARM_TIMER_RELOAD = 10000; - ARM_TIMER_LOAD = 10000; - - /* 23-bit counter, enable interrupt, enable timer */ - ARM_TIMER_CTRL = (1 << 1) | (1 << 5) | (1 << 7); -#endif -} - -void idle_wfi(void) -{ - asm volatile ("wfi"); -} - -/** - * Initialize the Hardware related stuffs. Called from rtthread_startup() - * after interrupt disabled. - */ void rt_hw_board_init(void) { - extern void *MMUTable; - rt_hw_mmu_map_init(&rt_kernel_space, (void*)0x80000000, 0x10000000, MMUTable, 0); - rt_hw_mmu_setup(&rt_kernel_space, platform_mem_desc, platform_mem_desc_size); - - /* initialize hardware interrupt */ - rt_hw_interrupt_init(); // in libcpu/interrupt.c. Set some data structures, no operation on device - - /* initialize uart */ - rt_hw_uart_init(); // driver/drv_uart.c - /* initialize timer for os tick */ - rt_hw_timer_init(); - rt_thread_idle_sethook(idle_wfi); - -#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) - /* set console device */ - rt_console_set_device(RT_CONSOLE_DEVICE_NAME); -#endif - -#ifdef RT_USING_HEAP - /* initialize memory system */ - rt_kprintf("heap: 0x%08x - 0x%08x\n", RT_HW_HEAP_BEGIN, RT_HW_HEAP_END); - rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END); -#endif - -#ifdef RT_USING_COMPONENTS_INIT - rt_components_board_init(); -#endif - -#ifdef RT_USING_SMP - /* install IPI handle */ - rt_hw_ipi_handler_install(IRQ_ARM_MAILBOX, rt_scheduler_ipi_handler); - rt_hw_interrupt_umask(IRQ_ARM_MAILBOX); - enable_cpu_ipi_intr(0); -#endif + rt_hw_common_setup(); } - -#ifdef RT_USING_SMP -static unsigned long cpu_release_paddr[] = -{ - [0] = 0xd8, - [1] = 0xe0, - [2] = 0xe8, - [3] = 0xf0, - [4] = 0 -}; - -void rt_hw_secondary_cpu_up(void) -{ - int i; - extern void secondary_cpu_start(void); - - for (i = 1; i < RT_CPUS_NR && cpu_release_paddr[i]; ++i) - { - __asm__ volatile ("str %0, [%1]"::"rZ"((unsigned long)secondary_cpu_start), "r"(cpu_release_paddr[i])); - rt_hw_dcache_flush_range(cpu_release_paddr[i], sizeof(cpu_release_paddr[i])); - __DSB(); - __SEV(); - } -} - -void secondary_cpu_c_start(void) -{ - int id = rt_hw_cpu_id(); - - rt_hw_mmu_init(); - rt_hw_spin_lock(&_cpus_lock); - - rt_hw_vector_init(); - rt_hw_timer_init(); - enable_cpu_ipi_intr(id); - - rt_kprintf("\rcall cpu %d on success\n", id); - - rt_system_scheduler_start(); -} - -void rt_hw_secondary_cpu_idle_exec(void) -{ - __WFE(); -} - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/board.h b/bsp/raspberry-pi/raspi3-64/driver/board.h index ad5d0007ce..08b8be3396 100644 --- a/bsp/raspberry-pi/raspi3-64/driver/board.h +++ b/bsp/raspberry-pi/raspi3-64/driver/board.h @@ -11,21 +11,6 @@ #ifndef BOARD_H__ #define BOARD_H__ -#include -#include "raspi.h" - -extern unsigned char __bss_start; -extern unsigned char __bss_end; - -#define RT_HW_HEAP_BEGIN (void*)&__bss_end -#define RT_HW_HEAP_END (void*)(RT_HW_HEAP_BEGIN + 64 * 1024 * 1024) - -#ifndef RT_USING_SMART -#define PV_OFFSET 0 -#define KERNEL_VADDR_START 0 -#endif - void rt_hw_board_init(void); -#endif - +#endif /* BOARD_H__ */ diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_fb.c b/bsp/raspberry-pi/raspi3-64/driver/drv_fb.c deleted file mode 100644 index 06056bf7c1..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_fb.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-08-29 zdzn first version - */ - -#include -#include -#include -#include -#include "mbox.h" -#include "drv_fb.h" -#include "mmu.h" -#include "cache.h" - -#define LCD_WIDTH (800) -#define LCD_HEIGHT (480) -#define LCD_DEPTH (32) -#define LCD_BPP (32) - -#define TAG_ALLOCATE_BUFFER 0x00040001 -#define TAG_SET_PHYS_WIDTH_HEIGHT 0x00048003 -#define TAG_SET_VIRT_WIDTH_HEIGHT 0x00048004 -#define TAG_SET_DEPTH 0x00048005 -#define TAG_SET_PIXEL_ORDER 0x00048006 -#define TAG_GET_PITCH 0x00040008 -#define TAG_SET_VIRT_OFFSET 0x00048009 -#define TAG_END 0x00000000 - - -enum { - MBOX_TAG_FB_GET_GPIOVIRT = 0x00040010, - MBOX_TAG_FB_ALLOCATE_BUFFER = 0x00040001, - MBOX_TAG_FB_RELEASE_BUFFER = 0x00048001, - MBOX_TAG_FB_BLANK_SCREEN = 0x00040002, - MBOX_TAG_FB_GET_PHYS_WH = 0x00040003, - MBOX_TAG_FB_TEST_PHYS_WH = 0x00044003, - MBOX_TAG_FB_SET_PHYS_WH = 0x00048003, - MBOX_TAG_FB_GET_VIRT_WH = 0x00040004, - MBOX_TAG_FB_TEST_VIRT_WH = 0x00044004, - MBOX_TAG_FB_SET_VIRT_WH = 0x00048004, - MBOX_TAG_FB_GET_DEPTH = 0x00040005, - MBOX_TAG_FB_TEST_DEPTH = 0x00044005, - MBOX_TAG_FB_SET_DEPTH = 0x00048005, - MBOX_TAG_FB_GET_PIXEL_ORDER = 0x00040006, - MBOX_TAG_FB_TEST_PIXEL_ORDER = 0x00044006, - MBOX_TAG_FB_SET_PIXEL_ORDER = 0x00048006, - MBOX_TAG_FB_GET_ALPHA_MODE = 0x00040007, - MBOX_TAG_FB_TEST_ALPHA_MODE = 0x00044007, - MBOX_TAG_FB_SET_ALPHA_MODE = 0x00048007, - MBOX_TAG_FB_GET_PITCH = 0x00040008, - MBOX_TAG_FB_GET_VIRT_OFFSET = 0x00040009, - MBOX_TAG_FB_TEST_VIRT_OFFSET = 0x00044009, - MBOX_TAG_FB_SET_VIRT_OFFSET = 0x00048009, - MBOX_TAG_FB_GET_OVERSCAN = 0x0004000a, - MBOX_TAG_FB_TEST_OVERSCAN = 0x0004400a, - MBOX_TAG_FB_SET_OVERSCAN = 0x0004800a, - MBOX_TAG_FB_GET_PALETTE = 0x0004000b, - MBOX_TAG_FB_TEST_PALETTE = 0x0004400b, - MBOX_TAG_FB_SET_PALETTE = 0x0004800b, -}; - -#define LCD_DEVICE(dev) (struct rt_hdmi_fb_device*)(dev) - -static struct rt_hdmi_fb_device _hdmi; - -typedef rt_uint16_t color_t; - -rt_err_t hdmi_fb_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; -} - -rt_err_t hdmi_fb_close(rt_device_t dev) -{ - return RT_EOK; -} - -rt_size_t hdmi_fb_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size) -{ - return 0; -} - -rt_size_t hdmi_fb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - return size; -} - -rt_err_t hdmi_fb_control(rt_device_t dev, int cmd, void *args) -{ - struct rt_hdmi_fb_device *lcd = LCD_DEVICE(dev); - switch (cmd) - { - case RTGRAPHIC_CTRL_RECT_UPDATE: - { - struct rt_device_rect_info *info = (struct rt_device_rect_info*)args; - info = info; - } - break; - - case RTGRAPHIC_CTRL_GET_INFO: - { - struct rt_device_graphic_info* info = (struct rt_device_graphic_info*)args; - - RT_ASSERT(info != RT_NULL); - info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888; - info->bits_per_pixel= LCD_DEPTH; - info->width = lcd->width; - info->height = lcd->height; - info->framebuffer = lcd->fb; - } - break; - } - return RT_EOK; -} - -const static struct rt_device_ops hdmi_fb_ops = -{ - RT_NULL, - hdmi_fb_open, - hdmi_fb_close, - hdmi_fb_read, - hdmi_fb_write, - hdmi_fb_control -}; - -rt_err_t rt_hdmi_fb_device_init(struct rt_hdmi_fb_device *hdmi_fb, const char *name) -{ - struct rt_device *device; - RT_ASSERT(hdmi_fb != RT_NULL); - - device = &hdmi_fb->parent; - - /* set device type */ - device->type = RT_Device_Class_Graphic; - /* initialize device interface */ -#ifdef RT_USING_DEVICE_OPS - device->ops = &hdmi_fb_ops; -#else - device->init = RT_NULL; - device->open = hdmi_fb_open; - device->close = hdmi_fb_close; - device->read = hdmi_fb_read; - device->write = hdmi_fb_write; - device->control = hdmi_fb_control; -#endif - - /* register to device manager */ - rt_device_register(device, name, RT_DEVICE_FLAG_RDWR); - - return RT_EOK; -} - -rt_uint32_t bcm283x_mbox_fb_get_gpiovirt(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_GET_GPIOVIRT; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return (mbox[5] & 0x3fffffff); -} - -rt_uint32_t bcm283x_mbox_fb_get_pitch(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_GET_PITCH; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return mbox[5]; -} - -void bcm283x_mbox_fb_set_porder(int rgb) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_PIXEL_ORDER; - mbox[3] = 4; // buffer size - mbox[4] = 4; // len - - mbox[5] = rgb; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - -void bcm283x_mbox_fb_setoffset(int xoffset, int yoffset) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_VIRT_OFFSET; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = xoffset; // id - mbox[6] = yoffset; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - - -void bcm283x_mbox_fb_setalpha(int alpha) -{ - - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_ALPHA_MODE; - mbox[3] = 4; // buffer size - mbox[4] = 4; // len - - mbox[5] = alpha; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - -void *bcm283x_mbox_fb_alloc(int width, int height, int bpp, int nrender) -{ - mbox[0] = 4 * 35; - mbox[1] = MBOX_REQUEST; - - mbox[2] = TAG_ALLOCATE_BUFFER;//get framebuffer, gets alignment on request - mbox[3] = 8; //size - mbox[4] = 4; //len - mbox[5] = 4096; //The design of MBOX driver forces us to give the virtual address 0x3C100000 - mbox[6] = 0; //FrameBufferInfo.size - - mbox[7] = TAG_SET_PHYS_WIDTH_HEIGHT; - mbox[8] = 8; - mbox[9] = 8; - mbox[10] = width; - mbox[11] = height; - - mbox[12] = TAG_SET_VIRT_WIDTH_HEIGHT; - mbox[13] = 8; - mbox[14] = 8; - mbox[15] = width; - mbox[16] = height * nrender; - - mbox[17] = TAG_SET_DEPTH; - mbox[18] = 4; - mbox[19] = 4; - mbox[20] = bpp; - - mbox[21] = TAG_SET_PIXEL_ORDER; - mbox[22] = 4; - mbox[23] = 0; - mbox[24] = 0; //RGB, not BGR preferably - - mbox[25] = TAG_GET_PITCH; - mbox[26] = 4; - mbox[27] = 0; - mbox[28] = 0; - - mbox[29] = TAG_SET_VIRT_OFFSET; - mbox[30] = 8; - mbox[31] = 8; - mbox[32] = 0; - mbox[33] = 0; - - mbox[34] = TAG_END; - - mbox_call(MBOX_CH_PROP, MMU_DISABLE); - - return (void *)((rt_uint64_t)(mbox[5] & 0x3fffffff)); -} - -int hdmi_fb_init(void) -{ - _hdmi.fb = (rt_uint8_t *)bcm283x_mbox_fb_alloc(LCD_WIDTH, LCD_HEIGHT, LCD_BPP, 1); - bcm283x_mbox_fb_setoffset(0, 0); - bcm283x_mbox_fb_set_porder(0); - _hdmi.width = LCD_WIDTH; - _hdmi.height = LCD_HEIGHT; - _hdmi.depth = LCD_DEPTH; - _hdmi.pitch = 0; - _hdmi.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888; - - // rt_hw_mmu_map(&mmu_info, (unsigned long)_hdmi.fb, (void *)0x200000, DEVICE_MEM); - - rt_hw_cpu_dcache_invalidate((unsigned long)_hdmi.fb,LCD_WIDTH * LCD_HEIGHT * 3); - - //rt_kprintf("_hdmi.fb is %p\n", _hdmi.fb); - rt_hdmi_fb_device_init(&_hdmi, "lcd"); - - return 0; -} - -INIT_DEVICE_EXPORT(hdmi_fb_init); diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_fb.h b/bsp/raspberry-pi/raspi3-64/driver/drv_fb.h deleted file mode 100644 index 1074dc79c7..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_fb.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-08-29 zdzn first version - */ -#ifndef __DRV_FB_H__ -#define __DRV_FB_H__ - -#define RGB(r, g, b) ((((r))<<16) | (((g))<<8) | ((b))) -struct rt_hdmi_fb_device -{ - struct rt_device parent; - - rt_uint32_t width; - rt_uint32_t height; - rt_uint32_t depth; - rt_uint32_t pitch; - rt_uint32_t pixel_format; - - rt_uint8_t *fb; -}; -#endif/* __DRV_FB_H__ */ diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.c b/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.c deleted file mode 100644 index 728f1514b6..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ -#include "raspi.h" -#include "drv_gpio.h" - - -#ifdef BSP_USING_PIN -/* - * gpio_int[0] for BANK0 (pins 0-27) - * gpio_int[1] for BANK1 (pins 28-45) - * gpio_int[2] for BANK2 (pins 46-53) - */ -static struct gpio_irq_def _g_gpio_irq_tbl[GPIO_IRQ_NUM]; - -void gpio_set_pud(rt_uint8_t pin, rt_uint8_t pud) -{ - rt_uint8_t num = pin / 32; - rt_uint8_t shift = pin % 32; - BCM283X_GPIO_GPPUD = pud; - DELAY_MICROS(10); - BCM283X_GPIO_GPPUDCLK(num) = 1 << shift; - DELAY_MICROS(10); - BCM283X_GPIO_GPPUD = BCM283X_GPIO_PUD_OFF; - BCM283X_GPIO_GPPUDCLK(num) = 0 << shift; -} - -static void gpio_ack_irq(int irq, bcm_gpio_pin pin) -{ - rt_uint32_t data; - data = IRQ_PEND2; - data &= (0x0 << (irq - 32)); - IRQ_PEND2 = data; - - data = IRQ_DISABLE2; - data |= (0x1 << (irq - 32)); - IRQ_DISABLE2 = data; -} - -void gpio_irq_disable(rt_uint8_t index, bcm_gpio_pin pin) -{ - int irq = 0; - rt_uint32_t reg_value; - rt_uint8_t irq_type; - irq = IRQ_GPIO0 + index; - - gpio_ack_irq(irq, pin); - - irq_type = _g_gpio_irq_tbl[index].irq_type[pin]; - rt_uint8_t shift = pin % 32; - rt_uint32_t mask = 1 << shift; - - switch (irq_type) - { - case PIN_IRQ_MODE_RISING: - reg_value = BCM283X_GPIO_GPREN(pin /32); - BCM283X_GPIO_GPREN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - break; - case PIN_IRQ_MODE_FALLING: - reg_value = BCM283X_GPIO_GPFEN(pin /32); - BCM283X_GPIO_GPFEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - break; - case PIN_IRQ_MODE_RISING_FALLING: - reg_value = BCM283X_GPIO_GPAREN(pin /32); - BCM283X_GPIO_GPAREN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - reg_value = BCM283X_GPIO_GPAFEN(pin /32); - BCM283X_GPIO_GPAFEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - break; - case PIN_IRQ_MODE_HIGH_LEVEL: - reg_value = BCM283X_GPIO_GPHEN(pin /32); - BCM283X_GPIO_GPHEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - break; - case PIN_IRQ_MODE_LOW_LEVEL: - reg_value = BCM283X_GPIO_GPLEN(pin /32); - BCM283X_GPIO_GPLEN(pin /32) = (reg_value & ~ mask) | (PIN_LOW & mask); - break; - } -} - -void gpio_irq_enable(rt_uint8_t index, bcm_gpio_pin pin) -{ - rt_uint32_t offset; - rt_uint32_t data; - - offset = pin; - if (index == 0) - offset = IRQ_GPIO0 - 32; - else if (index == 1) - offset = IRQ_GPIO1 - 32; - else - offset = IRQ_GPIO2 - 32; - - data = IRQ_ENABLE2; - data |= 0x1 << offset; - IRQ_ENABLE2 = data; - -} - -static void raspi_pin_mode(struct rt_device *dev, rt_base_t pin, rt_uint8_t mode) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - RT_ASSERT(!(mode & 0x8)); - - switch (mode) - { - case PIN_MODE_OUTPUT: - GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP); - break; - case PIN_MODE_INPUT: - GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); - break; - case PIN_MODE_INPUT_PULLUP: - gpio_set_pud(pin, BCM283X_GPIO_PUD_UP); - GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); - break; - case PIN_MODE_INPUT_PULLDOWN: - gpio_set_pud(pin, BCM283X_GPIO_PUD_DOWN); - GPIO_FSEL(pin, BCM283X_GPIO_FSEL_INPT); - break; - case PIN_MODE_OUTPUT_OD: - gpio_set_pud(pin, BCM283X_GPIO_PUD_OFF); - GPIO_FSEL(pin, BCM283X_GPIO_FSEL_OUTP); - break; - } -} - -static void raspi_pin_write(struct rt_device *dev, rt_base_t pin, rt_uint8_t value) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - RT_ASSERT(!(value & 0xE)); - - if (value) - BCM283X_GPIO_GPSET(pin / 32) |= (1 << (pin %32)); - else - BCM283X_GPIO_GPCLR(pin / 32) |= (1 << (pin %32)); - -} - -static rt_ssize_t raspi_pin_read(struct rt_device *device, rt_base_t pin) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - return (BCM2835_GPIO_GPLEV(pin / 32) & (1 << (pin % 32)))? PIN_HIGH : PIN_LOW; -} - -static rt_err_t raspi_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - - rt_uint8_t index; - rt_uint32_t reg_value; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - _g_gpio_irq_tbl[index].irq_cb[pin] = hdr; - _g_gpio_irq_tbl[index].irq_arg[pin] = args; - _g_gpio_irq_tbl[index].irq_type[pin] = mode; - - rt_uint8_t shift = pin % 32; - rt_uint32_t mask = 1 << shift; - - switch (mode) - { - case PIN_IRQ_MODE_RISING: - reg_value = BCM283X_GPIO_GPREN(pin /32); - BCM283X_GPIO_GPREN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - break; - case PIN_IRQ_MODE_FALLING: - reg_value = BCM283X_GPIO_GPFEN(pin /32); - BCM283X_GPIO_GPFEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - break; - case PIN_IRQ_MODE_RISING_FALLING: - reg_value = BCM283X_GPIO_GPAREN(pin /32); - BCM283X_GPIO_GPAREN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - reg_value = BCM283X_GPIO_GPAFEN(pin /32); - BCM283X_GPIO_GPAFEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - break; - case PIN_IRQ_MODE_HIGH_LEVEL: - reg_value = BCM283X_GPIO_GPHEN(pin /32); - BCM283X_GPIO_GPHEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - break; - case PIN_IRQ_MODE_LOW_LEVEL: - reg_value = BCM283X_GPIO_GPLEN(pin /32); - BCM283X_GPIO_GPLEN(pin /32) = (reg_value & ~ mask) | (PIN_HIGH & mask); - break; - } - return RT_EOK; -} - -static rt_err_t raspi_pin_detach_irq(struct rt_device *device, rt_base_t pin) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - - rt_uint8_t index; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - - gpio_irq_disable(index, pin); - - _g_gpio_irq_tbl[index].irq_cb[pin] = RT_NULL; - _g_gpio_irq_tbl[index].irq_arg[pin] = RT_NULL; - _g_gpio_irq_tbl[index].irq_type[pin] = RT_NULL; - - return RT_EOK; -} - -rt_err_t raspi_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) -{ - RT_ASSERT((BCM_GPIO_PIN_0 <= pin) && (pin < BCM_GPIO_PIN_NULL)); - - rt_uint8_t index; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - - if (enabled) - gpio_irq_enable(index, pin); - else - gpio_irq_disable(index, pin); - - return RT_EOK; -} - -static void gpio_irq_handler(int irq, void *param) -{ - struct gpio_irq_def *irq_def = (struct gpio_irq_def *)param; - rt_uint32_t pin; - rt_uint32_t value; - rt_uint32_t tmpvalue; - - if (irq == IRQ_GPIO0) - { - /* 0~27 */ - - value = BCM283X_GPIO_GPEDS(0); - value &= 0x0fffffff; - pin = 0; - BCM283X_GPIO_GPEDS(0) = 0; - } - else if (irq == IRQ_GPIO1) - { - /* 28-45 */ - tmpvalue = BCM283X_GPIO_GPEDS(0); - tmpvalue &= (~0x0fffffff); - - value = BCM283X_GPIO_GPEDS(1); - value &= 0x3fff; - value = (value<<4) | tmpvalue; - pin = 28; - BCM283X_GPIO_GPEDS(0) = 0; - BCM283X_GPIO_GPEDS(1) = 0; - } - else if (irq == IRQ_GPIO2) - { - /* 46-53 */ - value = BCM283X_GPIO_GPEDS(1); - value &= (~0x3fff); - value &= 0xff600000; - pin = 46; - BCM283X_GPIO_GPEDS(1) = 0; - } - - while (value) - { - if ((value & 0x1) && (irq_def->irq_cb[pin] != RT_NULL)) - { - irq_def->irq_cb[pin](irq_def->irq_arg[pin]); - gpio_ack_irq(irq,pin); - } - pin++; - value = value >> 1; - } -} - -static const struct rt_pin_ops ops = -{ - raspi_pin_mode, - raspi_pin_write, - raspi_pin_read, - raspi_pin_attach_irq, - raspi_pin_detach_irq, - raspi_pin_irq_enable, - RT_NULL, -}; -#endif - -int rt_hw_gpio_init(void) -{ -#ifdef BSP_USING_PIN - rt_device_pin_register("gpio", &ops, RT_NULL); - - /* install ISR */ - rt_hw_interrupt_install(IRQ_GPIO0, gpio_irq_handler, &_g_gpio_irq_tbl[0], "gpio0_irq"); - rt_hw_interrupt_umask(IRQ_GPIO0); - - rt_hw_interrupt_install(IRQ_GPIO1, gpio_irq_handler, &_g_gpio_irq_tbl[1], "gpio1_irq"); - rt_hw_interrupt_umask(IRQ_GPIO1); - - rt_hw_interrupt_install(IRQ_GPIO2, gpio_irq_handler, &_g_gpio_irq_tbl[2], "gpio2_irq"); - rt_hw_interrupt_umask(IRQ_GPIO2); -#endif - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_gpio_init); diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.h b/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.h deleted file mode 100644 index 009f4e3edc..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_gpio.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_GPIO_H__ -#define __DRV_GPIO_H__ - -#include -#include - -#include "board.h" -#include "interrupt.h" - - -#define GPIO_IRQ_NUM 3 - -#define IRQ_GPIO0 49 -#define IRQ_GPIO1 50 -#define IRQ_GPIO2 51 -#define IRQ_GPIO3 52 - -struct gpio_irq_def -{ - void *irq_arg[32]; - void (*irq_cb[32])(void *param); - rt_uint8_t irq_type[32]; -}; - -enum gpio_irq_clock -{ - GPIO_IRQ_LOSC_32KHZ = 0, - GPIO_IRQ_HOSC_24MHZ -}; - -int rt_hw_gpio_init(void); - -#endif /* __DRV_GPIO_H__ */ diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.c b/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.c deleted file mode 100644 index 4648f880e7..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#include "raspi.h" -#include "drv_i2c.h" - -//Maybe redefined -typedef unsigned long rt_ubase_t; -typedef rt_ubase_t rt_size_t; - -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 = BCM283X_I2C_REASON_OK; - - /* Clear FIFO */ - BCM283X_BSC_C(base) |= (BSC_C_CLEAR_1 & BSC_C_CLEAR_1); - /* Clear Status */ - BCM283X_BSC_S(base) = BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE; - /* Set Data Length */ - BCM283X_BSC_DLEN(base) = len; - if (flag) - { - /* Start read */ - BCM283X_BSC_C(base) = BSC_C_I2CEN | BSC_C_ST | BSC_C_READ; - /* wait for transfer to complete */ - while (!(BCM283X_BSC_S(base) & BSC_S_DONE)) - { - /* we must empty the FIFO as it is populated and not use any delay */ - while (remaining && (BCM283X_BSC_S(base) & BSC_S_RXD)) - { - /* Read from FIFO, no barrier */ - buf[i] = BCM283X_BSC_FIFO(base); - i++; - remaining--; - } - } - /* transfer has finished - grab any remaining stuff in FIFO */ - while (remaining && (BCM283X_BSC_S(base) & BSC_S_RXD)) - { - /* Read from FIFO, no barrier */ - buf[i] = BCM283X_BSC_FIFO(base); - i++; - remaining--; - } - } - else - { - /* pre populate FIFO with max buffer */ - while (remaining && (i < BSC_FIFO_SIZE)) - { - BCM283X_BSC_FIFO(base) = buf[i]; - i++; - remaining--; - } - - /* Enable device and start transfer */ - BCM283X_BSC_C(base) = BSC_C_I2CEN | BSC_C_ST; - - /* Transfer is over when BCM2835_BSC_S_DONE */ - while (!(BCM283X_BSC_S(base) & BSC_S_DONE)) - { - while (remaining && (BCM283X_BSC_S(base) & BSC_S_TXD)) - { - /* Write to FIFO */ - BCM283X_BSC_FIFO(base) = buf[i]; - i++; - remaining--; - } - } - } - - status = BCM283X_BSC_S(base); - if (status & BSC_S_ERR) - { - reason = BCM283X_I2C_REASON_ERROR_NACK; - } - else if (status & BSC_S_CLKT) - { - reason = BCM283X_I2C_REASON_ERROR_CLKT; - } - else if (remaining) - { - reason = BCM283X_I2C_REASON_ERROR_DATA; - } - BCM283X_BSC_C(base) |= (BSC_S_DONE & BSC_S_DONE); - - return reason; -} - -struct raspi_i2c_hw_config -{ - rt_uint8_t bsc_num; - rt_uint8_t sdl_pin; - rt_uint8_t scl_pin; - rt_uint8_t sdl_mode; - rt_uint8_t scl_mode; -}; - -#if (defined(BSP_USING_I2C0) || defined(BSP_USING_I2C1)) - -static rt_ssize_t raspi_i2c_mst_xfer(struct rt_i2c_bus_device *bus, - struct rt_i2c_msg msgs[], - rt_uint32_t num); -static rt_ssize_t raspi_i2c_slv_xfer(struct rt_i2c_bus_device *bus, - struct rt_i2c_msg msgs[], - rt_uint32_t num); -static rt_err_t raspi_i2c_bus_control(struct rt_i2c_bus_device *bus, - int cmd, - void *args); - -static rt_uint32_t i2c_byte_wait_us = 0; -static rt_ssize_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); - - volatile rt_base_t base = (volatile rt_base_t)(bus->parent.user_data); - - if (bus->parent.user_data == 0) - base = BCM283X_BSC0_BASE; - else - base = BCM283X_BSC1_BASE; - - BCM283X_BSC_A(base) = msgs->addr; - - for (i = 0; i < num; i++) - { - if (msgs[i].flags & RT_I2C_RD) - reason = i2c_read_or_write(base, msgs->buf, msgs->len, 1); - else - reason = i2c_read_or_write(base, msgs->buf, msgs->len, 0); - } - return (reason == 0)? i : 0; -} - -static rt_ssize_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, - int cmd, - void *args) -{ - 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, -}; - - -static rt_err_t raspi_i2c_configure(struct raspi_i2c_hw_config *cfg) -{ - RT_ASSERT(cfg != RT_NULL); - - volatile rt_uint32_t base = cfg->scl_mode ? BCM283X_BSC1_BASE : BCM283X_BSC0_BASE; - - GPIO_FSEL(cfg->sdl_pin, cfg->sdl_mode); /* SDA */ - GPIO_FSEL(cfg->scl_pin, cfg->scl_mode); /* SCL */ - /* use 0xFFFE mask to limit a max value and round down any odd number */ - rt_uint32_t divider = (BCM283X_CORE_CLK_HZ / 10000) & 0xFFFE; - BCM283X_BSC_DIV(base) = (rt_uint16_t) divider; - i2c_byte_wait_us = (divider * 1000000 * 9 / BCM283X_CORE_CLK_HZ); - - return RT_EOK; -} -#endif - -#if defined (BSP_USING_I2C0) -#define I2C0_BUS_NAME "i2c0" -static struct raspi_i2c_hw_config hw_device0 = -{ - .bsc_num = 0, - .sdl_pin = RPI_GPIO_P1_27, - .scl_pin = RPI_GPIO_P1_28, - .sdl_mode = BCM283X_GPIO_FSEL_ALT0, - .scl_mode = BCM283X_GPIO_FSEL_ALT0, -}; - -struct rt_i2c_bus_device device0 = -{ - .ops = &raspi_i2c_ops, -}; - -#endif - -#if defined (BSP_USING_I2C1) -#define I2C1_BUS_NAME "i2c1" -static struct raspi_i2c_hw_config hw_device1 = -{ - .bsc_num = 1, - .sdl_pin = RPI_GPIO_P1_03, - .scl_pin = RPI_GPIO_P1_05, - .sdl_mode = BCM283X_GPIO_FSEL_ALT0, - .scl_mode = BCM283X_GPIO_FSEL_ALT0, -}; -struct rt_i2c_bus_device device1 = -{ - .ops = &raspi_i2c_ops, -}; - -#endif - -int rt_hw_i2c_init(void) -{ -#if defined(BSP_USING_I2C0) - device0.parent.user_data = (void *)0; - raspi_i2c_configure(&hw_device0); - rt_i2c_bus_device_register(&device0, I2C0_BUS_NAME); -#endif - -#if defined(BSP_USING_I2C1) - device1.parent.user_data = (void *)1; - raspi_i2c_configure(&hw_device1); - rt_i2c_bus_device_register(&device1, I2C1_BUS_NAME); -#endif - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_i2c_init); diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.h b/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.h deleted file mode 100644 index 2412631852..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_i2c.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_I2C_H__ -#define __DRV_I2C_H__ - -#include -#include - -#include "board.h" - -struct raspi_master_config_t -{ - rt_uint8_t sdl_pin; - rt_uint8_t scl_pin; - rt_uint8_t sdl_pin_mode; - rt_uint8_t scl_pin_mode; - rt_uint8_t slave_address; - rt_uint32_t bsc_base; - rt_uint16_t clk_div; -}; - -struct raspi_i2c_bus -{ - struct rt_i2c_bus_device device; - struct rt_i2c_msg *msg; - rt_uint32_t msg_cnt; - volatile rt_uint32_t msg_ptr; - volatile rt_uint32_t dptr; - char *device_name; - struct raspi_master_config_t *cfg; -}; - -int rt_hw_i2c_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.c b/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.c deleted file mode 100644 index d68596ed57..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#include -#include -#include -#include "drv_rtc.h" - -#ifdef BSP_USING_RTC - -static struct rt_rtc_device rtc_device; - -rt_uint8_t buf[]= -{ - 0x00, 0x00, 0x43, 0x15, 0x05, 0x01, 0x03, 0x19 -}; - -static time_t raspi_get_timestamp(void) -{ - struct tm tm_new = {0}; - buf[0] = 0; - bcm283x_i2c_write_read_rs((char*)buf, 1, (char*)buf, 7); - - tm_new.tm_year = ((buf[6] / 16) + 0x30) * 10 + (buf[6] % 16) + 0x30; - tm_new.tm_mon = ((buf[5] & 0x1F) / 16 + 0x30) + (buf[5] & 0x1F) % 16+ 0x30; - tm_new.tm_mday = ((buf[4] & 0x3F) / 16 + 0x30) + (buf[4] & 0x3F) % 16+ 0x30; - tm_new.tm_hour = ((buf[2] & 0x3F) / 16 + 0x30) + (buf[2] & 0x3F) % 16+ 0x30; - tm_new.tm_min = ((buf[1] & 0x7F) / 16 + 0x30) + (buf[1] & 0x7F) % 16+ 0x30; - tm_new.tm_sec = ((buf[0] & 0x7F) / 16 + 0x30) + (buf[0] & 0x7F) % 16+ 0x30; - - return timegm(&tm_new); -} - -static int raspi_set_timestamp(time_t timestamp) -{ - struct tm tblock; - gmtime_r(×tamp, &tblock); - buf[0] = 0; - buf[1] = tblock.tm_sec; - buf[2] = tblock.tm_min; - buf[3] = tblock.tm_hour; - buf[4] = tblock.tm_wday; - buf[5] = tblock.tm_mday; - buf[6] = tblock.tm_mon; - buf[7] = tblock.tm_year; - bcm283x_i2c_write((PER_BASE + BCM283X_BSC0_BASE) ,buf, 8); - return RT_EOK; -} - -static rt_err_t raspi_rtc_init(rt_device_t dev) -{ - bcm283x_i2c_setSlaveAddress(0, 0x68); - bcm283x_i2c_set_baudrate(0, 10000); - raspi_set_timestamp(0); - return RT_EOK; -} - -static rt_err_t raspi_rtc_open(rt_device_t dev, rt_uint16_t oflag) -{ - bcm283x_i2c_begin(0); - return RT_EOK; -} - -static rt_err_t raspi_rtc_close(rt_device_t dev) -{ - bcm283x_i2c_end(0); - return RT_EOK; -} - -static rt_err_t raspi_rtc_control(rt_device_t dev, int cmd, void *args) -{ - - RT_ASSERT(dev != RT_NULL); - - switch (cmd) - { - case RT_DEVICE_CTRL_RTC_GET_TIME: - *(time_t *)args = raspi_get_timestamp(); - break; - case RT_DEVICE_CTRL_RTC_SET_TIME: - raspi_set_timestamp(*(time_t *)args); - break; - default: - return -RT_EINVAL; - } - return RT_EOK; -} - -static rt_ssize_t raspi_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - raspi_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer); - return size; -} - -static rt_ssize_t raspi_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - raspi_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer); - return size; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops raspi_rtc_ops = -{ - .init = raspi_rtc_init, - .open = raspi_rtc_open, - .close = raspi_rtc_close, - .read = raspi_rtc_read, - .write = raspi_rtc_write, - .control = raspi_rtc_control -}; -#endif - -int rt_hw_rtc_init(void) -{ - rt_memset(&rtc_device, 0, sizeof(rtc_device)); - - rtc_device.device.type = RT_Device_Class_RTC; - rtc_device.device.rx_indicate = RT_NULL; - rtc_device.device.tx_complete = RT_NULL; - rtc_device.device.ops = &raspi_rtc_ops; - rtc_device.device.user_data = RT_NULL; - - /* register a rtc device */ - rt_device_register(&rtc_device.device, "rtc", RT_DEVICE_FLAG_RDWR); - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_rtc_init); -#endif /* BSP_USING_RTC */ - diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.h b/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.h deleted file mode 100644 index 35ccaf39d5..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_rtc.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_RTC_H__ -#define __DRV_RTC_H__ - -#include -#include -#include -#include "bcm283x.h" - -struct rt_rtc_device -{ - struct rt_device device; -}; - -int rt_hw_rtc_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.c b/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.c deleted file mode 100644 index 1e7b72b985..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * File : drv_sdio.c - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#include "drv_sdio.h" -#include "raspi.h" - -static rt_uint32_t sdCommandTable[] = { - SD_CMD_INDEX(0), - SD_CMD_RESERVED(1), - SD_CMD_INDEX(2) | SD_RESP_R2, - SD_CMD_INDEX(3) | SD_RESP_R1, - SD_CMD_INDEX(4), - SD_CMD_RESERVED(5), //SD_CMD_INDEX(5) | SD_RESP_R4, - SD_CMD_INDEX(6) | SD_RESP_R1, - SD_CMD_INDEX(7) | SD_RESP_R1b, - SD_CMD_INDEX(8) | SD_RESP_R1, - SD_CMD_INDEX(9) | SD_RESP_R2, - SD_CMD_INDEX(10) | SD_RESP_R2, - SD_CMD_INDEX(11) | SD_RESP_R1, - SD_CMD_INDEX(12) | SD_RESP_R1b | SD_CMD_TYPE_ABORT, - SD_CMD_INDEX(13) | SD_RESP_R1, - SD_CMD_RESERVED(14), - SD_CMD_INDEX(15), - SD_CMD_INDEX(16) | SD_RESP_R1, - SD_CMD_INDEX(17) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_INDEX(18) | SD_RESP_R1 | SD_DATA_READ | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN, - SD_CMD_INDEX(19) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_INDEX(20) | SD_RESP_R1b, - SD_CMD_RESERVED(21), - SD_CMD_RESERVED(22), - SD_CMD_INDEX(23) | SD_RESP_R1, - SD_CMD_INDEX(24) | SD_RESP_R1 | SD_DATA_WRITE, - SD_CMD_INDEX(25) | SD_RESP_R1 | SD_DATA_WRITE | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN, - SD_CMD_INDEX(26) | SD_RESP_R1 | SD_DATA_WRITE, //add - SD_CMD_INDEX(27) | SD_RESP_R1 | SD_DATA_WRITE, - SD_CMD_INDEX(28) | SD_RESP_R1b, - SD_CMD_INDEX(29) | SD_RESP_R1b, - SD_CMD_INDEX(30) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_RESERVED(31), - SD_CMD_INDEX(32) | SD_RESP_R1, - SD_CMD_INDEX(33) | SD_RESP_R1, - SD_CMD_RESERVED(34), - SD_CMD_INDEX(35) | SD_RESP_R1, //add - SD_CMD_INDEX(36) | SD_RESP_R1, //add - SD_CMD_RESERVED(37), - SD_CMD_INDEX(38) | SD_RESP_R1b, - SD_CMD_INDEX(39) | SD_RESP_R4, //add - SD_CMD_INDEX(40) | SD_RESP_R5, //add - SD_CMD_INDEX(41) | SD_RESP_R3, //add, mov from harbote - SD_CMD_RESERVED(42) | SD_RESP_R1, - SD_CMD_RESERVED(43), - SD_CMD_RESERVED(44), - SD_CMD_RESERVED(45), - SD_CMD_RESERVED(46), - SD_CMD_RESERVED(47), - SD_CMD_RESERVED(48), - SD_CMD_RESERVED(49), - SD_CMD_RESERVED(50), - SD_CMD_INDEX(51) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_RESERVED(52), - SD_CMD_RESERVED(53), - SD_CMD_RESERVED(54), - SD_CMD_INDEX(55) | SD_RESP_R3, - SD_CMD_INDEX(56) | SD_RESP_R1 | SD_CMD_ISDATA, - SD_CMD_RESERVED(57), - SD_CMD_RESERVED(58), - SD_CMD_RESERVED(59), - SD_CMD_RESERVED(60), - SD_CMD_RESERVED(61), - SD_CMD_RESERVED(62), - SD_CMD_RESERVED(63) -}; - -static inline rt_uint32_t read32(rt_uint32_t addr) -{ - return (*((volatile unsigned int*)((rt_uint64_t)addr))); - //return (*((volatile rt_uint64_t *)(((long))addr))); -} - -static inline void write32(rt_uint32_t addr, rt_uint32_t value) -{ - (*((volatile unsigned int*)((rt_uint64_t)addr))) = value; - //*((volatile rt_uint64_t *)(((long))addr)) = value; -} - -rt_err_t sd_int(struct sdhci_pdata_t * pdat, unsigned int mask) -{ - unsigned int r; - unsigned int m = mask | INT_ERROR_MASK; - int cnt = 1000000; - while (!(read32(pdat->virt + EMMC_INTERRUPT) & (m | INT_ERROR_MASK)) && cnt--) - DELAY_MICROS(1); - r = read32(pdat->virt + EMMC_INTERRUPT); - if (cnt <= 0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT)) - { - write32(pdat->virt + EMMC_INTERRUPT, r); - //qemu maybe can not use sdcard - //rt_kprintf("send cmd/data timeout wait for %x int: %x, status: %x\n",mask, r, read32(pdat->virt + EMMC_STATUS)); - //return -RT_ETIMEOUT; - } - else if (r & INT_ERROR_MASK) - { - write32(pdat->virt + EMMC_INTERRUPT, r); - rt_kprintf("send cmd/data error %x -> %x\n",r, read32(pdat->virt + EMMC_INTERRUPT)); - return -RT_ERROR; - } - write32(pdat->virt + EMMC_INTERRUPT, mask); - return RT_EOK; -} - -rt_err_t sd_status(struct sdhci_pdata_t * pdat, unsigned int mask) -{ - int cnt = 500000; - while ((read32(pdat->virt + EMMC_STATUS) & mask) && !(read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) && cnt--) - DELAY_MICROS(1); - if (cnt <= 0) - { - return -RT_ETIMEOUT; - } - else if (read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) - { - return -RT_ERROR; - } - - return RT_EOK; -} - -static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd) -{ - rt_uint32_t cmdidx; - rt_err_t ret = RT_EOK; - ret = sd_status(pdat, SR_CMD_INHIBIT); - if (ret) - { - rt_kprintf("ERROR: EMMC busy %d\n", ret); - return ret; - } - - cmdidx = sdCommandTable[cmd->cmdidx]; - if (cmdidx == 0xFFFFFFFF) - return -RT_EINVAL; - if (cmd->datarw == DATA_READ) - cmdidx |= SD_DATA_READ; - if (cmd->datarw == DATA_WRITE) - cmdidx |= SD_DATA_WRITE; - mmcsd_dbg("transfer cmd %x(%d) %x %x\n", cmdidx, cmd->cmdidx, cmd->cmdarg, read32(pdat->virt + EMMC_INTERRUPT)); - write32(pdat->virt + EMMC_INTERRUPT,read32(pdat->virt + EMMC_INTERRUPT)); - write32(pdat->virt + EMMC_ARG1, cmd->cmdarg); - write32(pdat->virt + EMMC_CMDTM, cmdidx); - if (cmd->cmdidx == SD_APP_OP_COND) - DELAY_MICROS(1000); - else if ((cmd->cmdidx == SD_SEND_IF_COND) || (cmd->cmdidx == APP_CMD)) - DELAY_MICROS(100); - ret = sd_int(pdat, INT_CMD_DONE); - if (ret) - { - return ret; - } - if (cmd->resptype & RESP_MASK) - { - - if (cmd->resptype & RESP_R2) - { - rt_uint32_t resp[4]; - resp[0] = read32(pdat->virt + EMMC_RESP0); - resp[1] = read32(pdat->virt + EMMC_RESP1); - resp[2] = read32(pdat->virt + EMMC_RESP2); - resp[3] = read32(pdat->virt + EMMC_RESP3); - if (cmd->resptype == RESP_R2) - { - cmd->response[0] = resp[3]<<8 |((resp[2]>>24)&0xff); - cmd->response[1] = resp[2]<<8 |((resp[1]>>24)&0xff); - cmd->response[2] = resp[1]<<8 |((resp[0]>>24)&0xff); - cmd->response[3] = resp[0]<<8 ; - } - else - { - cmd->response[0] = resp[0]; - cmd->response[1] = resp[1]; - cmd->response[2] = resp[2]; - cmd->response[3] = resp[3]; - } - } - else - cmd->response[0] = read32(pdat->virt + EMMC_RESP0); - } - mmcsd_dbg("response: %x: %x %x %x %x (%x, %x)\n", cmd->resptype, cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], read32(pdat->virt + EMMC_STATUS),read32(pdat->virt + EMMC_INTERRUPT)); - return ret; -} - -static rt_err_t read_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) -{ - int c = 0; - rt_err_t ret; - int d; - while (c < blkcount) - { - if ((ret = sd_int(pdat, INT_READ_RDY))) - { - rt_kprintf("timeout happens when reading block %d\n",c); - return ret; - } - for (d=0; d < blksize / 4; d++) - if (read32(pdat->virt + EMMC_STATUS) & SR_READ_AVAILABLE) - buf[d] = read32(pdat->virt + EMMC_DATA); - c++; - buf += blksize / 4; - } - return RT_EOK; -} - -static rt_err_t write_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) -{ - int c = 0; - rt_err_t ret; - int d; - while (c < blkcount) - { - if ((ret = sd_int(pdat, INT_WRITE_RDY))) - { - return ret; - } - for (d=0; d < blksize / 4; d++) - write32(pdat->virt + EMMC_DATA, buf[d]); - c++; - buf += blksize / 4; - } - if ((ret = sd_int(pdat, INT_DATA_DONE))) - { - return ret; - } - return RT_EOK; -} - -static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) -{ - rt_uint32_t dlen = (rt_uint32_t)(dat->blkcnt * dat->blksz); - rt_err_t ret = sd_status(pdat, SR_DAT_INHIBIT); - if (ret) - { - rt_kprintf("ERROR: EMMC busy\n"); - return ret; - } - if (dat->blkcnt > 1) - { - struct sdhci_cmd_t newcmd; - newcmd.cmdidx = SET_BLOCK_COUNT; - newcmd.cmdarg = dat->blkcnt; - newcmd.resptype = RESP_R1; - ret = raspi_transfer_command(pdat, &newcmd); - if (ret) return ret; - } - - if(dlen < 512) - { - write32(pdat->virt + EMMC_BLKSIZECNT, dlen | 1 << 16); - } - else - { - write32(pdat->virt + EMMC_BLKSIZECNT, 512 | (dat->blkcnt) << 16); - } - if (dat->flag & DATA_DIR_READ) - { - cmd->datarw = DATA_READ; - ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("read_block %d, %d\n", dat->blkcnt, dat->blksz ); - ret = read_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); - } - else if (dat->flag & DATA_DIR_WRITE) - { - cmd->datarw = DATA_WRITE; - ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("write_block %d, %d", dat->blkcnt, dat->blksz ); - ret = write_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); - } - return ret; -} - -static rt_err_t sdhci_transfer(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) -{ - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; - if (!dat) - return raspi_transfer_command(pdat, cmd); - - return raspi_transfer_data(pdat, cmd, dat); -} - -static void mmc_request_send(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req) -{ - struct sdhci_t *sdhci = (struct sdhci_t *)host->private_data; - struct sdhci_cmd_t cmd; - struct sdhci_cmd_t stop; - struct sdhci_data_t dat; - rt_memset(&cmd, 0, sizeof(struct sdhci_cmd_t)); - rt_memset(&stop, 0, sizeof(struct sdhci_cmd_t)); - rt_memset(&dat, 0, sizeof(struct sdhci_data_t)); - - cmd.cmdidx = req->cmd->cmd_code; - cmd.cmdarg = req->cmd->arg; - cmd.resptype =resp_type(req->cmd); - if (req->data) - { - dat.buf = (rt_uint8_t *)req->data->buf; - dat.flag = req->data->flags; - dat.blksz = req->data->blksize; - dat.blkcnt = req->data->blks; - - req->cmd->err = sdhci_transfer(sdhci, &cmd, &dat); - } - else - { - req->cmd->err = sdhci_transfer(sdhci, &cmd, RT_NULL); - } - - req->cmd->resp[3] = cmd.response[3]; - req->cmd->resp[2] = cmd.response[2]; - req->cmd->resp[1] = cmd.response[1]; - req->cmd->resp[0] = cmd.response[0]; - - if (req->stop) - { - stop.cmdidx = req->stop->cmd_code; - stop.cmdarg = req->stop->arg; - cmd.resptype =resp_type(req->stop); - req->stop->err = sdhci_transfer(sdhci, &stop, RT_NULL); - } - - mmcsd_req_complete(host); -} - -rt_int32_t mmc_card_status(struct rt_mmcsd_host *host) -{ - return 0; -} - -void mmc_enable_irq(struct rt_mmcsd_host *host, rt_int32_t en) -{ - -} - -static rt_err_t sdhci_detect(struct sdhci_t * sdhci) -{ - return RT_EOK; -} - -static rt_err_t sdhci_setwidth(struct sdhci_t * sdhci, rt_uint32_t width) -{ - rt_uint32_t temp = 0; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; - if (width == MMCSD_BUS_WIDTH_4) - { - temp = read32((pdat->virt + EMMC_CONTROL0)); - temp |= C0_HCTL_HS_EN; - temp |= C0_HCTL_DWITDH; // always use 4 data lines: - write32((pdat->virt + EMMC_CONTROL0), temp); - } - return RT_EOK; -} - -static rt_uint32_t sdhci_getdivider(rt_uint32_t sdHostVer, rt_uint32_t freq) -{ - rt_uint32_t divisor; - rt_uint32_t closest = 41666666 / freq; - rt_uint32_t shiftcount = __rt_fls(closest - 1); - - - if (shiftcount > 0) shiftcount--; - if (shiftcount > 7) shiftcount = 7; - if (sdHostVer > HOST_SPEC_V2) - divisor = closest; - else - divisor = (1 << shiftcount); - - if (divisor <= 2) - { - divisor = 2; - shiftcount = 0; - } - - rt_uint32_t hi = 0; - if (sdHostVer > HOST_SPEC_V2) - hi = (divisor & 0x300) >> 2; - rt_uint32_t lo = (divisor & 0x0ff); - rt_uint32_t cdiv = (lo << 8) + hi; - return cdiv; -} - -static rt_err_t sdhci_setclock(struct sdhci_t * sdhci, rt_uint32_t clock) -{ - rt_uint32_t temp = 0; - rt_uint32_t sdHostVer = 0; - int count = 100000; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)(sdhci->priv); - - while ((read32(pdat->virt + EMMC_STATUS) & (SR_CMD_INHIBIT | SR_DAT_INHIBIT)) && (--count)) - DELAY_MICROS(1); - if (count <= 0) - { - rt_kprintf("EMMC: Set clock: timeout waiting for inhibit flags. Status %08x.\n",read32(pdat->virt + EMMC_STATUS)); - return -RT_ERROR; - } - - // Switch clock off. - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp &= ~C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - // Request the new clock setting and enable the clock - temp = read32(pdat->virt + EMMC_SLOTISR_VER); - sdHostVer = (temp & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; - int cdiv = sdhci_getdivider(sdHostVer, clock); - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp = (temp & 0xffff003f) | cdiv; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - - // Enable the clock. - temp = read32(pdat->virt + EMMC_CONTROL1); - temp |= C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - // Wait for clock to be stable. - count = 10000; - while (!(read32(pdat->virt + EMMC_CONTROL1) & C1_CLK_STABLE) && count--) - DELAY_MICROS(10); - if (count <= 0) - { - rt_kprintf("EMMC: ERROR: failed to get stable clock %d.\n", clock); - return -RT_ERROR; - } - mmcsd_dbg("set stable clock %d.\n", clock); - return RT_EOK; -} - -static void mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg) -{ - struct sdhci_t * sdhci = (struct sdhci_t *)host->private_data; - sdhci_setclock(sdhci, io_cfg->clock); - sdhci_setwidth(sdhci, io_cfg->bus_width); -} - -static const struct rt_mmcsd_host_ops ops = -{ - mmc_request_send, - mmc_set_iocfg, - RT_NULL, - RT_NULL, -}; - -static void sdmmc_gpio_init() -{ -// int pin; -// bcm283x_gpio_fsel(47,BCM283X_GPIO_FSEL_INPT); -// bcm283x_gpio_set_pud(47, BCM283X_GPIO_PUD_UP); -// bcm283x_peri_set_bits(BCM283X_GPIO_BASE + BCM283X_GPIO_GPHEN1, 1<<15, 1<<15); -// for (pin = 53; pin >= 48; pin--) -// { -// bcm283x_gpio_fsel(pin, BCM283X_GPIO_FSEL_ALT3); -// bcm283x_gpio_set_pud(pin, BCM283X_GPIO_PUD_UP); -// } -} - -static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat){ - rt_uint32_t temp; - int cnt; - write32((pdat->virt + EMMC_CONTROL0),0); - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp |= C1_SRST_HC; - write32((pdat->virt + EMMC_CONTROL1),temp); - cnt = 10000; - do - { - DELAY_MICROS(10); - } - while ((read32((pdat->virt + EMMC_CONTROL1)) & C1_SRST_HC) && cnt--); - if (cnt <= 0) - { - rt_kprintf("ERROR: failed to reset EMMC\n"); - return -RT_ERROR; - } - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp |= C1_CLK_INTLEN | C1_TOUNIT_MAX; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - return RT_EOK; -} - -#ifdef RT_MMCSD_DBG -void dump_registers(struct sdhci_pdata_t * pdat){ - rt_kprintf("EMMC registers:"); - int i = EMMC_ARG2; - for (; i <= EMMC_CONTROL2; i += 4) - rt_kprintf("\t%x:%x\n", i, read32(pdat->virt + i)); - rt_kprintf("\t%x:%x\n", 0x50, read32(pdat->virt + 0x50)); - rt_kprintf("\t%x:%x\n", 0x70, read32(pdat->virt + 0x70)); - rt_kprintf("\t%x:%x\n", 0x74, read32(pdat->virt + 0x74)); - rt_kprintf("\t%x:%x\n", 0x80, read32(pdat->virt + 0x80)); - rt_kprintf("\t%x:%x\n", 0x84, read32(pdat->virt + 0x84)); - rt_kprintf("\t%x:%x\n", 0x88, read32(pdat->virt + 0x88)); - rt_kprintf("\t%x:%x\n", 0x8c, read32(pdat->virt + 0x8c)); - rt_kprintf("\t%x:%x\n", 0x90, read32(pdat->virt + 0x90)); - rt_kprintf("\t%x:%x\n", 0xf0, read32(pdat->virt + 0xf0)); - rt_kprintf("\t%x:%x\n", 0xfc, read32(pdat->virt + 0xfc)); -} -#endif - -int raspi_sdmmc_init(void) -{ - rt_uint32_t virt; - struct rt_mmcsd_host * host = RT_NULL; - struct sdhci_pdata_t * pdat = RT_NULL; - struct sdhci_t * sdhci = RT_NULL; -#ifdef BSP_USING_SDIO0 - host = mmcsd_alloc_host(); - if (!host) - { - rt_kprintf("alloc host failed"); - goto err; - } - - sdhci = rt_malloc(sizeof(struct sdhci_t)); - if (!sdhci) - { - rt_kprintf("alloc sdhci failed"); - goto err; - } - rt_memset(sdhci, 0, sizeof(struct sdhci_t)); - - sdmmc_gpio_init(); - virt = MMC0_BASE_ADDR; - - pdat = (struct sdhci_pdata_t *)rt_malloc(sizeof(struct sdhci_pdata_t)); - RT_ASSERT(pdat != RT_NULL); - - pdat->virt = (rt_uint32_t)virt; - reset_emmc(pdat); - - sdhci->name = "sd0"; - sdhci->voltages = VDD_33_34; - sdhci->width = MMCSD_BUSWIDTH_4; - sdhci->clock = 200 * 1000 * 1000; - sdhci->removeable = RT_TRUE; - - sdhci->detect = sdhci_detect; - sdhci->setwidth = sdhci_setwidth; - sdhci->setclock = sdhci_setclock; - sdhci->transfer = sdhci_transfer; - sdhci->priv = pdat; - - host->ops = &ops; - host->freq_min = 400000; - host->freq_max = 50000000; - host->valid_ocr = VDD_32_33 | VDD_33_34; - host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ | MMCSD_BUSWIDTH_4; - host->max_seg_size = 2048; - host->max_dma_segs = 10; - host->max_blk_size = 512; - host->max_blk_count = 4096; - - host->private_data = sdhci; - - write32((pdat->virt + EMMC_IRPT_EN),0xffffffff); - write32((pdat->virt + EMMC_IRPT_MASK),0xffffffff); -#ifdef RT_MMCSD_DBG - dump_registers(pdat); -#endif - mmcsd_change(host); -#endif - return RT_EOK; - -err: - if (host) rt_free(host); - if (sdhci) rt_free(sdhci); - - return -RT_EIO; -} - -INIT_DEVICE_EXPORT(raspi_sdmmc_init); diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.h b/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.h deleted file mode 100644 index 726cf51cf5..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_sdio.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * File : drv_sdio.h - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_SDIO_H__ -#define __DRV_SDIO_H__ - -#include -#include -#include - -#include "board.h" - -#define MMC0_BASE_ADDR 0x3F300000 - -/* Struct for Intrrrupt Information */ -#define SDXC_CmdDone BIT(0) -#define SDXC_DataDone BIT(1) -#define SDXC_BlockGap BIT(2) -#define SDXC_WriteRdy BIT(4) -#define SDXC_ReadRdy BIT(5) -#define SDXC_Card BIT(8) -#define SDXC_Retune BIT(12) -#define SDXC_BootAck BIT(13) -#define SDXC_EndBoot BIT(14) -#define SDXC_Err BIT(15) -#define SDXC_CTOErr BIT(16) -#define SDXC_CCRCErr BIT(17) -#define SDXC_CENDErr BIT(18) -#define SDXC_CBADErr BIT(19) -#define SDXC_DTOErr BIT(20) -#define SDXC_DCRCErr BIT(21) -#define SDXC_DENDErr BIT(22) -#define SDXC_ACMDErr BIT(24) - -#define SDXC_BLKCNT_EN BIT(1) -#define SDXC_AUTO_CMD12_EN BIT(2) -#define SDXC_AUTO_CMD23_EN BIT(3) -#define SDXC_DAT_DIR BIT(4) //from card to host -#define SDXC_MULTI_BLOCK BIT(5) -#define SDXC_CMD_RSPNS_136 BIT(16) -#define SDXC_CMD_RSPNS_48 BIT(17) -#define SDXC_CMD_RSPNS_48busy BIT(16)|BIT(17) -#define SDXC_CHECK_CRC_CMD BIT(19) -#define SDXC_CMD_IXCHK_EN BIT(20) -#define SDXC_CMD_ISDATA BIT(21) -#define SDXC_CMD_SUSPEND BIT(22) -#define SDXC_CMD_RESUME BIT(23) -#define SDXC_CMD_ABORT BIT(23)|BIT(22) - -#define SDXC_CMD_INHIBIT BIT(0) -#define SDXC_DAT_INHIBIT BIT(1) -#define SDXC_DAT_ACTIVE BIT(2) -#define SDXC_WRITE_TRANSFER BIT(8) -#define SDXC_READ_TRANSFER BIT(9) - -struct sdhci_cmd_t -{ - rt_uint32_t cmdidx; - rt_uint32_t cmdarg; - rt_uint32_t resptype; - rt_uint32_t datarw; -#define DATA_READ 1 -#define DATA_WRITE 2 - rt_uint32_t response[4]; -}; - -struct sdhci_data_t -{ - rt_uint8_t * buf; - rt_uint32_t flag; - rt_uint32_t blksz; - rt_uint32_t blkcnt; -}; - -struct sdhci_t -{ - char * name; - rt_uint32_t voltages; - rt_uint32_t width; - rt_uint32_t clock; - rt_err_t removeable; - void * sdcard; - - rt_err_t (*detect)(struct sdhci_t * sdhci); - rt_err_t (*setwidth)(struct sdhci_t * sdhci, rt_uint32_t width); - rt_err_t (*setclock)(struct sdhci_t * sdhci, rt_uint32_t clock); - rt_err_t (*transfer)(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat); - void * priv; -}; - -struct sdhci_pdata_t -{ - rt_uint32_t virt; -}; - -// EMMC command flags -#define CMD_TYPE_NORMAL 0x00000000 -#define CMD_TYPE_SUSPEND 0x00400000 -#define CMD_TYPE_RESUME 0x00800000 -#define CMD_TYPE_ABORT 0x00c00000 -#define CMD_IS_DATA 0x00200000 -#define CMD_IXCHK_EN 0x00100000 -#define CMD_CRCCHK_EN 0x00080000 -#define CMD_RSPNS_NO 0x00000000 -#define CMD_RSPNS_136 0x00010000 -#define CMD_RSPNS_48 0x00020000 -#define CMD_RSPNS_48B 0x00030000 -#define TM_MULTI_BLOCK 0x00000020 -#define TM_DAT_DIR_HC 0x00000000 -#define TM_DAT_DIR_CH 0x00000010 -#define TM_AUTO_CMD23 0x00000008 -#define TM_AUTO_CMD12 0x00000004 -#define TM_BLKCNT_EN 0x00000002 -#define TM_MULTI_DATA (CMD_IS_DATA|TM_MULTI_BLOCK|TM_BLKCNT_EN) - -#define RCA_NO 1 -#define RCA_YES 2 - -// INTERRUPT register settings -#define INT_AUTO_ERROR 0x01000000 -#define INT_DATA_END_ERR 0x00400000 -#define INT_DATA_CRC_ERR 0x00200000 -#define INT_DATA_TIMEOUT 0x00100000 -#define INT_INDEX_ERROR 0x00080000 -#define INT_END_ERROR 0x00040000 -#define INT_CRC_ERROR 0x00020000 -#define INT_CMD_TIMEOUT 0x00010000 -#define INT_ERR 0x00008000 -#define INT_ENDBOOT 0x00004000 -#define INT_BOOTACK 0x00002000 -#define INT_RETUNE 0x00001000 -#define INT_CARD 0x00000100 -#define INT_READ_RDY 0x00000020 -#define INT_WRITE_RDY 0x00000010 -#define INT_BLOCK_GAP 0x00000004 -#define INT_DATA_DONE 0x00000002 -#define INT_CMD_DONE 0x00000001 -#define INT_ERROR_MASK (INT_CRC_ERROR|INT_END_ERROR|INT_INDEX_ERROR| \ - INT_DATA_TIMEOUT|INT_DATA_CRC_ERR|INT_DATA_END_ERR| \ - INT_ERR|INT_AUTO_ERROR) -#define INT_ALL_MASK (INT_CMD_DONE|INT_DATA_DONE|INT_READ_RDY|INT_WRITE_RDY|INT_ERROR_MASK) - -#define EMMC_ARG2 (0x00) -#define EMMC_BLKSIZECNT (0x04) -#define EMMC_ARG1 (0x08) -#define EMMC_CMDTM (0x0c) -#define EMMC_RESP0 (0x10) -#define EMMC_RESP1 (0x14) -#define EMMC_RESP2 (0x18) -#define EMMC_RESP3 (0x1c) -#define EMMC_DATA (0x20) -#define EMMC_STATUS (0x24) -#define EMMC_CONTROL0 (0x28) -#define EMMC_CONTROL1 (0x2c) -#define EMMC_INTERRUPT (0x30) -#define EMMC_IRPT_MASK (0x34) -#define EMMC_IRPT_EN (0x38) -#define EMMC_CONTROL2 (0x3c) -#define EMMC_BOOT_TIMEOUT (0x70) -#define EMMC_EXRDFIFO_EN (0x84) -#define EMMC_SPI_INT_SPT (0xf0) -#define EMMC_SLOTISR_VER (0xfc) - -// CONTROL register settings -#define C0_SPI_MODE_EN 0x00100000 -#define C0_HCTL_HS_EN 0x00000004 -#define C0_HCTL_DWITDH 0x00000002 - -#define C1_SRST_DATA 0x04000000 -#define C1_SRST_CMD 0x02000000 -#define C1_SRST_HC 0x01000000 -#define C1_TOUNIT_DIS 0x000f0000 -#define C1_TOUNIT_MAX 0x000e0000 -#define C1_CLK_GENSEL 0x00000020 -#define C1_CLK_EN 0x00000004 -#define C1_CLK_STABLE 0x00000002 -#define C1_CLK_INTLEN 0x00000001 - -#define FREQ_SETUP 400000 // 400 Khz -#define FREQ_NORMAL 25000000 // 25 Mhz - -// SLOTISR_VER values -#define HOST_SPEC_NUM 0x00ff0000 -#define HOST_SPEC_NUM_SHIFT 16 -#define HOST_SPEC_V3 2 -#define HOST_SPEC_V2 1 -#define HOST_SPEC_V1 0 - -// STATUS register settings -#define SR_DAT_LEVEL1 0x1e000000 -#define SR_CMD_LEVEL 0x01000000 -#define SR_DAT_LEVEL0 0x00f00000 -#define SR_DAT3 0x00800000 -#define SR_DAT2 0x00400000 -#define SR_DAT1 0x00200000 -#define SR_DAT0 0x00100000 -#define SR_WRITE_PROT 0x00080000 // From SDHC spec v2, BCM says reserved -#define SR_READ_AVAILABLE 0x00000800 // ???? undocumented -#define SR_WRITE_AVAILABLE 0x00000400 // ???? undocumented -#define SR_READ_TRANSFER 0x00000200 -#define SR_WRITE_TRANSFER 0x00000100 -#define SR_DAT_ACTIVE 0x00000004 -#define SR_DAT_INHIBIT 0x00000002 -#define SR_CMD_INHIBIT 0x00000001 - -#define CONFIG_MMC_USE_DMA -#define DMA_ALIGN (32U) - -#define SD_CMD_INDEX(a) ((a) << 24) -#define SD_CMD_RESERVED(a) 0xffffffff -#define SD_CMD_INDEX(a) ((a) << 24) -#define SD_CMD_TYPE_NORMAL 0x0 -#define SD_CMD_TYPE_SUSPEND (1 << 22) -#define SD_CMD_TYPE_RESUME (2 << 22) -#define SD_CMD_TYPE_ABORT (3 << 22) -#define SD_CMD_TYPE_MASK (3 << 22) -#define SD_CMD_ISDATA (1 << 21) -#define SD_CMD_IXCHK_EN (1 << 20) -#define SD_CMD_CRCCHK_EN (1 << 19) -#define SD_CMD_RSPNS_TYPE_NONE 0 // For no response -#define SD_CMD_RSPNS_TYPE_136 (1 << 16) // For response R2 (with CRC), R3,4 (no CRC) -#define SD_CMD_RSPNS_TYPE_48 (2 << 16) // For responses R1, R5, R6, R7 (with CRC) -#define SD_CMD_RSPNS_TYPE_48B (3 << 16) // For responses R1b, R5b (with CRC) -#define SD_CMD_RSPNS_TYPE_MASK (3 << 16) -#define SD_CMD_MULTI_BLOCK (1 << 5) -#define SD_CMD_DAT_DIR_HC 0 -#define SD_CMD_DAT_DIR_CH (1 << 4) -#define SD_CMD_AUTO_CMD_EN_NONE 0 -#define SD_CMD_AUTO_CMD_EN_CMD12 (1 << 2) -#define SD_CMD_AUTO_CMD_EN_CMD23 (2 << 2) -#define SD_CMD_BLKCNT_EN (1 << 1) -#define SD_CMD_DMA 1 -#define SD_RESP_NONE SD_CMD_RSPNS_TYPE_NONE -#define SD_RESP_R1 (SD_CMD_RSPNS_TYPE_48) // | SD_CMD_CRCCHK_EN) -#define SD_RESP_R1b (SD_CMD_RSPNS_TYPE_48B) // | SD_CMD_CRCCHK_EN) -#define SD_RESP_R2 (SD_CMD_RSPNS_TYPE_136) //| SD_CMD_CRCCHK_EN) -#define SD_RESP_R3 SD_CMD_RSPNS_TYPE_48 -#define SD_RESP_R4 SD_CMD_RSPNS_TYPE_136 -#define SD_RESP_R5 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_RESP_R5b (SD_CMD_RSPNS_TYPE_48B | SD_CMD_CRCCHK_EN) -#define SD_RESP_R6 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_RESP_R7 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_DATA_READ (SD_CMD_ISDATA | SD_CMD_DAT_DIR_CH) -#define SD_DATA_WRITE (SD_CMD_ISDATA | SD_CMD_DAT_DIR_HC) -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_spi.c b/bsp/raspberry-pi/raspi3-64/driver/drv_spi.c deleted file mode 100644 index bb3c7479c6..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_spi.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ -#include "drv_spi.h" -#include "raspi.h" - -#ifdef RT_USING_SPI - -#define RPI_CORE_CLK_HZ 250000000 -#define BSP_SPI_MAX_HZ (30* 1000 *1000) -#define SPITIMEOUT 0x0FFF - -void spi_gpio_write(rt_uint8_t pin, rt_uint8_t val) -{ - if (val) - BCM283X_GPIO_GPSET((pin / 32)) = 1 << (pin % 32); - else - BCM283X_GPIO_GPCLR((pin / 32)) = 1 << (pin % 32); -} - -struct raspi_spi_hw_config -{ - rt_uint8_t spi_num; - raspi_gpio_pin sclk_pin; - raspi_pin_select sclk_mode; - raspi_gpio_pin mosi_pin; - raspi_pin_select mosi_mode; - raspi_gpio_pin miso_pin; - raspi_pin_select miso_mode; -#if defined (BSP_USING_SPI0_DEVICE0) || defined (BSP_USING_SPI1_DEVICE0) - raspi_gpio_pin ce0_pin; - raspi_pin_select ce0_mode; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) || defined (BSP_USING_SPI1_DEVICE1) - raspi_gpio_pin ce1_pin; - raspi_pin_select ce1_mode; -#endif - -#if defined (BSP_USING_SPI1_DEVICE2) - raspi_gpio_pin ce2_pin; - raspi_pin_select ce2_mode; -#endif -}; - -struct raspi_spi_device -{ - char *device_name; - struct rt_spi_bus *spi_bus; - struct rt_spi_device *spi_device; - raspi_gpio_pin cs_pin; -}; - -static rt_err_t raspi_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg) -{ - RT_ASSERT(cfg != RT_NULL); - RT_ASSERT(device != RT_NULL); - rt_uint16_t divider; - - // spi clear fifo - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CLEAR; - - if (cfg->mode & RT_SPI_CPOL) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CPOL; - - if (cfg->mode & RT_SPI_CPHA) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CPHA; - - if (cfg->mode & RT_SPI_CS_HIGH) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CSPOL; - - //set clk - if (cfg->max_hz > BSP_SPI_MAX_HZ) - cfg->max_hz = BSP_SPI_MAX_HZ; - - divider = (rt_uint16_t) ((rt_uint32_t) RPI_CORE_CLK_HZ / cfg->max_hz); - divider &= 0xFFFE; - - BCM283X_SPI0_CLK(BCM283X_SPI0_BASE) = divider; - - return RT_EOK; -} - -rt_uint8_t correct_order(rt_uint8_t b, rt_uint8_t flag) -{ - if (flag) - return raspi_byte_reverse_table[b]; - else - return b; -} - -static rt_err_t spi_transfernb(rt_uint8_t* tbuf, rt_uint8_t* rbuf, rt_uint32_t len, rt_uint8_t flag) -{ - rt_uint32_t TXCnt=0; - rt_uint32_t RXCnt=0; - - /* Clear TX and RX fifos */ - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (BCM283X_SPI0_CS_CLEAR & BCM283X_SPI0_CS_CLEAR); - - /* Set TA = 1 */ - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (BCM283X_SPI0_CS_TA & BCM283X_SPI0_CS_TA); - - - /* Use the FIFO's to reduce the interbyte times */ - while ((TXCnt < len) || (RXCnt < len)) - { - /* TX fifo not full, so add some more bytes */ - while (((BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_TXD)) && (TXCnt < len)) - { - BCM283X_SPI0_FIFO(BCM283X_SPI0_BASE) = correct_order(tbuf[TXCnt],flag); - TXCnt++; - } - /* Rx fifo not empty, so get the next received bytes */ - while (((BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_RXD)) && (RXCnt < len)) - { - rbuf[RXCnt] = correct_order(BCM283X_SPI0_FIFO(BCM283X_SPI0_BASE),flag); - RXCnt++; - } - } - /* Wait for DONE to be set */ - while (!(BCM283X_SPI0_CS(BCM283X_SPI0_BASE) & BCM283X_SPI0_CS_DONE)); - - /* Set TA = 0, and also set the barrier */ - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= (0 & BCM283X_SPI0_CS_TA); - return RT_EOK; -} - -static rt_ssize_t raspi_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message) -{ - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->bus != RT_NULL); - RT_ASSERT(device->parent.user_data != RT_NULL); - RT_ASSERT(message->send_buf != RT_NULL || message->recv_buf != RT_NULL); - - rt_err_t res; - rt_uint8_t flag; - struct rt_spi_configuration config = device->config; - raspi_gpio_pin cs_pin = (raspi_gpio_pin)device->parent.user_data; - - if (config.mode & RT_SPI_MSB) - flag = 0; - else - flag = 1; - if (message->cs_take); - // (config.mode & RT_SPI_CS_HIGH)? - // spi_gpio_write(cs_pin, 1): - // spi_gpio_write(cs_pin, 0); - - /* deal data */ - res = spi_transfernb((rt_uint8_t *)message->send_buf, (rt_uint8_t *)message->recv_buf, - (rt_int32_t)message->length, flag); - - if (message->cs_release) - (config.mode & RT_SPI_CS_HIGH)? - spi_gpio_write(cs_pin, 0): - spi_gpio_write(cs_pin, 1); - - if (res != RT_EOK) - return res; - - return message->length; -} - -rt_err_t raspi_spi_bus_attach_device(const char *bus_name, struct raspi_spi_device *device) -{ - rt_err_t ret; - RT_ASSERT(device != RT_NULL); - ret = rt_spi_bus_attach_device(device->spi_device, device->device_name, bus_name, (void *)(device->cs_pin)); - return ret; -} - -rt_err_t raspi_spi_hw_init(struct raspi_spi_hw_config *hwcfg) -{ - GPIO_FSEL(hwcfg->sclk_pin, hwcfg->sclk_mode); - GPIO_FSEL(hwcfg->miso_pin, hwcfg->miso_mode); - GPIO_FSEL(hwcfg->mosi_pin, hwcfg->mosi_mode); - -#if defined (BSP_USING_SPI0_DEVICE0) - GPIO_FSEL(hwcfg->ce0_pin, hwcfg->ce0_mode); -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - GPIO_FSEL(hwcfg->ce1_pin, hwcfg->ce1_mode); -#endif - - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) = 0; - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) = BCM283X_SPI0_CS_CLEAR; - - //enable chip select -#if defined (BSP_USING_SPI0_DEVICE0) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= 0; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= 0x2; -#endif - -#if defined (BSP_USING_SPI0_DEVICE0) && defined (BSP_USING_SPI0_DEVICE1) - BCM283X_SPI0_CS(BCM283X_SPI0_BASE) |= BCM283X_SPI0_CS_CS; -#endif - return RT_EOK; -} - -static struct rt_spi_ops raspi_spi_ops = -{ - .configure = raspi_spi_configure, - .xfer = raspi_spi_xfer -}; - -#if defined (BSP_USING_SPI0_BUS) -#define SPI0_BUS_NAME "spi0" -#define SPI0_DEVICE0_NAME "spi0.0" -#define SPI0_DEVICE1_NAME "spi0.1" - -struct rt_spi_bus spi0_bus; - -#if defined (BSP_USING_SPI0_DEVICE0) -struct rt_spi_device spi0_device0; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) -static struct rt_spi_device spi0_device1; -#endif - -struct raspi_spi_hw_config raspi_spi0_hw = -{ - .spi_num = 0, - .sclk_pin = RPI_GPIO_P1_23, - .sclk_mode = BCM283X_GPIO_FSEL_ALT0, - .mosi_pin = RPI_GPIO_P1_19, - .mosi_mode = BCM283X_GPIO_FSEL_ALT0, - .miso_pin = RPI_GPIO_P1_21, - .miso_mode = BCM283X_GPIO_FSEL_ALT0, - -#if defined (BSP_USING_SPI0_DEVICE0) - .ce0_pin = RPI_GPIO_P1_24, - .ce0_mode = BCM283X_GPIO_FSEL_ALT0, -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - .ce1_pin = RPI_GPIO_P1_26, - .ce1_mode = BCM283X_GPIO_FSEL_ALT0, -#endif -}; -#endif - -int rt_hw_spi_init(void) -{ - -#if defined (BSP_USING_SPI0_BUS) - raspi_spi_hw_init(&raspi_spi0_hw); - rt_spi_bus_register(&spi0_bus, SPI0_BUS_NAME, &raspi_spi_ops); - -#if defined (BSP_USING_SPI0_DEVICE0) - struct raspi_spi_device raspi_spi0_device0 = - { - .device_name = SPI0_DEVICE0_NAME, - .spi_bus = &spi0_bus, - .spi_device = &spi0_device0, - .cs_pin = raspi_spi0_hw.ce0_pin, - }; - raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device0); -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - struct raspi_spi_device raspi_spi0_device1 = - { - .device_name = SPI0_DEVICE1_NAME, - .spi_bus = &spi0_bus, - .spi_device = &spi0_device1, - .cs_pin = raspi_spi0_hw.ce1_pin, - }; - raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device1); -#endif -#endif - return RT_EOK; -} -INIT_DEVICE_EXPORT(rt_hw_spi_init); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_spi.h b/bsp/raspberry-pi/raspi3-64/driver/drv_spi.h deleted file mode 100644 index 219afab8e7..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_spi.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_SPI_H__ -#define __DRV_SPI_H__ - -#include -#include - -//#include "drivers/dev_spi.h" -#include "board.h" - -#define SPI0_BASE_ADDR (PER_BASE + BCM283X_SPI0_BASE) - -static rt_uint8_t raspi_byte_reverse_table[] = -{ - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -#define SPI_CORE_CLK 250000000U -#define SPI_CS 0x00 -#define SPI_CS_LEN_LONG (1 << 25) -#define SPI_CS_DMA_LEN (1 << 24) -#define SPI_CS_CSPOL2 (1 << 23) -#define SPI_CS_CSPOL1 (1 << 22) -#define SPI_CS_CSPOL0 (1 << 21) -#define SPI_CS_RXF (1 << 20) -#define SPI_CS_RXR (1 << 19) -#define SPI_CS_TXD (1 << 18) -#define SPI_CS_RXD (1 << 17) -#define SPI_CS_DONE (1 << 16) -#define SPI_CS_LEN (1 << 13) -#define SPI_CS_REN (1 << 12) -#define SPI_CS_ADCS (1 << 11) -#define SPI_CS_INTR (1 << 10) -#define SPI_CS_INTD (1 << 9) -#define SPI_CS_DMAEN (1 << 8) -#define SPI_CS_TA (1 << 7) -#define SPI_CS_CSPOL (1 << 6) -#define SPI_CS_CLEAR_RXFIFO (1 << 5) -#define SPI_CS_CLEAR_TXFIFO (1 << 4) -#define SPI_CS_CPOL (1 << 3) -#define SPI_CS_CPHA (1 << 2) -#define SPI_CS_MASK 0x3 -#define SPI_FIFO 0x04 -#define SPI_CLK 0x08 -#define SPI_CLK_MASK 0xffff -#define SPI_DLEN 0x0c -#define SPI_DLEN_MASK 0xffff -#define SPI_LTOH 0x10 -#define SPI_LTOH_MASK 0xf -#define SPI_DC 0x14 -#define SPI_DC_RPANIC_SHIFT 24 -#define SPI_DC_RPANIC_MASK (0xff << SPI_DC_RPANIC_SHIFT) -#define SPI_DC_RDREQ_SHIFT 16 -#define SPI_DC_RDREQ_MASK (0xff << SPI_DC_RDREQ_SHIFT) -#define SPI_DC_TPANIC_SHIFT 8 -#define SPI_DC_TPANIC_MASK (0xff << SPI_DC_TPANIC_SHIFT) -#define SPI_DC_TDREQ_SHIFT 0 -#define SPI_DC_TDREQ_MASK 0xff - -int rt_hw_spi_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_timer.c b/bsp/raspberry-pi/raspi3-64/driver/drv_timer.c deleted file mode 100644 index eff6fe5417..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_timer.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#include "drv_timer.h" -#include "interrupt.h" -#include "raspi.h" - -#ifdef BSP_USING_SYSTIMER - -static void raspi_systimer_init(rt_clock_timer_t *clock_timer, rt_uint32_t state) -{ - if (state == 0) - clock_timer->ops->stop(clock_timer); -} - -static rt_err_t raspi_systimer_start(rt_clock_timer_t *clock_timer, rt_uint32_t cnt, rt_clock_timer_mode_t mode) -{ - rt_err_t result = RT_EOK; - rt_systimer_t *timer = (rt_systimer_t *)clock_timer->parent.user_data; - int timer_id = timer->timer_id; - - if (mode == CLOCK_TIMER_MODE_PERIOD) - timer->cnt = cnt; - else - timer->cnt = 0; - - __sync_synchronize(); - if (timer_id == 1) - { - rt_hw_interrupt_umask(IRQ_SYSTEM_TIMER_1); - STIMER_C1 = STIMER_CLO + cnt; - } - else if (timer_id == 3) - { - rt_hw_interrupt_umask(IRQ_SYSTEM_TIMER_3); - STIMER_C3 = STIMER_CLO + cnt; - } - else - result = -RT_ERROR; - - __sync_synchronize(); - - return result; -} - -static void raspi_systimer_stop(rt_clock_timer_t *clock_timer) -{ - rt_systimer_t *timer = (rt_systimer_t *)clock_timer->parent.user_data; - int timer_id = timer->timer_id; - if (timer_id == 1) - rt_hw_interrupt_mask(IRQ_SYSTEM_TIMER_1); - else if (timer_id == 3) - rt_hw_interrupt_mask(IRQ_SYSTEM_TIMER_3); - -} - -static rt_err_t raspi_systimer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg) -{ - /* The frequency value is an immutable value. */ - if (cmd == CLOCK_TIMER_CTRL_FREQ_SET) - { - return RT_EOK; - } - else - { - return -RT_ENOSYS; - } -} - - -void rt_device_systimer_isr(int vector, void *param) -{ - - rt_clock_timer_t *clock_timer = (rt_clock_timer_t *) param; - rt_systimer_t *timer = (rt_systimer_t *)clock_timer->parent.user_data; - RT_ASSERT(timer != RT_NULL); - - int timer_id = timer->timer_id; - - __sync_synchronize(); - if (timer_id == 1) - { - STIMER_CS = 0x2; - STIMER_C1 = STIMER_CLO + timer->cnt; - } - else if (timer_id == 3) - { - STIMER_CS = 0x8; - STIMER_C3 = STIMER_CLO + timer->cnt; - } - __sync_synchronize(); - - rt_clock_timer_isr(clock_timer); -} - -#ifdef RT_USING_SYSTIMER1 -static struct rt_clock_timer_device _clock_timer1; -static rt_systimer_t _systimer1; -#endif - -#ifdef RT_USING_SYSTIMER3 -static struct rt_clock_timer_device _clock_timer3; -static rt_systimer_t _systimer3; -#endif - -const static struct rt_clock_timer_ops systimer_ops = -{ - raspi_systimer_init, - raspi_systimer_start, - raspi_systimer_stop, - RT_NULL, - raspi_systimer_ctrl -}; - -static const struct rt_clock_timer_info _info = -{ - 1000000, /* the maxinum count frequency can be set */ - 1000000, /* the maxinum count frequency can be set */ - 0xFFFFFFFF, /* the maximum counter value */ - CLOCK_TIMER_CNTMODE_UP /* count mode (inc/dec) */ -}; - -#endif - -int rt_hw_systimer_init(void) -{ - -#ifdef BSP_USING_SYSTIMER - -#ifdef RT_USING_SYSTIMER1 - _systimer1.timer_id =1; - _clock_timer1.ops = &systimer_ops; - _clock_timer1.info = &_info; - rt_clock_timer_register(&_clock_timer1, "timer1",&_systimer1); - rt_hw_interrupt_install(IRQ_SYSTEM_TIMER_1, rt_device_systimer_isr, &_clock_timer1, "systimer1"); - rt_hw_interrupt_umask(IRQ_SYSTEM_TIMER_1); -#endif - -#ifdef RT_USING_SYSTIMER3 - _systimer3.timer_id =3; - _clock_timer3.ops = &systimer_ops; - _clock_timer3.info = &_info; - rt_clock_timer_register(&_clock_timer3, "timer3",&_systimer3); - rt_hw_interrupt_install(IRQ_SYSTEM_TIMER_3, rt_device_systimer_isr, &_clock_timer3, "systimer3"); - rt_hw_interrupt_umask(IRQ_SYSTEM_TIMER_3); -#endif - -#endif - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_systimer_init); diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_timer.h b/bsp/raspberry-pi/raspi3-64/driver/drv_timer.h deleted file mode 100644 index ebe5536fa5..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_timer.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ -#ifndef __DRV_TIMER_H__ -#define __DRV_TIMER_H__ - -#include -#include - -typedef struct rt_systimer_device -{ - int timer_id; - rt_uint32_t cnt; -} rt_systimer_t; - -int rt_hw_systimer_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_uart.c b/bsp/raspberry-pi/raspi3-64/driver/drv_uart.c deleted file mode 100644 index 6eb7a46f10..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_uart.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018/5/5 Bernard The first version - */ - -#include -#include -#include - -#include "raspi.h" -#include "board.h" -#include "drv_uart.h" - -#define AUX_BASE (0x3F000000 + 0x215000) - -struct hw_uart_device -{ - rt_ubase_t hw_base; - rt_uint32_t irqno; -}; - -static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - if (uart->hw_base == AUX_BASE) - { - rt_uint32_t value; - - /* GPIO function set */ - value = BCM283X_GPIO_GPFSEL(1); - value &= ~(7 << 12); /* GPIO14 */ - value |= 2 << 12 ; /* ALT5 */ - value &= ~(7 << 15); /* GPIO15 */ - value |= 2 << 15 ; /* ALT5 */ - BCM283X_GPIO_GPFSEL(1) = value; - - BCM283X_GPIO_GPPUD = 0; - BCM283X_GPIO_GPPUDCLK(0) = (1 << 14) | (1 << 15); - BCM283X_GPIO_GPPUDCLK(0) = 0; - - AUX_ENABLES(uart->hw_base) = 1; /* Enable UART1 */ - AUX_MU_IER_REG(uart->hw_base) = 0; /* Disable interrupt */ - AUX_MU_CNTL_REG(uart->hw_base) = 0; /* Disable Transmitter and Receiver */ - AUX_MU_LCR_REG(uart->hw_base) = 3; /* Works in 8-bit mode */ - AUX_MU_MCR_REG(uart->hw_base) = 0; /* Disable RTS */ - AUX_MU_IIR_REG(uart->hw_base) = 0xC6; /* Enable FIFO, Clear FIFO */ - AUX_MU_BAUD_REG(uart->hw_base) = 270; /* 115200 = system clock 250MHz / (8 * (baud + 1)), baud = 270 */ - AUX_MU_CNTL_REG(uart->hw_base) = 3; /* Enable Transmitter and Receiver */ - } - - return RT_EOK; -} - -static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - switch (cmd) - { - case RT_DEVICE_CTRL_CLR_INT: - /* disable rx irq */ - AUX_MU_IER_REG(uart->hw_base) = 0x0; - rt_hw_interrupt_mask(uart->irqno); - break; - - case RT_DEVICE_CTRL_SET_INT: - /* enable rx irq */ - AUX_MU_IER_REG(uart->hw_base) = 0x1; - rt_hw_interrupt_umask(uart->irqno); - break; - } - - return RT_EOK; -} - -static int uart_putc(struct rt_serial_device *serial, char c) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - while (!(AUX_MU_LSR_REG(uart->hw_base) & 0x20)); - AUX_MU_IO_REG(uart->hw_base) = c; - - return 1; -} - -static int uart_getc(struct rt_serial_device *serial) -{ - int ch = -1; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - if ((AUX_MU_LSR_REG(uart->hw_base) & 0x01)) - { - ch = AUX_MU_IO_REG(uart->hw_base) & 0xff; - } - - return ch; -} - -static const struct rt_uart_ops _uart_ops = -{ - uart_configure, - uart_control, - uart_putc, - uart_getc, -}; - -static void rt_hw_uart_isr(int irqno, void *param) -{ - struct rt_serial_device *serial = (struct rt_serial_device*)param; - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); -} - -#ifdef RT_USING_UART0 -/* UART device driver structure */ -static struct hw_uart_device _uart0_device = -{ - RPI_UART0_BASE, - IRQ_PBA8_UART0, -}; -static struct rt_serial_device _serial0; -#endif - -#ifdef RT_USING_UART1 -/* UART1 device driver structure */ -static struct hw_uart_device _uart1_device = -{ - AUX_BASE, - IRQ_AUX, -}; -static struct rt_serial_device _serial1; -#endif - -int rt_hw_uart_init(void) -{ - struct hw_uart_device *uart; - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - -#ifdef RT_USING_UART0 - uart = &_uart0_device; - - _serial0.ops = &_uart_ops; - _serial0.config = config; - - /* register UART1 device */ - rt_hw_serial_register(&_serial0, "uart0", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); - rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, &_serial0, "uart0"); -#endif - -#ifdef RT_USING_UART1 - uart = &_uart1_device; - _serial1.ops = &_uart_ops; - _serial1.config = config; - - /* register UART1 device */ - rt_hw_serial_register(&_serial1, "uart1", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); - /* enable Rx and Tx of UART */ - rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, &_serial1, "uart1"); -#endif - - return 0; -} diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_uart.h b/bsp/raspberry-pi/raspi3-64/driver/drv_uart.h deleted file mode 100644 index 76072f938e..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_uart.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017-5-30 Bernard the first version - */ - - -#ifndef DRV_UART_H__ -#define DRV_UART_H__ - -/* - * Auxiliary - */ -#define AUX_IRQ(BASE) HWREG32(BASE + 0x00) /* Auxiliary Interrupt status 3 */ -#define AUX_ENABLES(BASE) HWREG32(BASE + 0x04) /* Auxiliary enables 3bit */ -#define AUX_MU_IO_REG(BASE) HWREG32(BASE + 0x40) /* Mini Uart I/O Data 8bit */ -#define AUX_MU_IER_REG(BASE) HWREG32(BASE + 0x44) /* Mini Uart Interrupt Enable 8bit */ -#define AUX_MU_IIR_REG(BASE) HWREG32(BASE + 0x48) /* Mini Uart Interrupt Identify 8bit */ -#define AUX_MU_LCR_REG(BASE) HWREG32(BASE + 0x4C) /* Mini Uart Line Control 8bit */ -#define AUX_MU_MCR_REG(BASE) HWREG32(BASE + 0x50) /* Mini Uart Modem Control 8bit */ -#define AUX_MU_LSR_REG(BASE) HWREG32(BASE + 0x54) /* Mini Uart Line Status 8bit */ -#define AUX_MU_MSR_REG(BASE) HWREG32(BASE + 0x58) /* Mini Uart Modem Status 8bit */ -#define AUX_MU_SCRATCH(BASE) HWREG32(BASE + 0x5C) /* Mini Uart Scratch 8bit */ -#define AUX_MU_CNTL_REG(BASE) HWREG32(BASE + 0x60) /* Mini Uart Extra Control 8bit */ -#define AUX_MU_STAT_REG(BASE) HWREG32(BASE + 0x64) /* Mini Uart Extra Status 32bit */ -#define AUX_MU_BAUD_REG(BASE) HWREG32(BASE + 0x68) /* Mini Uart Baudrate 16bit */ -#define AUX_SPI0_CNTL0_REG(BASE) HWREG32(BASE + 0x80) /* SPI 1 Control register 0 32bit */ -#define AUX_SPI0_CNTL1_REG(BASE) HWREG32(BASE + 0x84) /* SPI 1 Control register 1 8bit */ -#define AUX_SPI0_STAT_REG(BASE) HWREG32(BASE + 0x88) /* SPI 1 Status 32bit */ -#define AUX_SPI0_IO_REG(BASE) HWREG32(BASE + 0x90) /* SPI 1 Data 32bit */ -#define AUX_SPI0_PEEK_REG(BASE) HWREG32(BASE + 0x94) /* SPI 1 Peek 16bit */ -#define AUX_SPI1_CNTL0_REG(BASE) HWREG32(BASE + 0xC0) /* SPI 2 Control register 0 32bit */ -#define AUX_SPI1_CNTL1_REG(BASE) HWREG32(BASE + 0xC4) /* SPI 2 Control register 1 8bit */ - -int rt_hw_uart_init(void); - -#endif /* DRV_UART_H__ */ - diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.c b/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.c deleted file mode 100644 index ccf8ca6cff..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ -#include "drv_wdt.h" -#include "raspi.h" - -#ifdef BSP_USING_WDT - -#define SECS_TO_WDOG_TICKS(x) ((x) << 16) -#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) - -static struct raspi_wdt_driver bcm_wdt; - -void raspi_watchdog_init(rt_uint32_t time_init) -{ - bcm_wdt.timeout = time_init; -} - -void raspi_watchdog_start() -{ - volatile rt_uint32_t cur; - PM_WDOG = PM_PASSWORD | (SECS_TO_WDOG_TICKS(bcm_wdt.timeout) & PM_WDOG_TIME_SET); - cur = PM_RSTC; - PM_RSTC = PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET; -} - -void raspi_watchdog_stop() -{ - PM_RSTC = PM_PASSWORD | PM_RSTC_RESET; -} - -void raspi_watchdog_clr() -{ - bcm_wdt.timeout = 0; -} - -void raspi_watchdog_set_timeout(rt_uint32_t timeout_us) -{ - bcm_wdt.timeout = timeout_us; -} - -rt_uint64_t raspi_watchdog_get_timeout() -{ - return bcm_wdt.timeout; -} - -rt_uint64_t raspi_watchdog_get_timeleft() -{ - rt_uint32_t ret = PM_WDOG; - return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); -} - -static rt_err_t raspi_wdg_init(rt_watchdog_t *wdt) -{ - /*init for 10S*/ - raspi_watchdog_init(1000000); - raspi_watchdog_start(); - raspi_watchdog_stop(); - return RT_EOK; -} - -static rt_err_t raspi_wdg_control(rt_watchdog_t *wdt, int cmd, void *arg) -{ - rt_uint64_t timeout_us = 0; - switch (cmd) - { - case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: - timeout_us = *((rt_uint32_t *)arg) * 1000000; - if (timeout_us >= 0xFFFFFFFF) - timeout_us = 0xFFFFFFFF; - raspi_watchdog_set_timeout((rt_uint32_t)timeout_us); - break; - case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: - timeout_us = raspi_watchdog_get_timeout(); - *((rt_uint32_t *)arg) = timeout_us / 1000000; - break; - case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: - timeout_us = raspi_watchdog_get_timeleft(); - *((rt_uint32_t *)arg) = timeout_us / 1000000; - break; - case RT_DEVICE_CTRL_WDT_KEEPALIVE: - raspi_watchdog_clr(); - break; - case RT_DEVICE_CTRL_WDT_START: - raspi_watchdog_start(); - break; - case RT_DEVICE_CTRL_WDT_STOP: - raspi_watchdog_stop(); - break; - default: - return -RT_EIO; - } - return RT_EOK; -} - -static const struct rt_watchdog_ops raspi_wdg_pos = -{ - raspi_wdg_init, - raspi_wdg_control, -}; - -static rt_watchdog_t raspi_wdg; - -int rt_hw_wdt_init(void) -{ - raspi_wdg.ops = &raspi_wdg_pos; - rt_hw_watchdog_register(&raspi_wdg, "wdg", 0, RT_NULL); - return RT_EOK; -} - -INIT_DEVICE_EXPORT(rt_hw_wdt_init); - -/** - * Reboot - */ -int reboot(void) -{ - unsigned int r; - - rt_kprintf("reboot system...\n"); - rt_thread_mdelay(100); - // trigger a restart by instructing the GPU to boot from partition 0 - r = PM_RSTS; r &= ~0xfffffaaa; - PM_RSTS = PM_PASSWORD | r; // boot from partition 0 - PM_WDOG = PM_PASSWORD | 10; - PM_RSTC = PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; - - while (1); - - return 0; -} -MSH_CMD_EXPORT(reboot,reboot system...); -#endif /*BSP_USING_WDT */ - diff --git a/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.h b/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.h deleted file mode 100644 index ffb07ff5da..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/drv_wdt.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __DRV_WDT_H__ -#define __DRV_WDT_H__ - -#include -#include - -#include "board.h" - -struct raspi_wdt_driver -{ - rt_uint32_t timeout; -}; - -int rt_hw_wdt_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/mbox.c b/bsp/raspberry-pi/raspi3-64/driver/mbox.c deleted file mode 100644 index 6a8bb0633d..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/mbox.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * File : mbox.c - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-08-29 zdzn first version - */ - -/* mailbox message buffer */ -#include "mbox.h" -#include "mmu.h" -//volatile unsigned int __attribute__((aligned(16))) mbox[36]; -volatile unsigned int *mbox = (volatile unsigned int *) MBOX_ADDR; -#define BUS_ADDRESS(phys) (((phys) & ~0xC0000000) | 0xC0000000) - -/** - * Make a mailbox call. Returns 0 on failure, non-zero on success - */ -int mbox_call(unsigned char ch, int mmu_enable) -{ - unsigned int r = (((MBOX_ADDR)&~0xF) | (ch&0xF)); - if(mmu_enable) - r = BUS_ADDRESS(r); - /* wait until we can write to the mailbox */ - do - { - asm volatile("nop"); - } while (*MBOX_STATUS & MBOX_FULL); - /* write the address of our message to the mailbox with channel identifier */ - *MBOX_WRITE = r; - /* now wait for the response */ - // rt_kprintf("mailbox request %x\n",r); - while(1) - { - /* is there a response? */ - do - { - asm volatile("nop"); - } while (*MBOX_STATUS & MBOX_EMPTY); - /* is it a response to our message? */ - if (r == *MBOX_READ){ - /* is it a valid successful response? */ - // rt_kprintf("mbox: %x, %x, %x, %x, %x, %x, %x, %x\n", mbox[0], mbox[1], mbox[2], mbox[3], mbox[4], mbox[5], mbox[6], mbox[7]); - return mbox[1] == MBOX_RESPONSE; - } - } - return 0; -} - -int bcm283x_mbox_hardware_get_model(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_MODEL; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - return mbox[5]; -} - -int bcm283x_mbox_hardware_get_revison(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_REV; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - return mbox[5]; -} - -int bcm283x_mbox_hardware_get_mac_address(uint8_t * mac) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_MAC_ADDRESS; - mbox[3] = 6; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - char * mac_str = (char *)&mbox[5]; - mac[0] = mac_str[0]; - mac[1] = mac_str[1]; - mac[2] = mac_str[2]; - mac[3] = mac_str[3]; - mac[4] = mac_str[4]; - mac[5] = mac_str[5]; - return 0; -} - - -int bcm283x_mbox_hardware_get_serial(rt_uint64_t* sn) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_SERIAL; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - sn = (rt_uint64_t *)&mbox[5]; - - return 0; -} - -int bcm283x_mbox_hardware_get_arm_memory(rt_uint32_t * base, rt_uint32_t * size) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_ARM_MEMORY; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - *base = mbox[5]; - *size = mbox[6]; - - return 0; - -} - -int bcm283x_mbox_hardware_get_vc_memory(rt_uint32_t * base, rt_uint32_t * size) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_VC_MEMORY; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - *base = mbox[5]; - *size = mbox[6]; - - return 0; -} - -int bcm283x_mbox_clock_get_turbo(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_TURBO; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; // id - mbox[6] = 0; // val - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_clock_set_turbo(int level) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_TURBO; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = 0; // id - mbox[6] = level ? 1 : 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_clock_get_state(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm283x_mbox_clock_set_state(int id, int state) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = state & 0x3; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm283x_mbox_clock_get_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_clock_set_rate(int id, int rate) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = rate; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_clock_get_max_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_MAX_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_clock_get_min_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_MIN_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_power_get_state(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_POWER_GET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm283x_mbox_power_set_state(int id, int state) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_POWER_SET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = state & 0x3; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm283x_mbox_temp_get(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_TEMP_GET; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; //id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm283x_mbox_temp_get_max(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_TEMP_GET_MAX; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} diff --git a/bsp/raspberry-pi/raspi3-64/driver/mbox.h b/bsp/raspberry-pi/raspi3-64/driver/mbox.h deleted file mode 100644 index c30a818803..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/mbox.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * File : mbox.h - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-08-29 zdzn first version - */ - -#ifndef __MBOX_H__ -#define __MBOX_H__ - -#include -#include -/* a properly aligned buffer */ -extern volatile unsigned int* mbox; - -#define MBOX_REQUEST 0 - -/* channels */ -#define MBOX_CH_POWER 0 -#define MBOX_CH_FB 1 -#define MBOX_CH_VUART 2 -#define MBOX_CH_VCHIQ 3 -#define MBOX_CH_LEDS 4 -#define MBOX_CH_BTNS 5 -#define MBOX_CH_TOUCH 6 -#define MBOX_CH_COUNT 7 -#define MBOX_CH_PROP 8 - -/* tags */ -#define MBOX_TAG_SETPOWER 0x28001 -#define MBOX_TAG_SETCLKRATE 0x38002 -#define MBOX_GET_MAC_ADDRESS 0x10003 -#define MBOX_TAG_LAST 0 - -#define MMIO_BASE 0x3F000000 -#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) -#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) -#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) -#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) -#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) -#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) -#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) -#define MBOX_RESPONSE 0x80000000 -#define MBOX_FULL 0x80000000 -#define MBOX_EMPTY 0x40000000 - -#define DEVICE_ID_SD_CARD 0 -#define DEVICE_ID_USB_HCD 3 -#define POWER_STATE_OFF (0 << 0) -#define POWER_STATE_ON (1 << 0) -#define POWER_STATE_WAIT (1 << 1) -#define POWER_STATE_NO_DEVICE (1 << 1) // in response -#define MMU_ENABLE 1 -#define MMU_DISABLE 0 - -/* - * raspi hardware info - */ -enum { - MBOX_TAG_HARDWARE_GET_MODEL = 0x00010001, - MBOX_TAG_HARDWARE_GET_REV = 0x00010002, - MBOX_TAG_HARDWARE_GET_MAC_ADDRESS = 0x00010003, - MBOX_TAG_HARDWARE_GET_SERIAL = 0x00010004, - MBOX_TAG_HARDWARE_GET_ARM_MEMORY = 0x00010005, - MBOX_TAG_HARDWARE_GET_VC_MEMORY = 0x00010006, - MBOX_TAG_HARDWARE_GET_CLOCKS = 0x00010007, -}; - -/* - * raspi clock - */ -enum { - MBOX_TAG_CLOCK_GET_TURBO = 0x00030009, - MBOX_TAG_CLOCK_SET_TURBO = 0x00038009, - MBOX_TAG_CLOCK_GET_STATE = 0x00030001, - MBOX_TAG_CLOCK_SET_STATE = 0x00038001, - MBOX_TAG_CLOCK_GET_RATE = 0x00030002, - MBOX_TAG_CLOCK_SET_RATE = 0x00038002, - MBOX_TAG_CLOCK_GET_MAX_RATE = 0x00030004, - MBOX_TAG_CLOCK_GET_MIN_RATE = 0x00030007, -}; - -/* - * raspi power - */ -enum { - MBOX_TAG_POWER_GET_STATE = 0x00020001, - MBOX_TAG_POWER_SET_STATE = 0x00028001, -}; - -/* - * raspi temperature - */ -enum { - MBOX_TAG_TEMP_GET = 0x00030006, - MBOX_TAG_TEMP_GET_MAX = 0x0003000A, -}; - -#define MBOX_ADDR 0xc00000 - -int mbox_call(unsigned char ch, int mmu_enable); -int bcm283x_mbox_hardware_get_model(void); -int bcm283x_mbox_hardware_get_revison(void); -int bcm283x_mbox_hardware_get_mac_address(uint8_t * mac); -int bcm283x_mbox_hardware_get_serial(rt_uint64_t* sn); -int bcm283x_mbox_hardware_get_arm_memory(rt_uint32_t * base, rt_uint32_t * size); -int bcm283x_mbox_hardware_get_vc_memory(rt_uint32_t * base, rt_uint32_t * size); -int bcm283x_mbox_clock_get_turbo(void); -int bcm283x_mbox_clock_set_turbo(int level); -int bcm283x_mbox_clock_get_state(int id); -int bcm283x_mbox_clock_set_state(int id, int state); -int bcm283x_mbox_clock_get_rate(int id); -int bcm283x_mbox_clock_set_rate(int id, int rate); -int bcm283x_mbox_clock_get_max_rate(int id); -int bcm283x_mbox_clock_get_min_rate(int id); -int bcm283x_mbox_power_get_state(int id); -int bcm283x_mbox_power_set_state(int id, int state); -int bcm283x_mbox_temp_get(void); -int bcm283x_mbox_temp_get_max(void); - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/driver/raspi.h b/bsp/raspberry-pi/raspi3-64/driver/raspi.h deleted file mode 100644 index e8979b54f1..0000000000 --- a/bsp/raspberry-pi/raspi3-64/driver/raspi.h +++ /dev/null @@ -1,454 +0,0 @@ -/* - * File : rsapi.h - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-07-29 zdzn first version - */ - -#ifndef __RASPI_H__ -#define __RASPI_H__ - -#include - -#define __REG32(x) (*((volatile unsigned int*)((rt_uint64_t)x))) - -typedef enum -{ - BCM_GPIO_PIN_0 = 0, - BCM_GPIO_PIN_1, - BCM_GPIO_PIN_2, - BCM_GPIO_PIN_3, - BCM_GPIO_PIN_4, - BCM_GPIO_PIN_5, - BCM_GPIO_PIN_6, - BCM_GPIO_PIN_7, - BCM_GPIO_PIN_8, - BCM_GPIO_PIN_9, - BCM_GPIO_PIN_10, - BCM_GPIO_PIN_11, - BCM_GPIO_PIN_12, - BCM_GPIO_PIN_13, - BCM_GPIO_PIN_14, - BCM_GPIO_PIN_15, - BCM_GPIO_PIN_16, - BCM_GPIO_PIN_17, - BCM_GPIO_PIN_18, - BCM_GPIO_PIN_19, - BCM_GPIO_PIN_20, - BCM_GPIO_PIN_21, - BCM_GPIO_PIN_22, - BCM_GPIO_PIN_23, - BCM_GPIO_PIN_24, - BCM_GPIO_PIN_25, - BCM_GPIO_PIN_26, - BCM_GPIO_PIN_27, - BCM_GPIO_PIN_28, - BCM_GPIO_PIN_29, - BCM_GPIO_PIN_30, - BCM_GPIO_PIN_31, - BCM_GPIO_PIN_32, - BCM_GPIO_PIN_33, - BCM_GPIO_PIN_34, - BCM_GPIO_PIN_35, - BCM_GPIO_PIN_36, - BCM_GPIO_PIN_37, - BCM_GPIO_PIN_38, - BCM_GPIO_PIN_39, - BCM_GPIO_PIN_40, - BCM_GPIO_PIN_41, - BCM_GPIO_PIN_42, - BCM_GPIO_PIN_43, - BCM_GPIO_PIN_44, - BCM_GPIO_PIN_45, - BCM_GPIO_PIN_46, - BCM_GPIO_PIN_47, - BCM_GPIO_PIN_48, - BCM_GPIO_PIN_49, - BCM_GPIO_PIN_50, - BCM_GPIO_PIN_51, - BCM_GPIO_PIN_52, - BCM_GPIO_PIN_53, - BCM_GPIO_PIN_NULL, -} bcm_gpio_pin; - -typedef enum -{ - BCM283X_GPIO_FSEL_INPT = 0x00, /*!< Input 0b000 */ - BCM283X_GPIO_FSEL_OUTP = 0x01, /*!< Output 0b001 */ - BCM283X_GPIO_FSEL_ALT0 = 0x04, /*!< Alternate function 0 0b100 */ - BCM283X_GPIO_FSEL_ALT1 = 0x05, /*!< Alternate function 1 0b101 */ - BCM283X_GPIO_FSEL_ALT2 = 0x06, /*!< Alternate function 2 0b110, */ - BCM283X_GPIO_FSEL_ALT3 = 0x07, /*!< Alternate function 3 0b111 */ - BCM283X_GPIO_FSEL_ALT4 = 0x03, /*!< Alternate function 4 0b011 */ - BCM283X_GPIO_FSEL_ALT5 = 0x02, /*!< Alternate function 5 0b010 */ - BCM283X_GPIO_FSEL_MASK = 0x07 /*!< Function select bits mask 0b111 */ -} gpio_function_select; - -typedef enum -{ - BCM283X_GPIO_PUD_OFF = 0x00, /*!< Off ? disable pull-up/down 0b00 */ - BCM283X_GPIO_PUD_DOWN = 0x01, /*!< Enable Pull Down control 0b01 */ - BCM283X_GPIO_PUD_UP = 0x02 /*!< Enable Pull Up control 0b10 */ -} gpio_pud_mode; - -#define BCM283X_CORE_CLK_HZ 250000000 /* 50 MHz */ - -/* Base Address */ -#define PER_BASE (0x3F000000) -#define PER_BASE_40000000 (0x40000000) -//#define BCM283X_PERI_BASE (0x3F000000) -//#define BCM283X_PER_BASE_40000000 (0x40000000) - -/* Base Address Registers Offset */ -#define ST_BASE_OFFSET (0x003000) -#define GPIO_PAD_OFFSET (0x100000) -#define CLOCK_BASE_OFFSET (0x101000) -#define GPIO_BASE_OFFSET (0x200000) -#define SPI0_BASE_OFFSET (0x204000) -#define BSC0_BASE_OFFSET (0x205000) -#define GPIO_PWM_OFFSET (0x20C000) -#define AUX_BASE_OFFSET (0x215000) -#define SPI1_BASE_OFFSET (0x215080) -#define SPI2_BASE_OFFSET (0x2150C0) -#define BSC1_BASE_OFFSET (0x804000) -#define BSC2_BASE_OFFSET (0x805000) - -/* IRQ */ -#define MAX_HANDLERS 72 -#define IRQ_SYSTEM_TIMER_0 0 -#define IRQ_SYSTEM_TIMER_1 1 -#define IRQ_SYSTEM_TIMER_2 2 -#define IRQ_SYSTEM_TIMER_3 3 -#define IRQ_USB 9 -#define IRQ_AUX 29 -#define IRQ_PCM 55 -#define IRQ_ARM_TIMER 64 -#define IRQ_ARM_MAILBOX 65 - -/* Interrupt Controler */ -#define IRQ_BASE (PER_BASE + 0xB200) -#define IRQ_PEND_BASIC __REG32(IRQ_BASE + 0x0000) -#define IRQ_PEND1 __REG32(IRQ_BASE + 0x0004) -#define IRQ_PEND2 __REG32(IRQ_BASE + 0x0008) -#define IRQ_FIQ_CONTROL __REG32(IRQ_BASE + 0x000C) -#define IRQ_ENABLE1 __REG32(IRQ_BASE + 0x0010) -#define IRQ_ENABLE2 __REG32(IRQ_BASE + 0x0014) -#define IRQ_ENABLE_BASIC __REG32(IRQ_BASE + 0x0018) -#define IRQ_DISABLE1 __REG32(IRQ_BASE + 0x001C) -#define IRQ_DISABLE2 __REG32(IRQ_BASE + 0x0020) -#define IRQ_DISABLE_BASIC __REG32(IRQ_BASE + 0x0024) - - -/* Defines for WDT*/ -#define PM_BASE (PER_BASE + GPIO_PAD_OFFSET) -#define PM_RSTC __REG32(PM_BASE + 0x001C) -#define PM_RSTS __REG32(PM_BASE + 0x0020) -#define PM_WDOG __REG32(PM_BASE + 0x0024) - -#define PM_PASSWORD 0x5a000000 -#define PM_WDOG_TIME_SET 0x000fffff -#define PM_RSTC_WRCFG_CLR 0xffffffcf -#define PM_RSTS_HADWRH_SET 0x00000040 -#define PM_RSTC_WRCFG_SET 0x00000030 -#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 -#define PM_RSTC_RESET 0x00000102 -#define PM_RSTS_PARTITION_CLR 0xfffffaaa - -/* Defines for System Timer */ -#define STIMER_BASE (PER_BASE + ST_BASE_OFFSET) -#define STIMER_CS __REG32(STIMER_BASE + 0x0000) -#define STIMER_CLO __REG32(STIMER_BASE + 0x0004) -#define STIMER_CHI __REG32(STIMER_BASE + 0x0008) -#define STIMER_C0 __REG32(STIMER_BASE + 0x000C) -#define STIMER_C1 __REG32(STIMER_BASE + 0x0010) -#define STIMER_C2 __REG32(STIMER_BASE + 0x0014) -#define STIMER_C3 __REG32(STIMER_BASE + 0x0018) - -#define DELAY_MICROS(micros) \ - do{ \ - rt_uint32_t compare = STIMER_CLO + micros * 25; \ - while (STIMER_CLO < compare); \ - } while (0) \ - -/* Defines for GPIO */ -#define BCM283X_GPIO_BASE (PER_BASE + GPIO_BASE_OFFSET) -#define BCM283X_GPIO_GPFSEL(n) __REG32(BCM283X_GPIO_BASE + 0x0000 + 0x4 * (n)) /* GPIO Function Select 32bit R/W */ -#define BCM283X_GPIO_GPSET(n) __REG32(BCM283X_GPIO_BASE + 0x001C + 0x4 * (n)) /* GPIO Pin Output Set */ -#define BCM283X_GPIO_GPCLR(n) __REG32(BCM283X_GPIO_BASE + 0x0028 + 0x4 * (n)) /* GPIO Pin Output Clear */ -#define BCM2835_GPIO_GPLEV(n) __REG32(BCM283X_GPIO_BASE + 0x0034 + 0x4 * (n)) /* GPIO Pin Level */ -#define BCM283X_GPIO_GPEDS(n) __REG32(BCM283X_GPIO_BASE + 0x0040 + 0x4 * (n)) /* GPIO Pin Event Detect Status */ -#define BCM283X_GPIO_GPREN(n) __REG32(BCM283X_GPIO_BASE + 0x004c + 0x4 * (n)) /* GPIO Pin Rising Edge Detect Enable */ -#define BCM283X_GPIO_GPFEN(n) __REG32(BCM283X_GPIO_BASE + 0x0058 + 0x4 * (n)) /* GPIO Pin Falling Edge Detect Enable */ -#define BCM283X_GPIO_GPHEN(n) __REG32(BCM283X_GPIO_BASE + 0x0064 + 0x4 * (n)) /* GPIO Pin High Detect Enable */ -#define BCM283X_GPIO_GPLEN(n) __REG32(BCM283X_GPIO_BASE + 0x0070 + 0x4 * (n)) /* GPIO Pin Low Detect Enable */ -#define BCM283X_GPIO_GPAREN(n) __REG32(BCM283X_GPIO_BASE + 0x007C + 0x4 * (n)) /* GPIO Pin Async. Rising Edge Detect */ -#define BCM283X_GPIO_GPAFEN(n) __REG32(BCM283X_GPIO_BASE + 0x0088 + 0x4 * (n)) /* GPIO Pin Async. Falling Edge Detect */ -#define BCM283X_GPIO_GPPUD __REG32(BCM283X_GPIO_BASE + 0x0094) /* GPIO Pin Pull-up/down Enable */ -#define BCM283X_GPIO_GPPUDCLK(n) __REG32(BCM283X_GPIO_BASE + 0x0098 + 0x4 * (n)) /* GPIO Pin Pull-up/down Enable Clock */ - -#define GPIO_FSEL_NUM(pin) (pin/10) -#define GPIO_FSEL_SHIFT(pin) ((pin%10)*3) -#define GPIO_FSEL(pin, mode) \ - do{ \ - __sync_synchronize(); \ - BCM283X_GPIO_GPFSEL(GPIO_FSEL_NUM(pin)) |= ((mode & BCM283X_GPIO_FSEL_MASK) << GPIO_FSEL_SHIFT(pin)); \ - } while (0) \ - -/* Defines for I2C */ -#define BCM283X_BSC0_BASE (PER_BASE + BSC0_BASE_OFFSET) //for i2c0 -#define BCM283X_BSC1_BASE (PER_BASE + BSC1_BASE_OFFSET) //for i2c1 -#define BCM283X_BSC2_BASE (PER_BASE + BSC2_BASE_OFFSET) //for hdmi i2c not use - -#define BCM283X_BSC_C(BASE) __REG32(BASE + 0x0000) /* BSC Master Control */ -#define BCM283X_BSC_S(BASE) __REG32(BASE + 0x0004) /* BSC Master Status */ -#define BCM283X_BSC_DLEN(BASE) __REG32(BASE + 0x0008) /* BSC Master Data Length */ -#define BCM283X_BSC_A(BASE) __REG32(BASE + 0x000c) /* BSC Master Slave Address */ -#define BCM283X_BSC_FIFO(BASE) __REG32(BASE + 0x0010) /* BSC Master Data FIFO */ -#define BCM283X_BSC_DIV(BASE) __REG32(BASE + 0x0014) /* BSC Master Clock Divider */ -#define BCM283X_BSC_DEL(BASE) __REG32(BASE + 0x0018) /* BSC Master Data Delay */ -#define BCM283X_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 */ - -/* Defines for SPI */ -#define BCM283X_SPI0_BASE (PER_BASE + SPI0_BASE_OFFSET) -#define BCM283X_SPI1_BASE (PER_BASE + SPI1_BASE_OFFSET) -#define BCM283X_SPI2_BASE (PER_BASE + SPI2_BASE_OFFSET) - -#define BCM283X_SPI0_CS(BASE) __REG32(BASE + 0x0000) /* SPI Master Control and Status */ -#define BCM283X_SPI0_FIFO(BASE) __REG32(BASE + 0x0004) /* SPI Master TX and RX FIFOs */ -#define BCM283X_SPI0_CLK(BASE) __REG32(BASE + 0x0008) /* SPI Master Clock Divider */ -#define BCM283X_SPI0_DLEN(BASE) __REG32(BASE + 0x000c) /* SPI Master Data Length */ -#define BCM283X_SPI0_LTOH(BASE) __REG32(BASE + 0x0010) /* SPI LOSSI mode TOH */ -#define BCM283X_SPI0_DC(BASE) __REG32(BASE + 0x0014) /* SPI DMA DREQ Controls */ - -/* Register masks for SPI0_CS */ -#define BCM283X_SPI0_CS_LEN_LONG 0x02000000 /* Enable Long data word in Lossi mode if DMA_LEN is set */ -#define BCM283X_SPI0_CS_DMA_LEN 0x01000000 /* Enable DMA mode in Lossi mode */ -#define BCM283X_SPI0_CS_CSPOL2 0x00800000 /* Chip Select 2 Polarity */ -#define BCM283X_SPI0_CS_CSPOL1 0x00400000 /* Chip Select 1 Polarity */ -#define BCM283X_SPI0_CS_CSPOL0 0x00200000 /* Chip Select 0 Polarity */ -#define BCM283X_SPI0_CS_RXF 0x00100000 /* RXF - RX FIFO Full */ -#define BCM283X_SPI0_CS_RXR 0x00080000 /* RXR RX FIFO needs Reading (full) */ -#define BCM283X_SPI0_CS_TXD 0x00040000 /* TXD TX FIFO can accept Data */ -#define BCM283X_SPI0_CS_RXD 0x00020000 /* RXD RX FIFO contains Data */ -#define BCM283X_SPI0_CS_DONE 0x00010000 /* Done transfer Done */ -#define BCM283X_SPI0_CS_TE_EN 0x00008000 /* Unused */ -#define BCM283X_SPI0_CS_LMONO 0x00004000 /* Unused */ -#define BCM283X_SPI0_CS_LEN 0x00002000 /* LEN LoSSI enable */ -#define BCM283X_SPI0_CS_REN 0x00001000 /* REN Read Enable */ -#define BCM283X_SPI0_CS_ADCS 0x00000800 /* ADCS Automatically Deassert Chip Select */ -#define BCM283X_SPI0_CS_INTR 0x00000400 /* INTR Interrupt on RXR */ -#define BCM283X_SPI0_CS_INTD 0x00000200 /* INTD Interrupt on Done */ -#define BCM283X_SPI0_CS_DMAEN 0x00000100 /* DMAEN DMA Enable */ -#define BCM283X_SPI0_CS_TA 0x00000080 /* Transfer Active */ -#define BCM283X_SPI0_CS_CSPOL 0x00000040 /* Chip Select Polarity */ -#define BCM283X_SPI0_CS_CLEAR 0x00000030 /* Clear FIFO Clear RX and TX */ -#define BCM283X_SPI0_CS_CLEAR_RX 0x00000020 /* Clear FIFO Clear RX */ -#define BCM283X_SPI0_CS_CLEAR_TX 0x00000010 /* Clear FIFO Clear TX */ -#define BCM283X_SPI0_CS_CPOL 0x00000008 /* Clock Polarity */ -#define BCM283X_SPI0_CS_CPHA 0x00000004 /* Clock Phase */ -#define BCM283X_SPI0_CS_CS 0x00000003 /* Chip Select */ - -/* ARM Timer */ -#define ARM_TIMER_BASE (PER_BASE + 0xB000) -#define ARM_TIMER_LOAD __REG32(ARM_TIMER_BASE + 0x400) -#define ARM_TIMER_VALUE __REG32(ARM_TIMER_BASE + 0x404) -#define ARM_TIMER_CTRL __REG32(ARM_TIMER_BASE + 0x408) -#define ARM_TIMER_IRQCLR __REG32(ARM_TIMER_BASE + 0x40C) -#define ARM_TIMER_RAWIRQ __REG32(ARM_TIMER_BASE + 0x410) -#define ARM_TIMER_MASKIRQ __REG32(ARM_TIMER_BASE + 0x414) -#define ARM_TIMER_RELOAD __REG32(ARM_TIMER_BASE + 0x418) -#define ARM_TIMER_PREDIV __REG32(ARM_TIMER_BASE + 0x41C) -#define ARM_TIMER_CNTR __REG32(ARM_TIMER_BASE + 0x420) - -/* ARM Core Timer */ -#define C0TIMER_INTCTL __REG32(PER_BASE_40000000 + 0x40) /* Core0 timers Interrupt control */ -#define C1TIMER_INTCTL __REG32(PER_BASE_40000000 + 0x44) /* Core1 timers Interrupt control */ -#define C2TIMER_INTCTL __REG32(PER_BASE_40000000 + 0x48) /* Core2 timers Interrupt control */ -#define C3TIMER_INTCTL __REG32(PER_BASE_40000000 + 0x4C) /* Core3 timers Interrupt control */ -#define CORETIMER_INTCTL(n) __REG32(PER_BASE_40000000 + 0x40 + n*4) /* Coren timers Interrupt control */ - -/* - * Gtimer IRQ flag - */ -#define SYSTEM_TIMER_IRQ_0 (1 << 0) -#define SYSTEM_TIMER_IRQ_1 (1 << 1) -#define SYSTEM_TIMER_IRQ_2 (1 << 2) -#define SYSTEM_TIMER_IRQ_3 (1 << 3) - -#define NON_SECURE_TIMER_IRQ (1 << 1) -rt_inline void core_timer_enable(int cpu_id) -{ - CORETIMER_INTCTL(cpu_id) |= NON_SECURE_TIMER_IRQ; -} - -/* ARM Core Mailbox interrupt */ -#define C0MB_INTCTL __REG32(PER_BASE_40000000 + 0x50) /* Core0 Mailboxes Interrupt control */ -#define C1MB_INTCTL __REG32(PER_BASE_40000000 + 0x54) /* Core1 Mailboxes Interrupt control */ -#define C2MB_INTCTL __REG32(PER_BASE_40000000 + 0x58) /* Core2 Mailboxes Interrupt control */ -#define C3MB_INTCTL __REG32(PER_BASE_40000000 + 0x5C) /* Core3 Mailboxes Interrupt control */ -#define COREMB_INTCTL(n) __REG32(PER_BASE_40000000 + 0x50 + 4*n) /* Coren Mailboxes Interrupt control */ - -/* ARM Core IRQ/FIQ status */ -#define C0_IRQSOURCE __REG32(PER_BASE_40000000 + 0x60) /* Core0 IRQ Source */ -#define C1_IRQSOURCE __REG32(PER_BASE_40000000 + 0x64) /* Core1 IRQ Source */ -#define C2_IRQSOURCE __REG32(PER_BASE_40000000 + 0x68) /* Core2 IRQ Source */ -#define C3_IRQSOURCE __REG32(PER_BASE_40000000 + 0x6C) /* Core3 IRQ Source */ -#define C0_FIQSOURCE __REG32(PER_BASE_40000000 + 0x70) /* Core0 FIQ Source */ -#define C1_FIQSOURCE __REG32(PER_BASE_40000000 + 0x74) /* Core1 FIQ Source */ -#define C2_FIQSOURCE __REG32(PER_BASE_40000000 + 0x78) /* Core2 FIQ Source */ -#define C3_FIQSOURCE __REG32(PER_BASE_40000000 + 0x7C) /* Core3 FIQ Source */ -#define CORE_IRQSOURCE(n) __REG32(PER_BASE_40000000 + 0x60+ n*0x4) -#define CORE_FIQSOURCE(n) __REG32(PER_BASE_40000000 + 0x70+ n*0x4) - -#define CORE_MAILBOX3_SET(n) __REG32(PER_BASE_40000000 + 0x8C + n*0x10) -#define CORE_MAILBOX3_CLEAR(n) __REG32(PER_BASE_40000000 + 0xCC + n*0x10) -#define CORE_MAILBOX2_SET(n) __REG32(PER_BASE_40000000 + 0x88 + n*0x10) -#define CORE_MAILBOX2_CLEAR(n) __REG32(PER_BASE_40000000 + 0xC8 + n*0x10) -#define CORE_MAILBOX1_SET(n) __REG32(PER_BASE_40000000 + 0x84 + n*0x10) -#define CORE_MAILBOX1_CLEAR(n) __REG32(PER_BASE_40000000 + 0xC4 + n*0x10) -#define CORE_MAILBOX0_SET(n) __REG32(PER_BASE_40000000 + 0x80 + n*0x10) -#define CORE_MAILBOX0_CLEAR(n) __REG32(PER_BASE_40000000 + 0xC0 + n*0x10) - -/* For SMP IPI use MailBox0 */ -#define IPI_MAILBOX_SET CORE_MAILBOX0_SET -#define IPI_MAILBOX_CLEAR CORE_MAILBOX0_CLEAR -#define IPI_MAILBOX_INT_MASK (0x01) -rt_inline void enable_cpu_ipi_intr(int cpu_id) -{ - COREMB_INTCTL(cpu_id) = IPI_MAILBOX_INT_MASK; -} - -enum spi_bit_order -{ - BCM283X_SPI_BIT_ORDER_LSBFIRST = 0, /*!< LSB First */ - BCM283X_SPI_BIT_ORDER_MSBFIRST = 1 /*!< MSB First */ -}; - -enum spi_mode -{ - BCM283X_SPI_MODE0 = 0, /*!< CPOL = 0, CPHA = 0 */ - BCM283X_SPI_MODE1 = 1, /*!< CPOL = 0, CPHA = 1 */ - BCM283X_SPI_MODE2 = 2, /*!< CPOL = 1, CPHA = 0 */ - BCM283X_SPI_MODE3 = 3 /*!< CPOL = 1, CPHA = 1 */ -}; - -enum spi_chip_select -{ - BCM283X_SPI_CS0 = 0, /*!< Chip Select 0 */ - BCM283X_SPI_CS1 = 1, /*!< Chip Select 1 */ - BCM283X_SPI_CS2 = 2, /*!< Chip Select 2 (ie pins CS1 and CS2 are asserted) */ - BCM283X_SPI_CS_NONE = 3 /*!< No CS, control it yourself */ -}; - -enum spi_clock_divider -{ - BCM283X_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 3.814697260kHz on Rpi2, 6.1035156kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 7.629394531kHz on Rpi2, 12.20703125kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 15.25878906kHz on Rpi2, 24.4140625kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 30.51757813kHz on Rpi2, 48.828125kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 61.03515625kHz on Rpi2, 97.65625kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 122.0703125kHz on Rpi2, 195.3125kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 244.140625kHz on Rpi2, 390.625kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 488.28125kHz on Rpi2, 781.25kHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 976.5625kHz on Rpi2, 1.5625MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 1.953125MHz on Rpi2, 3.125MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 3.90625MHz on Rpi2, 6.250MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 7.8125MHz on Rpi2, 12.5MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 15.625MHz on Rpi2, 25MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 31.25MHz on Rpi2, 50MHz on RPI3 */ - BCM283X_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 62.5MHz on Rpi2, 100MHz on RPI3. Dont expect this speed to work reliably. */ - BCM283X_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 125MHz on Rpi2, 200MHz on RPI3, fastest you can get. Dont expect this speed to work reliably.*/ - BCM283X_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 3.814697260kHz on Rpi2, 6.1035156kHz on RPI3, same as 0/65536 */ -}; - -/*redefine for raspi*/ -typedef gpio_function_select raspi_pin_select; -typedef enum -{ - RPI_GPIO_P1_01 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_02 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_03 = BCM_GPIO_PIN_2, - RPI_GPIO_P1_04 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_05 = BCM_GPIO_PIN_3, - RPI_GPIO_P1_06 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_07 = BCM_GPIO_PIN_4, - RPI_GPIO_P1_08 = BCM_GPIO_PIN_14, - RPI_GPIO_P1_09 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_10 = BCM_GPIO_PIN_15, - RPI_GPIO_P1_11 = BCM_GPIO_PIN_17, - RPI_GPIO_P1_12 = BCM_GPIO_PIN_18, - RPI_GPIO_P1_13 = BCM_GPIO_PIN_27, - RPI_GPIO_P1_14 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_15 = BCM_GPIO_PIN_22, - RPI_GPIO_P1_16 = BCM_GPIO_PIN_23, - RPI_GPIO_P1_17 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_18 = BCM_GPIO_PIN_24, - RPI_GPIO_P1_19 = BCM_GPIO_PIN_10, - RPI_GPIO_P1_20 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_21 = BCM_GPIO_PIN_9, - RPI_GPIO_P1_22 = BCM_GPIO_PIN_25, - RPI_GPIO_P1_23 = BCM_GPIO_PIN_11, - RPI_GPIO_P1_24 = BCM_GPIO_PIN_8, - RPI_GPIO_P1_25 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_26 = BCM_GPIO_PIN_7, - RPI_GPIO_P1_27 = BCM_GPIO_PIN_0, - RPI_GPIO_P1_28 = BCM_GPIO_PIN_1, - RPI_GPIO_P1_29 = BCM_GPIO_PIN_5, - RPI_GPIO_P1_30 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_31 = BCM_GPIO_PIN_6, - RPI_GPIO_P1_32 = BCM_GPIO_PIN_12, - RPI_GPIO_P1_33 = BCM_GPIO_PIN_13, - RPI_GPIO_P1_34 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_35 = BCM_GPIO_PIN_19, - RPI_GPIO_P1_36 = BCM_GPIO_PIN_16, - RPI_GPIO_P1_37 = BCM_GPIO_PIN_26, - RPI_GPIO_P1_38 = BCM_GPIO_PIN_20, - RPI_GPIO_P1_39 = BCM_GPIO_PIN_NULL, - RPI_GPIO_P1_40 = BCM_GPIO_PIN_21, -} raspi_gpio_pin; - -typedef enum -{ - BCM283X_I2C_CLOCK_DIVIDER_2500 = 2500, /* 2500 = 10us = 100 kHz */ - BCM283X_I2C_CLOCK_DIVIDER_626 = 626, /* 622 = 2.504us = 399.3610 kHz */ - BCM283X_I2C_CLOCK_DIVIDER_150 = 150, /* 150 = 60ns = 1.666 MHz (default at reset) */ - BCM283X_I2C_CLOCK_DIVIDER_148 = 148 /* 148 = 59ns = 1.689 MHz */ -} i2c_clock_divider; - -typedef enum -{ - BCM283X_I2C_REASON_OK = 0x00, /* Success */ - BCM283X_I2C_REASON_ERROR_NACK = 0x01, /* Received a NACK */ - BCM283X_I2C_REASON_ERROR_CLKT = 0x02, /* Received Clock Stretch Timeout */ - BCM283X_I2C_REASON_ERROR_DATA = 0x04 /* Not all data is sent / received */ -} i2c_reason_codes; - -#endif diff --git a/bsp/raspberry-pi/raspi3-64/link.lds b/bsp/raspberry-pi/raspi3-64/link.lds deleted file mode 100644 index 953be4c28b..0000000000 --- a/bsp/raspberry-pi/raspi3-64/link.lds +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * 2017-5-30 bernard first version - */ - -/* _EL1_STACK_SIZE = DEFINED(_EL1_STACK_SIZE) ? _EL1_STACK_SIZE : 0x20000; */ - -SECTIONS -{ - . = 0x80000; - . = ALIGN(4096); - .text : - { - KEEP(*(.text.entrypoint)) /* The entry point */ - *(.vectors) - *(.text) /* remaining code */ - *(.text.*) /* remaining code */ - - *(.rodata) /* read-only data (constants) */ - *(.rodata*) - *(.glue_7) - *(.glue_7t) - *(.gnu.linkonce.t*) - - *(COMMON) - - /* section information for finsh shell */ - . = ALIGN(16); - __fsymtab_start = .; - KEEP(*(FSymTab)) - __fsymtab_end = .; - . = ALIGN(16); - __vsymtab_start = .; - KEEP(*(VSymTab)) - __vsymtab_end = .; - . = ALIGN(16); - - /* section information for initial. */ - . = ALIGN(16); - __rt_init_start = .; - KEEP(*(SORT(.rti_fn*))) - __rt_init_end = .; - . = ALIGN(16); - - . = ALIGN(16); - _etext = .; - } - - .eh_frame_hdr : - { - *(.eh_frame_hdr) - *(.eh_frame_entry) - } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - - . = ALIGN(16); - .data : - { - *(.data) - *(.data.*) - - *(.data1) - *(.data1.*) - - . = ALIGN(16); - _gp = ABSOLUTE(.); /* Base of small data */ - - *(.sdata) - *(.sdata.*) - } - - . = ALIGN(16); - .ctors : - { - PROVIDE(__ctors_start__ = .); - /* new GCC version uses .init_array */ - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE(__ctors_end__ = .); - } - - .dtors : - { - PROVIDE(__dtors_start__ = .); - KEEP(*(SORT(.dtors.*))) - KEEP(*(.dtors)) - PROVIDE(__dtors_end__ = .); - } - - . = ALIGN(16); - .bss : - { - PROVIDE(__bss_start = .); - *(.bss) - *(.bss.*) - *(.dynbss) - - PROVIDE(__bss_end = .); - } - _end = .; - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} - -__bss_size = SIZEOF(.bss); diff --git a/bsp/raspberry-pi/raspi3-64/qemu-64.bat b/bsp/raspberry-pi/raspi3-64/qemu-64.bat deleted file mode 100755 index b57c8a5b5b..0000000000 --- a/bsp/raspberry-pi/raspi3-64/qemu-64.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -if exist sd.bin goto run -qemu-img create -f raw sd.bin 64M - -:run -qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio -sd sd.bin \ No newline at end of file diff --git a/bsp/raspberry-pi/raspi3-64/qemu-64.sh b/bsp/raspberry-pi/raspi3-64/qemu-64.sh deleted file mode 100644 index db14a102df..0000000000 --- a/bsp/raspberry-pi/raspi3-64/qemu-64.sh +++ /dev/null @@ -1,4 +0,0 @@ -if [ ! -f "sd.bin" ]; then -dd if=/dev/zero of=sd.bin bs=1024 count=65536 -fi -qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio -sd sd.bin -nographic -monitor pty \ No newline at end of file diff --git a/bsp/raspberry-pi/raspi3-64/qemu.py b/bsp/raspberry-pi/raspi3-64/qemu.py new file mode 100755 index 0000000000..01326e54c3 --- /dev/null +++ b/bsp/raspberry-pi/raspi3-64/qemu.py @@ -0,0 +1,74 @@ +#!/bin/python +# -*- coding: utf-8 -*- +import os, sys, re, shutil + +with open('rtconfig.h', 'r') as file: + rtconfig_header = file.read() + +if os.getenv('RTT_QEMU_ROOT'): + RTT_QEMU_ROOT = os.getenv('RTT_QEMU_ROOT') +else: + RTT_QEMU_ROOT = "" + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.join(os.getcwd(), '..', '..', '..') + +sys.path.append(RTT_ROOT + '/tools') + +from building import * +import dtc + +dts_name = "bcm283x-rpi-3-b" + +dtc.dts_to_dtb(RTT_ROOT, ["../dm/dts/" + dts_name + ".dts"], include_paths = [os.getcwd() + '/../dm/include'], + ignore_warning = ["simple_bus_reg", "unit_address_vs_reg", "clocks_is_cell", "gpios_property", "unique_unit_address"]) +try: + shutil.move("../dm/dts/" + dts_name + ".dtb", dts_name + ".dtb") +except: + exit(-1) + +opt = sys.argv + +q_graphic = "-nographic" +q_debug = "" + +def is_opt(key, inkey): + if str("-" + key) == inkey: + return True + return False + +for i in range(len(opt)): + if i == 0: + continue + inkey = opt[i] + + if is_opt("debug", inkey): q_debug = "-S -s" + if is_opt("graphic", inkey): q_graphic = "-device usb-kbd,port=1.2 -device usb-mouse,port=1.3" + +disk = "sd.qcow2" +if not os.path.exists(disk): + os.system("qemu-img create -f qcow2 {} 64M".format(disk)) + +flash = "flash.bin" +if not os.path.exists(flash): + os.system("qemu-img create -f raw {} 1M".format(flash)) + +os.system(""" +{}qemu-system-aarch64 \ + -M raspi3b \ + -m 1G \ + -kernel kernel8.img \ + -dtb {}.dtb \ + -append "console=ttyAMA0 earlycon=pl011,0x3f201000 cma=8M coherent_pool=2M root=sd0p0 rootfstype=elm rootwait rw" \ + -serial mon:stdio \ + -drive if=sd,file={},format=qcow2 \ + -device ds1338,address=0x68,bus=i2c-bus.0 \ + -device m25p80,write-enable=true,drive=flash0,bus=spi \ + -blockdev node-name=flash0,driver=file,filename={} \ + -device usb-hub,port=1 \ + -device usb-net,netdev=net0,port=1.1 -netdev user,id=net0 \ + {} \ + {} +""".format(RTT_QEMU_ROOT, dts_name, disk, flash, q_graphic, q_debug)) diff --git a/bsp/raspberry-pi/raspi3-64/rtconfig.h b/bsp/raspberry-pi/raspi3-64/rtconfig.h index 07be2b0c7c..70bb92ce6a 100644 --- a/bsp/raspberry-pi/raspi3-64/rtconfig.h +++ b/bsp/raspberry-pi/raspi3-64/rtconfig.h @@ -7,17 +7,6 @@ /* rt_vsnprintf options */ -#define RT_KLIBC_USING_VSNPRINTF_LONGLONG -#define RT_KLIBC_USING_VSNPRINTF_STANDARD -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6 -#define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 -#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4 /* end of rt_vsnprintf options */ /* rt_vsscanf options */ @@ -72,8 +61,9 @@ /* end of rt_strnlen options */ /* end of klibc options */ -#define RT_NAME_MAX 12 -#define RT_CPUS_NR 1 +#define RT_NAME_MAX 24 +#define RT_USING_SMP +#define RT_CPUS_NR 4 #define RT_ALIGN_SIZE 8 #define RT_THREAD_PRIORITY_32 #define RT_THREAD_PRIORITY_MAX 32 @@ -84,9 +74,12 @@ #define RT_USING_IDLE_HOOK #define RT_IDLE_HOOK_LIST_SIZE 4 #define IDLE_THREAD_STACK_SIZE 8192 +#define SYSTEM_THREAD_STACK_SIZE 8192 #define RT_USING_TIMER_SOFT #define RT_TIMER_THREAD_PRIO 4 -#define RT_TIMER_THREAD_STACK_SIZE 4096 +#define RT_TIMER_THREAD_STACK_SIZE 8192 +#define RT_USING_CPU_USAGE_TRACER +#define RT_CPU_USAGE_CALC_INTERVAL_MS 200 /* kservice options */ @@ -117,11 +110,13 @@ /* end of Memory Management */ #define RT_USING_DEVICE #define RT_USING_DEVICE_OPS +#define RT_USING_INTERRUPT_INFO #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 512 #define RT_CONSOLE_DEVICE_NAME "uart1" #define RT_USING_CONSOLE_OUTPUT_CTL #define RT_VER_NUM 0x50300 +#define RT_USING_STDC_ATOMIC #define RT_BACKTRACE_LEVEL_MAX_NR 32 /* end of RT-Thread Kernel */ @@ -131,6 +126,7 @@ #define ARCH_RAM_OFFSET 0 #define ARCH_SECONDARY_CPU_STACK_SIZE 4096 #define ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS +#define ARCH_USING_GENERIC_CPUID #define ARCH_HEAP_SIZE 0x4000000 #define ARCH_INIT_PAGE_SIZE 0x200000 /* end of AArch64 Architecture Configuration */ @@ -142,20 +138,21 @@ #define ARCH_ARM_MMU #define ARCH_ARMV8 #define ARCH_USING_ASID +#define ARCH_USING_HW_THREAD_SELF #define ARCH_USING_IRQ_CTX_LIST /* RT-Thread Components */ #define RT_USING_COMPONENTS_INIT #define RT_USING_USER_MAIN -#define RT_MAIN_THREAD_STACK_SIZE 4096 +#define RT_MAIN_THREAD_STACK_SIZE 8192 #define RT_MAIN_THREAD_PRIORITY 10 #define RT_USING_MSH #define RT_USING_FINSH #define FINSH_USING_MSH #define FINSH_THREAD_NAME "tshell" #define FINSH_THREAD_PRIORITY 20 -#define FINSH_THREAD_STACK_SIZE 4096 +#define FINSH_THREAD_STACK_SIZE 8192 #define FINSH_USING_HISTORY #define FINSH_HISTORY_LINES 5 #define FINSH_USING_SYMTAB @@ -171,9 +168,7 @@ #define DFS_USING_POSIX #define DFS_USING_WORKDIR #define DFS_FD_MAX 16 -#define RT_USING_DFS_V1 -#define DFS_FILESYSTEMS_MAX 2 -#define DFS_FILESYSTEM_TYPES_MAX 2 +#define RT_USING_DFS_V2 #define RT_USING_DFS_ELMFAT /* elm-chan's FatFs, Generic FAT Filesystem Module */ @@ -195,25 +190,79 @@ /* Device Drivers */ +#define RT_USING_DM #define RT_USING_DEVICE_IPC #define RT_UNAMED_PIPE_NUMBER 64 +#define RT_USING_SYSTEM_WORKQUEUE +#define RT_SYSTEM_WORKQUEUE_STACKSIZE 8192 +#define RT_SYSTEM_WORKQUEUE_PRIORITY 23 #define RT_USING_SERIAL #define RT_USING_SERIAL_V1 #define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_SERIAL_BYPASS +#define RT_SERIAL_PL011 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_BCM2835AUX #define RT_USING_CLOCK_TIME +#define RT_CLOCK_TIME_ARM_ARCH +#define RT_CLOCK_TIME_BCM2835 #define RT_USING_I2C #define RT_I2C_DEBUG -#define RT_USING_I2C_BITOPS +#define RT_I2C_BCM2835 +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM +#define RT_USING_PWM +#define RT_PWM_BCM2835 +#define RT_USING_MTD_NOR +#define RT_USING_MTD_NOR_SPI +#define RT_USING_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 8192 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_DS1307 #define RT_USING_SDIO -#define RT_SDIO_STACK_SIZE 2048 +#define RT_SDIO_STACK_SIZE 8192 #define RT_SDIO_THREAD_PRIORITY 15 -#define RT_MMCSD_STACK_SIZE 4096 +#define RT_MMCSD_STACK_SIZE 8192 #define RT_MMCSD_THREAD_PRIORITY 22 #define RT_MMCSD_MAX_PARTITION 16 -#define RT_SDIO_DEBUG +#define RT_USING_SDHCI +#define RT_SDIO_SDHCI_IPROC #define RT_USING_SPI #define RT_USING_SPI_ISR +#define RT_USING_SFUD +#define RT_SFUD_USING_SFDP +#define RT_SFUD_USING_FLASH_INFO_TABLE +#define RT_SFUD_SPI_MAX_HZ 50000000 +#define RT_SPI_BCM2835 #define RT_USING_WDT +#define RT_WDT_BCM2835 +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#define RT_AUDIO_RECORD_PIPE_SIZE 2048 +#define RT_AUDIO_BCM2835_I2S +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_BCM2708 +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RASPI_CLUT224 +#define RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH "../dm/graphic/logo/logo-raspi-clut224.ppm" +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_RNG_BCM2835 +#define RT_USING_LED +#define RT_LED_GPIO +#define RT_USING_MBOX +#define RT_MBOX_BCM2835 +#define RT_USING_PHYE +#define RT_PHYE_GENERIC_USB #define RT_USING_BLK /* Partition Types */ @@ -221,7 +270,53 @@ #define RT_BLK_PARTITION_DFS #define RT_BLK_PARTITION_EFI /* end of Partition Types */ +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_RASPBERRYPI +#define RT_USING_REGULATOR +#define RT_REGULATOR_FIXED +#define RT_REGULATOR_GPIO +#define RT_USING_RESET + +/* Power Management (PM) Domains device drivers */ + +#define RT_PMDOMAIN_BCM2835 +#define RT_PMDOMAIN_RASPBERRYPI +/* end of Power Management (PM) Domains device drivers */ +#define RT_USING_THERMAL + +/* Thermal Sensors Drivers */ + +#define RT_THERMAL_BCM2835 + +/* Thermal Cool Drivers */ + +#define RT_USING_NVMEM +#define RT_NVMEM_RASPBERRYPI_OTP +#define RT_USING_DMA +#define RT_DMA_BCM2835 +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_BCM2835_PM +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PIC +#define MAX_HANDLERS 256 +#define RT_PIC_BCM2835_INTC +#define RT_PIC_BCM2836_L1_INTC #define RT_USING_PIN +#define RT_PIN_BCM_VIRT +#define RT_PIN_RASPBERRYPI_EXP +#define RT_USING_PINCTRL +#define RT_PINCTRL_BCM2835 +#define RT_USING_CLK +#define RT_CLK_BCM2835 +#define RT_CLK_RASPBERRYPI + +/* SoC (System on Chip) Drivers */ + +#define RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR +/* end of SoC (System on Chip) Drivers */ /* end of Device Drivers */ /* C/C++ and POSIX layer */ @@ -239,6 +334,14 @@ /* POSIX (Portable Operating System Interface) layer */ +#define RT_USING_POSIX_FS +#define RT_USING_POSIX_DEVIO +#define RT_USING_POSIX_STDIO +#define RT_USING_POSIX_POLL +#define RT_USING_POSIX_TERMIOS +#define RT_USING_POSIX_DELAY +#define RT_USING_POSIX_CLOCK +#define RT_USING_POSIX_TIMER /* Interprocess Communication (IPC) */ @@ -251,6 +354,68 @@ /* Network */ +#define RT_USING_SAL +#define SAL_INTERNET_CHECK +#define SOCKET_TABLE_STEP_LEN 4 + +/* Docking with protocol stacks */ + +#define SAL_USING_LWIP +/* end of Docking with protocol stacks */ +#define SAL_USING_POSIX +#define RT_USING_NETDEV +#define NETDEV_USING_IFCONFIG +#define NETDEV_USING_PING +#define NETDEV_USING_NETSTAT +#define NETDEV_USING_AUTO_DEFAULT +#define NETDEV_IPV4 1 +#define NETDEV_IPV6 0 +#define RT_USING_LWIP +#define RT_USING_LWIP212 +#define RT_USING_LWIP_VER_NUM 0x20102 +#define RT_LWIP_MEM_ALIGNMENT 8 +#define RT_LWIP_IGMP +#define RT_LWIP_ICMP +#define RT_LWIP_DNS +#define RT_LWIP_DHCP +#define IP_SOF_BROADCAST 1 +#define IP_SOF_BROADCAST_RECV 1 + +/* Static IPv4 Address */ + +#define RT_LWIP_IPADDR "192.168.1.30" +#define RT_LWIP_GWADDR "192.168.1.1" +#define RT_LWIP_MSKADDR "255.255.255.0" +/* end of Static IPv4 Address */ +#define RT_LWIP_UDP +#define RT_LWIP_TCP +#define RT_LWIP_RAW +#define RT_MEMP_NUM_NETCONN 8 +#define RT_LWIP_PBUF_NUM 16 +#define RT_LWIP_RAW_PCB_NUM 4 +#define RT_LWIP_UDP_PCB_NUM 4 +#define RT_LWIP_TCP_PCB_NUM 4 +#define RT_LWIP_TCP_SEG_NUM 40 +#define RT_LWIP_TCP_SND_BUF 8196 +#define RT_LWIP_TCP_WND 8196 +#define RT_LWIP_TCPTHREAD_PRIORITY 10 +#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 +#define RT_LWIP_TCPTHREAD_STACKSIZE 16384 +#define LWIP_NO_RX_THREAD +#define LWIP_NO_TX_THREAD +#define RT_LWIP_ETHTHREAD_PRIORITY 12 +#define RT_LWIP_ETHTHREAD_STACKSIZE 8192 +#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define RT_LWIP_NETIF_NAMESIZE 6 +#define SO_REUSE 1 +#define LWIP_SO_RCVTIMEO 1 +#define LWIP_SO_SNDTIMEO 1 +#define LWIP_SO_RCVBUF 1 +#define LWIP_SO_LINGER 0 +#define LWIP_NETIF_LOOPBACK 0 +#define RT_LWIP_USING_PING /* end of Network */ /* Memory protection */ @@ -259,6 +424,7 @@ /* Utilities */ +#define RT_USING_RESOURCE_ID #define RT_USING_ADT #define RT_USING_ADT_AVL #define RT_USING_ADT_BITMAP @@ -270,6 +436,8 @@ #define RT_PAGE_AFFINITY_BLOCK_SIZE 0x1000 #define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMBLOCK +#define RT_INIT_MEMORY_REGIONS 128 /* Debugging */ @@ -406,14 +574,6 @@ /* GD32 Drivers */ /* end of GD32 Drivers */ - -/* HPMicro SDK */ - -/* end of HPMicro SDK */ - -/* FT32 HAL & SDK Drivers */ - -/* end of FT32 HAL & SDK Drivers */ /* end of HAL & SDK Drivers */ /* sensors drivers */ @@ -493,35 +653,6 @@ /* end of Arduino libraries */ /* end of RT-Thread online packages */ -#define BCM2836_SOC #define SOC_BCM283x -/* Hardware Drivers Config */ - -/* BCM Peripheral Drivers */ - -#define BSP_USING_UART -#define RT_USING_UART1 -#define BSP_USING_PIN -#define BSP_USING_CORETIMER -#define BSP_USING_SYSTIMER -#define RT_USING_SYSTIMER1 -#define RT_USING_SYSTIMER3 -#define BSP_USING_I2C -#define BSP_USING_I2C1 -#define BSP_USING_SPI -#define BSP_USING_SPI0_BUS -#define BSP_USING_SPI0_DEVICE0 -#define BSP_USING_WDT -#define BSP_USING_SDIO -#define BSP_USING_SDIO0 -/* end of BCM Peripheral Drivers */ - -/* Board Peripheral Drivers */ - -#define BSP_USING_HDMI -#define BSP_USING_HDMI_DISPLAY -/* end of Board Peripheral Drivers */ -/* end of Hardware Drivers Config */ - #endif diff --git a/bsp/raspberry-pi/raspi3-64/rtconfig.py b/bsp/raspberry-pi/raspi3-64/rtconfig.py index cef22a954e..d49cfdbc58 100644 --- a/bsp/raspberry-pi/raspi3-64/rtconfig.py +++ b/bsp/raspberry-pi/raspi3-64/rtconfig.py @@ -26,6 +26,7 @@ if PLATFORM == 'gcc': PREFIX = os.getenv('RTT_CC_PREFIX') or 'aarch64-none-elf-' CC = PREFIX + 'gcc' CXX = PREFIX + 'g++' + CPP = PREFIX + 'cpp' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' @@ -34,7 +35,8 @@ if PLATFORM == 'gcc': OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' - DEVICE = ' -march=armv8-a -mtune=cortex-a53' + CPPFLAGS = ' -nostdinc -undef -E -P -x assembler-with-cpp' + DEVICE = ' -march=armv8-a -mtune=cortex-a53 -fdiagnostics-color=always -ftree-vectorize -ffast-math -funwind-tables -fno-strict-aliasing' CFLAGS = DEVICE + ' -Wall -Wno-cpp' AFLAGS = ' -c' + ' -x assembler-with-cpp -D__ASSEMBLY__' LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds' @@ -51,3 +53,10 @@ if PLATFORM == 'gcc': DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' POST_ACTION = OBJCPY + ' -O binary $TARGET kernel8.img\n' + SIZE + ' $TARGET \n' + + +def dist_handle(BSP_ROOT, dist_dir): + import sys + sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools')) + from sdk_dist import dist_do_building + dist_do_building(BSP_ROOT, dist_dir) diff --git a/bsp/raspberry-pi/raspi4-64/.config b/bsp/raspberry-pi/raspi4-64/.config index ecdaf52e70..d471b43c31 100644 --- a/bsp/raspberry-pi/raspi4-64/.config +++ b/bsp/raspberry-pi/raspi4-64/.config @@ -12,17 +12,7 @@ # # CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y -# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6 -CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9 -CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set # end of rt_vsnprintf options # @@ -116,7 +106,7 @@ CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 # end of rt_strnlen options # end of klibc options -CONFIG_RT_NAME_MAX=12 +CONFIG_RT_NAME_MAX=24 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set # CONFIG_RT_USING_NANO is not set # CONFIG_RT_USING_SMART is not set @@ -141,7 +131,8 @@ CONFIG_RT_USING_TIMER_SOFT=y CONFIG_RT_TIMER_THREAD_PRIO=4 CONFIG_RT_TIMER_THREAD_STACK_SIZE=8192 # CONFIG_RT_USING_TIMER_ALL_SOFT is not set -# CONFIG_RT_USING_CPU_USAGE_TRACER is not set +CONFIG_RT_USING_CPU_USAGE_TRACER=y +CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 # # kservice options @@ -173,7 +164,7 @@ CONFIG_RT_USING_MESSAGEQUEUE=y # # Memory Management # -# CONFIG_RT_USING_MEMPOOL is not set +CONFIG_RT_USING_MEMPOOL=y # CONFIG_RT_USING_SMALL_MEM is not set CONFIG_RT_USING_SLAB=y # CONFIG_RT_USING_MEMHEAP is not set @@ -203,13 +194,14 @@ CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32 # # AArch64 Architecture Configuration # -CONFIG_ARCH_TEXT_OFFSET=0x200000 +CONFIG_ARCH_TEXT_OFFSET=0x208000 CONFIG_ARCH_RAM_OFFSET=0 CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -# CONFIG_ARCH_USING_GENERIC_CPUID is not set +CONFIG_ARCH_USING_GENERIC_CPUID=y CONFIG_ARCH_HEAP_SIZE=0x4000000 CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +# CONFIG_ARCH_USING_CPUIDLE is not set # end of AArch64 Architecture Configuration CONFIG_ARCH_CPU_64BIT=y @@ -220,6 +212,7 @@ CONFIG_ARCH_ARM=y CONFIG_ARCH_ARM_MMU=y CONFIG_ARCH_ARMV8=y CONFIG_ARCH_USING_ASID=y +CONFIG_ARCH_USING_HW_THREAD_SELF=y CONFIG_ARCH_USING_IRQ_CTX_LIST=y # @@ -227,7 +220,7 @@ CONFIG_ARCH_USING_IRQ_CTX_LIST=y # CONFIG_RT_USING_COMPONENTS_INIT=y CONFIG_RT_USING_USER_MAIN=y -CONFIG_RT_MAIN_THREAD_STACK_SIZE=8192 +CONFIG_RT_MAIN_THREAD_STACK_SIZE=16384 CONFIG_RT_MAIN_THREAD_PRIORITY=10 # CONFIG_RT_USING_LEGACY is not set CONFIG_RT_USING_MSH=y @@ -296,7 +289,7 @@ CONFIG_RT_USING_DFS_TMPFS=y # # Device Drivers # -# CONFIG_RT_USING_DM is not set +CONFIG_RT_USING_DM=y CONFIG_RT_USING_DEV_BUS=y CONFIG_RT_USING_DEVICE_IPC=y CONFIG_RT_UNAMED_PIPE_NUMBER=64 @@ -308,38 +301,77 @@ CONFIG_RT_USING_SERIAL_V1=y # CONFIG_RT_USING_SERIAL_V2 is not set CONFIG_RT_SERIAL_USING_DMA=y CONFIG_RT_SERIAL_RB_BUFSZ=64 -# CONFIG_RT_USING_SERIAL_BYPASS is not set +CONFIG_RT_USING_SERIAL_BYPASS=y +# CONFIG_RT_SERIAL_EARLY_HVC is not set +CONFIG_RT_SERIAL_PL011=y +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +CONFIG_RT_SERIAL_8250_BCM2835AUX=y +# CONFIG_RT_SERIAL_8250_BCM7271 is not set # CONFIG_RT_USING_CAN is not set +# CONFIG_RT_USING_ADC is not set CONFIG_RT_USING_CLOCK_TIME=y +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_RT_CLOCK_TIME_ARM_ARCH=y +CONFIG_RT_CLOCK_TIME_BCM2835=y +CONFIG_RT_USING_ETHERNET=y +# CONFIG_RT_ETHERNET_CADENCE is not set +# CONFIG_RT_ETHERNET_DWMAC is not set +CONFIG_RT_ETHERNET_BCMGENET=y 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_I2C_BITOPS is not set # CONFIG_RT_USING_SOFT_I2C is not set +CONFIG_RT_I2C_BCM2835=y +CONFIG_RT_I2C_BRCMSTB=y # CONFIG_RT_USING_PHY is not set -# CONFIG_RT_USING_PHY_V2 is not set -# CONFIG_RT_USING_ADC is not set +CONFIG_RT_USING_PHY_V2=y +# CONFIG_RT_PHY_V2_REALTEK is not set +CONFIG_RT_PHY_MDIO_BCM_UNIMAC=y +CONFIG_RT_PHY_BCM54213=y # CONFIG_RT_USING_DAC is not set CONFIG_RT_USING_NULL=y CONFIG_RT_USING_ZERO=y CONFIG_RT_USING_RANDOM=y -# CONFIG_RT_USING_PWM is not set +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_BCM2835=y +CONFIG_RT_PWM_BRCMSTB=y +# CONFIG_RT_PWM_RP1 is not set # CONFIG_RT_USING_PULSE_ENCODER is not set # CONFIG_RT_USING_INPUT_CAPTURE is not set # CONFIG_RT_USING_MTD_NOR is not set # CONFIG_RT_USING_MTD_NAND is not set # CONFIG_RT_USING_PM is not set CONFIG_RT_USING_RTC=y -# CONFIG_RT_USING_ALARM is not set -CONFIG_RT_USING_SOFT_RTC=y +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=8192 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_DS1302 is not set +CONFIG_RT_RTC_DS1307=y +# CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +# CONFIG_RT_RTC_PCF8523 is not set +# CONFIG_RT_RTC_PCF8563 is not set +# CONFIG_RT_RTC_PL031 is not set +# CONFIG_RT_RTC_RX8010 is not set +# CONFIG_RT_RTC_RPI is not set CONFIG_RT_USING_SDIO=y CONFIG_RT_SDIO_STACK_SIZE=8192 CONFIG_RT_SDIO_THREAD_PRIORITY=15 -CONFIG_RT_MMCSD_STACK_SIZE=8192 +CONFIG_RT_MMCSD_STACK_SIZE=16384 CONFIG_RT_MMCSD_THREAD_PRIORITY=22 CONFIG_RT_MMCSD_MAX_PARTITION=16 # CONFIG_RT_SDIO_DEBUG is not set -# CONFIG_RT_USING_SDHCI is not set +CONFIG_RT_USING_SDHCI=y +# CONFIG_RT_SDIO_SDHCI_PCI is not set +# CONFIG_RT_SDIO_DW_MMC is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +CONFIG_RT_SDIO_SDHCI_BRCMSTB=y +CONFIG_RT_SDIO_SDHCI_IPROC=y CONFIG_RT_USING_SPI=y CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SPI_BITOPS is not set @@ -349,14 +381,81 @@ CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SFUD is not set # CONFIG_RT_USING_ENC28J60 is not set # CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_BCM2835=y +CONFIG_RT_SPI_BCM2835AUX=y CONFIG_RT_USING_WDT=y -# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_WDT_DW is not set +# CONFIG_RT_WDT_I6300ESB is not set +CONFIG_RT_WDT_BCM2835=y +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=2 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=2048 +# CONFIG_RT_AUDIO_INTEL_HDA is not set +CONFIG_RT_AUDIO_BCM2835_I2S=y # CONFIG_RT_USING_SENSOR is not set CONFIG_RT_USING_TOUCH=y # CONFIG_RT_TOUCH_PIN_IRQ is not set CONFIG_RT_USING_LCD=y -# CONFIG_RT_USING_HWCRYPTO is not set +CONFIG_RT_USING_GRAPHIC=y +CONFIG_RT_GRAPHIC_BACKLIGHT=y +# CONFIG_RT_GRAPHIC_BACKLIGHT_GPIO is not set +# CONFIG_RT_GRAPHIC_BACKLIGHT_PWM is not set +CONFIG_RT_GRAPHIC_BACKLIGHT_RPI=y +CONFIG_RT_GRAPHIC_FB=y +CONFIG_RT_GRAPHIC_FB_ILI9486=y +CONFIG_RT_GRAPHIC_FB_SIMPLE=y +CONFIG_RT_GRAPHIC_FB_BCM2708=y +CONFIG_RT_GRAPHIC_FB_RPISENSE=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224=y +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH="../dm/graphic/logo/logo-raspi-clut224.ppm" +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +# CONFIG_RT_HWCRYPTO_USING_AES is not set +# CONFIG_RT_HWCRYPTO_USING_DES is not set +# CONFIG_RT_HWCRYPTO_USING_3DES is not set +# CONFIG_RT_HWCRYPTO_USING_RC4 is not set +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set +CONFIG_RT_HWCRYPTO_RNG_BCM2835=y +CONFIG_RT_HWCRYPTO_RNG_IPROC_RNG200=y # CONFIG_RT_USING_WIFI is not set +# CONFIG_RT_USING_PTP is not set +CONFIG_RT_USING_LED=y +CONFIG_RT_LED_GPIO=y +# CONFIG_RT_LED_PWM is not set +# CONFIG_RT_LED_SYSCON is not set +CONFIG_RT_USING_INPUT=y +CONFIG_RT_INPUT_POWER=y +# CONFIG_RT_INPUT_UAPI is not set +CONFIG_RT_INPUT_JOYSTICK=y +CONFIG_RT_INPUT_JOYSTICK_RPISENSE=y +# CONFIG_RT_INPUT_KEYBOARD is not set +# CONFIG_RT_INPUT_MISC is not set +CONFIG_RT_INPUT_TOUCHSCREEN=y +CONFIG_RT_INPUT_TOUCHSCREEN_ADS7846=y +# CONFIG_RT_INPUT_TOUCHSCREEN_GOODIX is not set +CONFIG_RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW=y +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_PIC is not set +CONFIG_RT_MBOX_BCM2835=y +# CONFIG_RT_USING_HWSPINLOCK is not set +# CONFIG_RT_USING_RPMSG is not set +CONFIG_RT_USING_PHYE=y +CONFIG_RT_PHYE_GENERIC_USB=y +# CONFIG_RT_USING_ATA is not set +# CONFIG_RT_USING_NVME is not set CONFIG_RT_USING_BLK=y # @@ -366,11 +465,132 @@ CONFIG_RT_BLK_PARTITION_DFS=y CONFIG_RT_BLK_PARTITION_EFI=y # end of Partition Types -# CONFIG_RT_USING_REGULATOR is not set +CONFIG_RT_USING_SCSI=y +CONFIG_RT_SCSI_SD=y +# CONFIG_RT_SCSI_CDROM is not set +# CONFIG_RT_USING_UFS is not set +CONFIG_RT_USING_FIRMWARE=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set +# CONFIG_RT_FIRMWARE_ARM_SCMI is not set +CONFIG_RT_FIRMWARE_RASPBERRYPI=y +# CONFIG_RT_USING_TEE is not set +# CONFIG_RT_USING_HWCACHE is not set +CONFIG_RT_USING_DVFS=y +CONFIG_RT_USING_DVFS_EVENT=y +CONFIG_RT_USING_DVFS_OPP_RETRY_MAX=10 + +# +# DVFS Event Drivers +# + +# +# DVFS CPUfreq Drivers +# +CONFIG_RT_DVFS_RASPBERRY_CPUFREQ=y + +# +# DVFS Devfreq Drivers +# +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_FAN53555 is not set +CONFIG_RT_REGULATOR_FIXED=y +CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set +CONFIG_RT_USING_RESET=y +CONFIG_RT_RESET_SIMPLE=y +CONFIG_RT_RESET_BRCMSTB_RESCAL=y +CONFIG_RT_RESET_BRCMSTB=y +CONFIG_RT_RESET_RASPBERRYPI=y + +# +# Power Management (PM) Domains device drivers +# +# CONFIG_RT_PMDOMAIN_BCM2835 is not set +CONFIG_RT_PMDOMAIN_RASPBERRYPI=y +# end of Power Management (PM) Domains device drivers + +# CONFIG_RT_USING_POWER_RESET is not set # CONFIG_RT_USING_POWER_SUPPLY is not set +CONFIG_RT_USING_THERMAL=y + +# +# Thermal Sensors Drivers +# +CONFIG_RT_THERMAL_BCM2835=y +CONFIG_RT_THERMAL_BCM2711=y + +# +# Thermal Cool Drivers +# +# CONFIG_RT_THERMAL_COOL_DVFS is not set +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set +# CONFIG_RT_THERMAL_COOL_PWM_FAN is not set # CONFIG_RT_USING_VIRTIO is not set +CONFIG_RT_USING_NVMEM=y +CONFIG_RT_NVMEM_RASPBERRYPI_OTP=y +CONFIG_RT_USING_DMA=y +# CONFIG_RT_DMA_PL330 is not set +# CONFIG_RT_DMA_DW_AXI_DMAC is not set +CONFIG_RT_DMA_BCM2835=y +CONFIG_RT_USING_MFD=y +# CONFIG_RT_MFD_EDU is not set +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_BCM2835_PM=y +# CONFIG_RT_MFD_RP1 is not set +CONFIG_RT_MFD_RPI_SENSE=y +# CONFIG_RT_USING_IVSHMEM is not set +CONFIG_RT_USING_OFW=y +# CONFIG_RT_USING_BUILTIN_FDT is not set +CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 +CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +# CONFIG_RT_PCI_ENDPOINT is not set +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set + +# +# PCI Device Drivers +# +CONFIG_RT_PCI_ECAM=y +CONFIG_RT_PCI_HOST_COMMON=y +CONFIG_RT_PCI_HOST_GENERIC=y +# CONFIG_RT_PCI_DW is not set +CONFIG_RT_PCIE_BRCMSTB=y +CONFIG_RT_USING_PIC=y +# CONFIG_RT_USING_PIC_STATISTICS is not set +CONFIG_MAX_HANDLERS=512 +CONFIG_RT_PIC_ARM_GIC=y +# CONFIG_RT_PIC_ARM_GIC_V2M is not set +# CONFIG_RT_PIC_ARM_GIC_V3 is not set +CONFIG_RT_PIC_ARM_GIC_MAX_NR=1 +# CONFIG_RT_PIC_BCM2712_MIP is not set +CONFIG_RT_PIC_BCM2835_INTC=y +CONFIG_RT_PIC_BCM2836_L1_INTC=y +CONFIG_RT_PIC_BRCMSTB_L2_IRQ=y CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_BCM_VIRT=y +CONFIG_RT_PIN_BRCMSTB=y +CONFIG_RT_PIN_RASPBERRYPI_EXP=y +CONFIG_RT_USING_PINCTRL=y +# CONFIG_RT_PINCTRL_SINGLE is not set +# CONFIG_RT_PINCTRL_BCM2712 is not set +CONFIG_RT_PINCTRL_BCM2835=y +# CONFIG_RT_PINCTRL_RP1 is not set +CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_BCM2711_DVP=y +CONFIG_RT_CLK_BCM2835=y +CONFIG_RT_CLK_RASPBERRYPI=y +# CONFIG_RT_CLK_RP1 is not set # CONFIG_RT_USING_CHERRYUSB is not set + +# +# SoC (System on Chip) Drivers +# +CONFIG_RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR=y +# end of SoC (System on Chip) Drivers # end of Device Drivers # @@ -551,7 +771,8 @@ CONFIG_RT_USING_ADT_REF=y # CONFIG_RT_PAGE_MPR_SIZE_DYNAMIC is not set CONFIG_RT_PAGE_AFFINITY_BLOCK_SIZE=0x1000 CONFIG_RT_PAGE_MAX_ORDER=11 -# CONFIG_RT_USING_MEMBLOCK is not set +CONFIG_RT_USING_MEMBLOCK=y +CONFIG_RT_INIT_MEMORY_REGIONS=128 # # Debugging @@ -570,6 +791,7 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # end of Using USB legacy version # CONFIG_RT_USING_FDT is not set +# CONFIG_RT_USING_LEGACY_VIRTIO is not set # CONFIG_RT_USING_RUST is not set # end of RT-Thread Components @@ -772,7 +994,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_U8G2 is not set # end of u8g2: a monochrome graphic library -# CONFIG_PKG_USING_NES_SIMULATOR is not set # CONFIG_PKG_USING_OPENMV is not set # CONFIG_PKG_USING_MUPDF is not set # CONFIG_PKG_USING_STEMWIN is not set @@ -797,9 +1018,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # tools packages # -# CONFIG_PKG_USING_VECTOR is not set -# CONFIG_PKG_USING_SORCH is not set -# CONFIG_PKG_USING_DICT is not set # CONFIG_PKG_USING_CMBACKTRACE is not set # CONFIG_PKG_USING_MCOREDUMP is not set # CONFIG_PKG_USING_EASYFLASH is not set @@ -848,9 +1066,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_RVBACKTRACE is not set # CONFIG_PKG_USING_HPATCHLITE is not set # CONFIG_PKG_USING_THREAD_METRIC is not set -# CONFIG_PKG_USING_UORB is not set -# CONFIG_PKG_USING_RT_TUNNEL is not set -# CONFIG_PKG_USING_VIRTUAL_TERMINAL is not set # end of tools packages # @@ -945,9 +1160,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_R_RHEALSTONE is not set # CONFIG_PKG_USING_HEARTBEAT is not set # CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set -# CONFIG_PKG_USING_CHERRYECAT is not set -# CONFIG_PKG_USING_EVENT_LOOP is not set -# CONFIG_PKG_USING_THREAD_MANAGER is not set # end of system packages # @@ -1093,7 +1305,9 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # NUVOTON Drivers # +# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set # CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set # end of NUVOTON Drivers # @@ -1101,24 +1315,7 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # # CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set # CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32_RISCV_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32VW55X_WIFI is not set # end of GD32 Drivers - -# -# HPMicro SDK -# -# CONFIG_PKG_USING_HPM_SDK is not set -# end of HPMicro SDK - -# -# FT32 HAL & SDK Drivers -# -# CONFIG_PKG_USING_FT32F0_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F0_CMSIS_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_CMSIS_DRIVER is not set -# end of FT32 HAL & SDK Drivers # end of HAL & SDK Drivers # @@ -1164,11 +1361,9 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_RT3020 is not set # CONFIG_PKG_USING_MLX90632 is not set # CONFIG_PKG_USING_MLX90382 is not set -# CONFIG_PKG_USING_MLX90384 is not set # CONFIG_PKG_USING_MLX90393 is not set # CONFIG_PKG_USING_MLX90392 is not set # CONFIG_PKG_USING_MLX90394 is not set -# CONFIG_PKG_USING_MLX90396 is not set # CONFIG_PKG_USING_MLX90397 is not set # CONFIG_PKG_USING_MS5611 is not set # CONFIG_PKG_USING_MAX31865 is not set @@ -1197,7 +1392,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_P3T1755 is not set # CONFIG_PKG_USING_QMI8658 is not set # CONFIG_PKG_USING_ICM20948 is not set -# CONFIG_PKG_USING_SCD4X is not set # end of sensors drivers # @@ -1215,7 +1409,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_CST812T is not set # end of touch drivers -# CONFIG_PKG_USING_LCD_SPI_DRIVER is not set # CONFIG_PKG_USING_REALTEK_AMEBA is not set # CONFIG_PKG_USING_BUTTON is not set # CONFIG_PKG_USING_PCF8574 is not set @@ -1295,13 +1488,6 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # CONFIG_PKG_USING_IC74HC165 is not set # CONFIG_PKG_USING_IST8310 is not set # CONFIG_PKG_USING_ST7789_SPI is not set -# CONFIG_PKG_USING_CAN_UDS is not set -# CONFIG_PKG_USING_ISOTP_C is not set -# CONFIG_PKG_USING_IKUNLED is not set -# CONFIG_PKG_USING_INS5T8025 is not set -# CONFIG_PKG_USING_IRUART is not set -# CONFIG_PKG_USING_ST7305 is not set -# CONFIG_PKG_USING_TM1668 is not set # CONFIG_PKG_USING_SPI_TOOLS is not set # end of peripheral libraries and drivers @@ -1641,41 +1827,4 @@ CONFIG_RT_PAGE_MAX_ORDER=11 # end of Arduino libraries # end of RT-Thread online packages -CONFIG_BCM2711_SOC=y -CONFIG_BSP_SUPPORT_FPU=y -# CONFIG_BSP_USING_VM_MODE is not set - -# -# Hardware Drivers Config -# - -# -# BCM Peripheral Drivers -# -CONFIG_BSP_USING_UART=y -CONFIG_RT_USING_UART0=y -# CONFIG_RT_USING_UART1 is not set -CONFIG_RT_USING_UART3=y -CONFIG_RT_USING_UART4=y -# CONFIG_RT_USING_UART5 is not set -CONFIG_BSP_USING_GIC=y -CONFIG_BSP_USING_GICV2=y -# CONFIG_BSP_USING_GICV3 is not set -CONFIG_BSP_USING_PIN=y -# CONFIG_BSP_USING_SPI is not set -CONFIG_BSP_USING_CORETIMER=y -# CONFIG_BSP_USING_SYSTIMER is not set -CONFIG_BSP_USING_WDT=y -# CONFIG_BSP_USING_RTC is not set -CONFIG_BSP_USING_SDIO=y -CONFIG_BSP_USING_SDIO0=y -# end of BCM Peripheral Drivers - -# -# Board Peripheral Drivers -# -CONFIG_BSP_USING_HDMI=y -# CONFIG_BSP_USING_HDMI_DISPLAY is not set -# CONFIG_BSP_USING_TOUCH is not set -# end of Board Peripheral Drivers -# end of Hardware Drivers Config +CONFIG_SOC_BCM2711=y diff --git a/bsp/raspberry-pi/raspi4-64/Kconfig b/bsp/raspberry-pi/raspi4-64/Kconfig index f62b1758e9..9a2d2d7992 100644 --- a/bsp/raspberry-pi/raspi4-64/Kconfig +++ b/bsp/raspberry-pi/raspi4-64/Kconfig @@ -6,17 +6,18 @@ RTT_DIR := ../../.. PKGS_DIR := packages +SOC_DM_DIR := $BSP_DIR/../dm/ + +source "$(SOC_DM_DIR)/Kconfig" source "$(RTT_DIR)/Kconfig" osource "$PKGS_DIR/Kconfig" -config BCM2711_SOC +config SOC_BCM2711 bool select ARCH_ARMV8 - select ARCH_ARM_MMU - select RT_USING_CACHE select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN select ARCH_CPU_64BIT + select RT_USING_CACHE + select RT_USING_STDC_ATOMIC default y - -rsource "drivers/Kconfig" diff --git a/bsp/raspberry-pi/raspi4-64/README.md b/bsp/raspberry-pi/raspi4-64/README.md index 66e6b8e996..a531d674cc 100644 --- a/bsp/raspberry-pi/raspi4-64/README.md +++ b/bsp/raspberry-pi/raspi4-64/README.md @@ -47,7 +47,7 @@ windows系统电脑上可以安装tftpd搭建tftp服务器。将目录指定到` 在控制台输入下列命令: ``` -setenv bootcmd "dhcp 0x00208000 x.x.x.x:rtthread.bin;dcache flush;go 0x00208000" +setenv bootcmd "dhcp 0x208000 x.x.x.x:rtthread.bin;fdt addr ${fdt_addr};fdt set /chosen bootargs 'earlycon=uart8250,mmio32,0xfe215040 console=ttyAMA0 cma=8M coherent_pool=2M';booti 0x208000 - ${fdt_addr}" saveenv reset ``` diff --git a/bsp/raspberry-pi/raspi4-64/SConscript b/bsp/raspberry-pi/raspi4-64/SConscript index c7ef7659ec..40e1864cf6 100644 --- a/bsp/raspberry-pi/raspi4-64/SConscript +++ b/bsp/raspberry-pi/raspi4-64/SConscript @@ -11,4 +11,6 @@ for d in list: if os.path.isfile(os.path.join(path, 'SConscript')): objs = objs + SConscript(os.path.join(d, 'SConscript')) +objs = objs + SConscript(cwd + '/../dm/SConscript', variant_dir = 'dm', duplicate = 0) + Return('objs') diff --git a/bsp/raspberry-pi/raspi4-64/SConstruct b/bsp/raspberry-pi/raspi4-64/SConstruct index 55cab35463..ec6fe0187f 100644 --- a/bsp/raspberry-pi/raspi4-64/SConstruct +++ b/bsp/raspberry-pi/raspi4-64/SConstruct @@ -11,20 +11,19 @@ TARGET = 'rtthread.' + rtconfig.TARGET_EXT DefaultEnvironment(tools=[]) env = Environment(tools = ['mingw'], - AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, - CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, - CPP = rtconfig.CPP, CXXFLAGS = rtconfig.CXXFLAGS, - AR = rtconfig.AR, ARFLAGS = '-rc', + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) env.PrependENVPath('PATH', rtconfig.EXEC_PATH) env['ASCOM'] = env['ASPPCOM'] -env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS -Wl,--start-group $_LIBFLAGS -Wl,--end-group' Export('RTT_ROOT') Export('rtconfig') # prepare building environment -objs = PrepareBuilding(env, RTT_ROOT) +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) # make a building DoBuilding(TARGET, objs) diff --git a/bsp/raspberry-pi/raspi4-64/applications/SConscript b/bsp/raspberry-pi/raspi4-64/applications/SConscript old mode 100644 new mode 100755 diff --git a/bsp/raspberry-pi/raspi4-64/applications/main.c b/bsp/raspberry-pi/raspi4-64/applications/main.c old mode 100644 new mode 100755 index 9400e2a598..c492727ca7 --- a/bsp/raspberry-pi/raspi4-64/applications/main.c +++ b/bsp/raspberry-pi/raspi4-64/applications/main.c @@ -9,8 +9,6 @@ */ #include -#include -#include int main(int argc, char** argv) { diff --git a/bsp/raspberry-pi/raspi4-64/applications/mnt.c b/bsp/raspberry-pi/raspi4-64/applications/mnt.c deleted file mode 100644 index d204e788b5..0000000000 --- a/bsp/raspberry-pi/raspi4-64/applications/mnt.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017-5-30 bernard the first version - */ - -#include - -#ifdef BSP_USING_SDIO -#include - -int mnt_init(void) -{ - rt_thread_delay(RT_TICK_PER_SECOND/100); - if (dfs_mount("sd1", "/", "ext", 0, 0) == 0) - { - rt_kprintf("file system initialization done!\n"); - } - else if (dfs_mount("sd0", "/", "elm", 0, 0) == 0) - { - rt_kprintf("file system initialization done!\n"); - } - -#ifdef RT_USING_DFS_ROMFS - mkdir("/rom", 0777); - extern const struct romfs_dirent romfs_root; - if (dfs_mount(RT_NULL, "/rom", "rom", 0, &romfs_root) == 0) - { - rt_kprintf("ROM File System initialized!\n"); - } -#endif - - return 0; -} -INIT_ENV_EXPORT(mnt_init); -#endif diff --git a/bsp/raspberry-pi/raspi4-64/drivers/Kconfig b/bsp/raspberry-pi/raspi4-64/drivers/Kconfig deleted file mode 100644 index 3ea981e1f1..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/Kconfig +++ /dev/null @@ -1,139 +0,0 @@ - -config BSP_SUPPORT_FPU - bool "Using Float" - default n - -menuconfig BSP_USING_VM_MODE - bool "Enable VM mode" - default n - -menu "Hardware Drivers Config" - menu "BCM Peripheral Drivers" - menuconfig BSP_USING_UART - bool "Using UART" - select RT_USING_SERIAL - default y - - if BSP_USING_UART - config RT_USING_UART0 - bool "Enable UART 0" - default y - - config RT_USING_UART1 - bool "Enable UART 1" - default n - - config RT_USING_UART3 - bool "Enable UART 3" - default n - - config RT_USING_UART4 - bool "Enable UART 4" - default n - - config RT_USING_UART5 - bool "Enable UART 5" - default n - endif - - menuconfig BSP_USING_GIC - bool "Enable GIC" - select RT_USING_GIC - default y - if BSP_USING_GIC - config BSP_USING_GICV2 - bool "Enable GIC400(GICV2)" - default y - config BSP_USING_GICV3 - bool "Enable GIC500(GICV3)" - default n - endif - - config BSP_USING_PIN - bool "Using PIN" - select RT_USING_PIN - default y - - menuconfig BSP_USING_SPI - bool "Enable SPI" - select RT_USING_SPI - default n - - if BSP_USING_SPI - config BSP_USING_SPI0_BUS - bool "Enable SPI0 BUS" - default n - config BSP_USING_SPI0_DEVICE0 - bool "Enable SPI0 DEVICE0" - select BSP_USING_SPI0_BUS - default n - config BSP_USING_SPI0_DEVICE1 - bool "Enable SPI0 DEVICE1" - select BSP_USING_SPI0_BUS - default n - endif - - config BSP_USING_CORETIMER - bool "Using core timer" - select RT_USING_CORETIMER - default y - - menuconfig BSP_USING_SYSTIMER - bool "Enable SYSTIMER" - default n - - if BSP_USING_SYSTIMER - config RT_USING_SYSTIMER1 - bool "Enable sys timer1" - default n - config RT_USING_SYSTIMER3 - bool "Enable sys timer3" - default n - endif - - config BSP_USING_WDT - bool "Enable WDT" - select RT_USING_WDT - default n - - menuconfig BSP_USING_RTC - bool "Enable RTC" - select RT_USING_RTC - default n - - if BSP_USING_RTC - config BSP_USING_ALARM - bool "Enable Alarm" - select RT_USING_ALARM - default n - endif - - menuconfig BSP_USING_SDIO - bool "Enable SDIO" - select RT_USING_SDIO - default n - - if BSP_USING_SDIO - config BSP_USING_SDIO0 - bool "Enable SDIO0" - select RT_USING_SDIO - default n - endif - endmenu - - menu "Board Peripheral Drivers" - menuconfig BSP_USING_HDMI - bool "Enable HDMI" - default n - - if BSP_USING_HDMI - config BSP_USING_HDMI_DISPLAY - bool "HDMI DISPLAY" - default n - endif - - menuconfig BSP_USING_TOUCH - bool "Enable Touch" - default n - endmenu -endmenu diff --git a/bsp/raspberry-pi/raspi4-64/drivers/SConscript b/bsp/raspberry-pi/raspi4-64/drivers/SConscript index 98c38943e9..f7e8f47ce8 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/SConscript +++ b/bsp/raspberry-pi/raspi4-64/drivers/SConscript @@ -1,19 +1,12 @@ +# RT-Thread building script for component + from building import * cwd = GetCurrentDir() -src = Glob('*.c') + Glob('*.cpp') + Glob('*.S') -CPPPATH = [cwd, str(Dir('#'))] +src = Glob('*.c') +CPPPATH = [cwd] +objs = [] -group = DefineGroup('driver', src, depend = [''], CPPPATH = CPPPATH) - -# build for sub-directory -list = os.listdir(cwd) -objs = [] - -for d in list: - path = os.path.join(cwd, d) - if os.path.isfile(os.path.join(path, 'SConscript')): - objs = objs + SConscript(os.path.join(d, 'SConscript')) -group = group + objs +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/raspberry-pi/raspi4-64/drivers/board.c b/bsp/raspberry-pi/raspi4-64/drivers/board.c index e66a4bc09e..f79e5e7bbb 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/board.c +++ b/bsp/raspberry-pi/raspi4-64/drivers/board.c @@ -10,204 +10,67 @@ * 2023-03-28 WangXiaoyao sync works & memory layout fixups * code formats */ -#define DBG_TAG "board" -#define DBG_LVL DBG_INFO -#include -#include -#include +#include +#include +#include +#include #include -#include "board.h" -#include "drv_uart.h" +// extern char __noncacheable_start[]; +// extern char __noncacheable_end[]; -#include "cp15.h" -#include "mmu.h" -#include "mbox.h" -#include +// static void rt_hw_noncacheable_map(void) +// { +// rt_ubase_t start = (rt_ubase_t)__noncacheable_start; +// rt_ubase_t end = (rt_ubase_t)__noncacheable_end; +// rt_size_t size; -#ifdef RT_USING_SMART -#include -#endif +// if (end <= start) +// { +// return; +// } -extern size_t MMUTable[]; +// RT_ASSERT((start & (ARCH_SECTION_SIZE - 1)) == 0); +// RT_ASSERT((end & (ARCH_SECTION_SIZE - 1)) == 0); +// size = end - start; -size_t gpio_base_addr = GPIO_BASE_ADDR; +// rt_hw_mmu_control(&rt_kernel_space, (void *)start, size, MMU_CNTL_NONCACHE); +// rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)start, size); +// rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, (void *)start, size); +// } -size_t uart_base_addr = UART_BASE; - -size_t gic_base_addr = GIC_V2_BASE; - -size_t arm_timer_base = ARM_TIMER_BASE; - -size_t pactl_cs_base = PACTL_CS_ADDR; - -size_t stimer_base_addr = STIMER_BASE; - -size_t mmc2_base_addr = MMC2_BASE_ADDR; - -size_t videocore_mbox = VIDEOCORE_MBOX; - -size_t mbox_addr = MBOX_ADDR; - -size_t wdt_base_addr = WDT_BASE; - -uint8_t *mac_reg_base_addr = (uint8_t *)MAC_REG; - -uint8_t *eth_send_no_cache = (uint8_t *)SEND_DATA_NO_CACHE; -uint8_t *eth_recv_no_cache = (uint8_t *)RECV_DATA_NO_CACHE; - -#ifdef RT_USING_SMART -struct mem_desc platform_mem_desc[] = { - {KERNEL_VADDR_START, KERNEL_VADDR_START + 0x0fffffff, (rt_size_t)ARCH_MAP_FAILED, NORMAL_MEM} -}; -#else -struct mem_desc platform_mem_desc[] = { - {0x00200000, (256ul << 20) - 1, 0x00200000, NORMAL_MEM}, - {0xFC000000, 0x000100000000 - 1, 0xFC000000, DEVICE_MEM}, -}; -#endif - -const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc)/sizeof(platform_mem_desc[0]); - -void idle_wfi(void) -{ - asm volatile ("wfi"); -} - -/** - * This function will initialize board - */ - -extern size_t MMUTable[]; -int rt_hw_gtimer_init(void); - -rt_region_t init_page_region = { - PAGE_START, - PAGE_END, -}; - -/** - * Initialize the Hardware related stuffs. Called from rtthread_startup() - * after interrupt disabled. - */ void rt_hw_board_init(void) { - rt_hw_earlycon_ioremap_early(); - - /* io device remap */ -#ifdef RT_USING_SMART - rt_hw_mmu_map_init(&rt_kernel_space, (void*)0xfffffffff0000000, 0x10000000, MMUTable, PV_OFFSET); -#else - rt_hw_mmu_map_init(&rt_kernel_space, (void*)0x080000000000, 0x10000000, MMUTable, 0); -#endif /* RT_USING_SMART */ - rt_page_init(init_page_region); - rt_hw_mmu_setup(&rt_kernel_space, platform_mem_desc, platform_mem_desc_size); - - /* map peripheral address to virtual address */ -#ifdef RT_USING_HEAP - /* initialize system heap */ - rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); -#endif - - /* initialize hardware interrupt */ - rt_hw_interrupt_init(); - - //gpio - gpio_base_addr = (size_t)rt_ioremap((void*)GPIO_BASE_ADDR, 0x1000); - - //pactl - pactl_cs_base = (size_t)rt_ioremap((void*)PACTL_CS_ADDR, 0x1000); - - //stimer - stimer_base_addr = (size_t)rt_ioremap((void*)STIMER_BASE, 0x1000); - - //mmc2_base_addr - mmc2_base_addr = (size_t)rt_ioremap((void*)MMC2_BASE_ADDR, 0x1000); - - //mbox - videocore_mbox = (size_t)rt_ioremap((void*)VIDEOCORE_MBOX, 0x1000); - - // mbox msg - mbox = (volatile unsigned int *)rt_pages_alloc(0); - - //wdt - wdt_base_addr = (size_t)rt_ioremap((void*)WDT_BASE, 0x1000); - - //mac - mac_reg_base_addr = (void *)rt_ioremap((void*)MAC_REG, 0x80000); - - // eth data - eth_send_no_cache = (void *)rt_pages_alloc(rt_page_bits(0x200000)); - eth_recv_no_cache = (void *)rt_pages_alloc(rt_page_bits(0x200000)); - - /* initialize uart */ - rt_hw_uart_init(); - - /* initialize timer for os tick */ - rt_hw_gtimer_init(); - -#ifdef RT_USING_CONSOLE - /* set console device */ - rt_console_set_device(RT_CONSOLE_DEVICE_NAME); -#endif /* RT_USING_CONSOLE */ - -#ifdef RT_USING_COMPONENTS_INIT - rt_components_board_init(); -#endif - rt_thread_idle_sethook(idle_wfi); + rt_hw_common_setup(); + // rt_hw_noncacheable_map(); } -#ifdef RT_USING_SMP -#include - -void rt_hw_mmu_ktbl_set(unsigned long tbl); -void _secondary_cpu_entry(void); - -static unsigned long cpu_release_paddr[] = +static int ttyAMA0_init(void) { - [0] = 0xd8, - [1] = 0xe0, - [2] = 0xe8, - [3] = 0xf0, - [4] = 0x00 -}; + const char *con = rt_ofw_bootargs_select("console=", 0); + struct rt_device_pin *pinctrl; + struct rt_ofw_node *pinctrl_np, *conf_np; -void rt_hw_secondary_cpu_up(void) -{ - int i; - void *release_addr; - - for (i = 1; i < RT_CPUS_NR && cpu_release_paddr[i]; ++i) + /* + * Pi4 DT routes PL011 to GPIO32/33 (BT). Header UART needs GPIO14/15. + */ + if (!con || rt_strncmp(con, "ttyAMA0", 7)) { - release_addr = rt_ioremap((void *)cpu_release_paddr[i], sizeof(cpu_release_paddr[0])); - __asm__ volatile ("str %0, [%1]"::"rZ"((unsigned long)_secondary_cpu_entry + PV_OFFSET), "r"(release_addr)); - rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, release_addr, sizeof(release_addr)); - asm volatile ("dsb sy"); - asm volatile ("sev"); + return 0; } + + pinctrl_np = rt_ofw_find_node_by_path("/soc/gpio@7e200000"); + conf_np = rt_ofw_get_child_by_tag(pinctrl_np, "uart0-gpio14"); + + if (conf_np && (pinctrl = rt_ofw_data(pinctrl_np))) + { + pinctrl->ops->pin_ctrl_confs_apply(&pinctrl->parent, conf_np); + } + + rt_ofw_node_put(conf_np); + rt_ofw_node_put(pinctrl_np); + + return 0; } - -void rt_hw_secondary_cpu_bsp_start(void) -{ - rt_hw_spin_lock(&_cpus_lock); - - rt_hw_mmu_ktbl_set((unsigned long)MMUTable); - - rt_hw_vector_init(); - - arm_gic_cpu_init(0, 0); - - rt_hw_gtimer_init(); - - rt_kprintf("\rcpu %d boot success\n", rt_hw_cpu_id()); - - rt_system_scheduler_start(); -} - -void rt_hw_secondary_cpu_idle_exec(void) -{ - asm volatile ("wfe":::"memory", "cc"); -} - -#endif +INIT_EXPORT(ttyAMA0_init, "1.3"); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/board.h b/bsp/raspberry-pi/raspi4-64/drivers/board.h index 9d28915ba3..f3525ae59b 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/board.h +++ b/bsp/raspberry-pi/raspi4-64/drivers/board.h @@ -11,26 +11,6 @@ #ifndef BOARD_H__ #define BOARD_H__ -#include -#include "raspi4.h" -#include "mmu.h" -#include "ioremap.h" - -extern int __bss_end; -#define HEAP_BEGIN ((void*)&__bss_end) - -#ifdef RT_USING_SMART -#define HEAP_END ((size_t)KERNEL_VADDR_START + 32 * 1024 * 1024) -#define PAGE_START HEAP_END -#define PAGE_END ((size_t)KERNEL_VADDR_START + 128 * 1024 * 1024) -#else -#define KERNEL_VADDR_START 0x0 - -#define HEAP_END (KERNEL_VADDR_START + 32 * 1024 * 1024) -#define PAGE_START HEAP_END -#define PAGE_END ((size_t)PAGE_START + 128 * 1024 * 1024) -#endif - void rt_hw_board_init(void); -#endif +#endif /* BOARD_H__ */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_dsi_touch.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_dsi_touch.c deleted file mode 100644 index 2628ea5404..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_dsi_touch.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-11-26 bigmagic first version - */ -#include -#include -#include "drivers/dev_touch.h" -#include -#include - -#ifdef RT_USING_SMART -#include -#include -#endif - -#include - -#ifdef BSP_USING_TOUCH - -#include "mbox.h" -#include "drv_dsi_touch.h" - -#define DBG_TAG "dsi_touch" -#define DBG_LVL DBG_INFO -#include - -static rt_touch_t touch_device = RT_NULL; -static struct rt_semaphore dsi_touch_ack; - -static rt_uint32_t touch_x; -static rt_uint32_t touch_y; -static rt_uint32_t touch_state = 0; - -static rt_thread_t dsi_touch_tid = RT_NULL; -#define DSI_TOUCH_THREAD_STACK_SIZE (4096) -#define DSI_TOUCH_THREAD_PRIORITY (25) -#define DSI_TOUCH_THREAD_TIMESLICE (10) - -#define MAXIMUM_SUPPORTED_POINTS (10) - -struct touch_regs -{ - uint8_t device_mode; - uint8_t gesture_id; - uint8_t num_points; - struct touch - { - uint8_t xh; - uint8_t xl; - uint8_t yh; - uint8_t yl; - uint8_t res1; - uint8_t res2; - } point[MAXIMUM_SUPPORTED_POINTS]; -}; - -struct drv_mouse_device -{ - struct rt_device parent; - struct rt_touch_data touchdata; - int channel; -}; - -struct drv_mouse_device _mouse; - -static void post_event(rt_uint16_t x, rt_uint16_t y, rt_uint8_t event) -{ - struct rt_touch_data *minfo = &_mouse.touchdata; - struct rt_channel_msg ch_msg; - - LOG_D("event:%d, x:%d, y:%d\n", event, x, y); - - minfo->x_coordinate = x; - minfo->y_coordinate = y; - minfo->event = event; - ch_msg.type = RT_CHANNEL_RAW; - ch_msg.u.d = (void *)(size_t)event; - rt_channel_send(_mouse.channel, &ch_msg); -} - -static void dsi_touch_thread_entry(void *param) -{ - static volatile unsigned long touchbuf; - touchbuf = bcm271x_mbox_get_touch(); - - if (touchbuf == RT_NULL) - { - rt_kprintf("init dsi touch err!\n"); - return; - } - -#ifdef BSP_USING_VM_MODE - if (rt_hv_stage2_map((unsigned long)touchbuf, 0x1000)) - { - rt_kprintf("alloc mmio from hyper fail!\n"); - return; - } -#endif - - touchbuf = (unsigned long)rt_ioremap((void *)touchbuf, 0x1000); - - while (1) - { - struct touch_regs *regs = (struct touch_regs *)touchbuf; - if ((regs->num_points > 0) && (regs->num_points < MAXIMUM_SUPPORTED_POINTS)) - { - /* only one touch point */ - touch_x = (((int)regs->point[0].xh & 0xf) << 8) + regs->point[0].xl; - touch_y = (((int)regs->point[0].yh & 0xf) << 8) + regs->point[0].yl; - if (!touch_state) - { - post_event(touch_x, touch_y, RT_TOUCH_EVENT_DOWN); - } - else - { - post_event(touch_x, touch_y, RT_TOUCH_EVENT_MOVE); - } - touch_state = 1; - } - else - { - if (touch_state) - { - post_event(touch_x, touch_y, RT_TOUCH_EVENT_UP); - } - touch_state = 0; - } - rt_thread_mdelay(1); - } -} - -static rt_size_t dsi_read_point(struct rt_touch_device *touch, void *buf, rt_size_t read_num) -{ - rt_uint16_t* touchxy = (rt_uint16_t *)buf; - - if ((read_num != 0) && (touch_state == 1)) - { - touchxy[0] = touch_x; - touchxy[1] = touch_y; - touch_state = 0; - return read_num; - } - else - { - return 0; - } -} - -static rt_err_t dsi_control(struct rt_touch_device *device, int cmd, void *data) -{ - return RT_EOK; -} - -static struct rt_touch_ops dsi_touch_ops = -{ - .touch_readpoint = dsi_read_point, - .touch_control = dsi_control, -}; - -static rt_err_t drv_mouse_init(struct rt_device *device) -{ - struct drv_mouse_device *mouse = (struct drv_mouse_device*)device; - - return RT_EOK; -} - -static rt_err_t drv_mouse_control(struct rt_device *device, int cmd, void *args) -{ - switch (cmd) - { -#define CMD_MOUSE_SET_NOTIFY 0 /* arg is shmid, in the shm, a sem point is given */ - case CMD_MOUSE_SET_NOTIFY: - *(unsigned long *)args = (rt_uint32_t)(unsigned long)lwp_map_user_phy(lwp_self(), RT_NULL, (uint32_t*)((size_t)&_mouse.touchdata + PV_OFFSET), sizeof(struct rt_touch_data), 1); - break; - default: - break; - } - return RT_EOK; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops _mouse_ops = -{ - drv_mouse_init, - RT_NULL, - RT_NULL, - RT_NULL, - RT_NULL, - drv_mouse_control -}; -#endif - -static int hw_dsi_touch_init(void) -{ - struct rt_device *device = &_mouse.parent; - -#ifdef RT_USING_DEVICE_OPS - device->ops = &_mouse_ops; -#else - device->init = drv_mouse_init; - device->open = RT_NULL; - device->close = RT_NULL; - device->read = RT_NULL; - device->write = RT_NULL; - device->control = drv_mouse_control; -#endif - rt_device_register(device, "mouse", RT_DEVICE_FLAG_RDWR); - _mouse.channel = rt_channel_open("mouse", O_CREAT); - - /* touch sem */ - rt_sem_init(&dsi_touch_ack, "dsi_touch_ack", 0, RT_IPC_FLAG_FIFO); - - dsi_touch_tid = rt_thread_create("dsi_touch", - dsi_touch_thread_entry, RT_NULL, - DSI_TOUCH_THREAD_STACK_SIZE, - DSI_TOUCH_THREAD_PRIORITY, DSI_TOUCH_THREAD_TIMESLICE); - if (dsi_touch_tid != RT_NULL) - { - rt_thread_startup(dsi_touch_tid); - } - - touch_device = (rt_touch_t)rt_malloc(sizeof(struct rt_touch_device)); - - if (touch_device == RT_NULL) - { - return -RT_ERROR; - } - - /* register touch device */ - touch_device->info.type = RT_TOUCH_TYPE_RESISTANCE; - touch_device->info.vendor = RT_TOUCH_VENDOR_UNKNOWN; - - touch_device->ops = &dsi_touch_ops; - rt_hw_touch_register(touch_device, "dsi_touch", RT_DEVICE_FLAG_INT_RX, RT_NULL); - return 0; -} -INIT_APP_EXPORT(hw_dsi_touch_init); -#endif /* BSP_USING_TOUCH */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.c deleted file mode 100644 index 81380896c5..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.c +++ /dev/null @@ -1,714 +0,0 @@ - -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-30 bigmagic first version - * 2023-03-28 WangXiaoyao Modify pbuf_alloc - */ - -#include -#include -#include -#include -#include - -#include "mbox.h" -#include "raspi4.h" -#include "drv_eth.h" - -#define LOG_LVL DBG_LOG -#define LOG_TAG "drv.eth" -#include - -static int link_speed = 0; -static int link_flag = 0; - -#define DMA_DISC_ADDR_SIZE (4 * 1024 *1024) - -#define RX_DESC_BASE (mac_reg_base_addr + GENET_RX_OFF) -#define TX_DESC_BASE (mac_reg_base_addr + GENET_TX_OFF) - -#define MAX_ADDR_LEN (6) - -#define upper_32_bits(n) ((rt_uint32_t)(((n) >> 16) >> 16)) -#define lower_32_bits(n) ((rt_uint32_t)(n)) - -#define BIT(nr) (1UL << (nr)) - -static rt_thread_t link_thread_tid = RT_NULL; -#define LINK_THREAD_STACK_SIZE (8192) -#define LINK_THREAD_PRIORITY (20) -#define LINK_THREAD_TIMESLICE (10) - -static rt_uint32_t tx_index = 0; -static rt_uint32_t rx_index = 0; -static rt_uint32_t index_flag = 0; - -struct rt_eth_dev -{ - struct eth_device parent; - rt_uint8_t dev_addr[MAX_ADDR_LEN]; - char *name; - void *iobase; - int state; - int index; - struct rt_timer link_timer; - void *priv; -}; -static struct rt_eth_dev eth_dev; -static struct rt_semaphore link_ack; - -static inline rt_uint32_t read32(void *addr) -{ - return (*((volatile unsigned int*)(addr))); -} - -static inline void write32(void *addr, rt_uint32_t value) -{ - (*((volatile unsigned int*)(addr))) = value; -} - -static void eth_rx_irq(int irq, void *param) -{ - rt_uint32_t val = 0; - val = read32(mac_reg_base_addr + GENET_INTRL2_CPU_STAT); - val &= ~read32(mac_reg_base_addr + GENET_INTRL2_CPU_STAT_MASK); - - write32(mac_reg_base_addr + GENET_INTRL2_CPU_CLEAR, val); - - if (val & GENET_IRQ_RXDMA_DONE) - { - eth_device_ready(ð_dev.parent); - } - - if (val & GENET_IRQ_TXDMA_DONE) - { - //todo - } -} - -/* We only support RGMII (as used on the RPi4). */ -static int bcmgenet_interface_set(void) -{ - int phy_mode = PHY_INTERFACE_MODE_RGMII; - switch (phy_mode) - { - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_RXID: - write32(mac_reg_base_addr + SYS_PORT_CTRL, PORT_MODE_EXT_GPHY); - break; - - default: - rt_kprintf("unknown phy mode: %d\n", mac_reg_base_addr); - return -1; - } - return 0; -} - -static void bcmgenet_umac_reset(void) -{ - rt_uint32_t reg; - reg = read32(mac_reg_base_addr + SYS_RBUF_FLUSH_CTRL); - reg |= BIT(1); - write32((mac_reg_base_addr + SYS_RBUF_FLUSH_CTRL), reg); - - reg &= ~BIT(1); - write32((mac_reg_base_addr + SYS_RBUF_FLUSH_CTRL), reg); - - DELAY_MICROS(10); - - write32((mac_reg_base_addr + SYS_RBUF_FLUSH_CTRL), 0); - DELAY_MICROS(10); - - write32(mac_reg_base_addr + UMAC_CMD, 0); - write32(mac_reg_base_addr + UMAC_CMD, (CMD_SW_RESET | CMD_LCL_LOOP_EN)); - DELAY_MICROS(2); - - write32(mac_reg_base_addr + UMAC_CMD, 0); - /* clear tx/rx counter */ - write32(mac_reg_base_addr + UMAC_MIB_CTRL, MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT); - write32(mac_reg_base_addr + UMAC_MIB_CTRL, 0); - write32(mac_reg_base_addr + UMAC_MAX_FRAME_LEN, ENET_MAX_MTU_SIZE); - - /* init rx registers, enable ip header optimization */ - reg = read32(mac_reg_base_addr + RBUF_CTRL); - reg |= RBUF_ALIGN_2B; - write32(mac_reg_base_addr + RBUF_CTRL, reg); - write32(mac_reg_base_addr + RBUF_TBUF_SIZE_CTRL, 1); -} - -static void bcmgenet_disable_dma(void) -{ - rt_uint32_t tdma_reg = 0, rdma_reg = 0; - - tdma_reg = read32(mac_reg_base_addr + TDMA_REG_BASE + DMA_CTRL); - tdma_reg &= ~(1UL << DMA_EN); - write32(mac_reg_base_addr + TDMA_REG_BASE + DMA_CTRL, tdma_reg); - rdma_reg = read32(mac_reg_base_addr + RDMA_REG_BASE + DMA_CTRL); - rdma_reg &= ~(1UL << DMA_EN); - write32(mac_reg_base_addr + RDMA_REG_BASE + DMA_CTRL, rdma_reg); - write32(mac_reg_base_addr + UMAC_TX_FLUSH, 1); - DELAY_MICROS(100); - write32(mac_reg_base_addr + UMAC_TX_FLUSH, 0); -} - -static void bcmgenet_enable_dma(void) -{ - rt_uint32_t reg = 0; - rt_uint32_t dma_ctrl = 0; - - dma_ctrl = (1 << (DEFAULT_Q + DMA_RING_BUF_EN_SHIFT)) | DMA_EN; - write32(mac_reg_base_addr + TDMA_REG_BASE + DMA_CTRL, dma_ctrl); - - reg = read32(mac_reg_base_addr + RDMA_REG_BASE + DMA_CTRL); - write32(mac_reg_base_addr + RDMA_REG_BASE + DMA_CTRL, dma_ctrl | reg); -} - -static int bcmgenet_mdio_write(rt_uint32_t addr, rt_uint32_t reg, rt_uint32_t value) -{ - int count = 10000; - rt_uint32_t val; - val = MDIO_WR | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT) | (0xffff & value); - write32(mac_reg_base_addr + MDIO_CMD, val); - - rt_uint32_t reg_val = read32(mac_reg_base_addr + MDIO_CMD); - reg_val = reg_val | MDIO_START_BUSY; - write32(mac_reg_base_addr + MDIO_CMD, reg_val); - - while ((read32(mac_reg_base_addr + MDIO_CMD) & MDIO_START_BUSY) && (--count)) - DELAY_MICROS(1); - - reg_val = read32(mac_reg_base_addr + MDIO_CMD); - - return reg_val & 0xffff; -} - -static int bcmgenet_mdio_read(rt_uint32_t addr, rt_uint32_t reg) -{ - int count = 10000; - rt_uint32_t val = 0; - rt_uint32_t reg_val = 0; - - val = MDIO_RD | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); - write32(mac_reg_base_addr + MDIO_CMD, val); - - reg_val = read32(mac_reg_base_addr + MDIO_CMD); - reg_val = reg_val | MDIO_START_BUSY; - write32(mac_reg_base_addr + MDIO_CMD, reg_val); - - while ((read32(mac_reg_base_addr + MDIO_CMD) & MDIO_START_BUSY) && (--count)) - DELAY_MICROS(1); - - reg_val = read32(mac_reg_base_addr + MDIO_CMD); - - return reg_val & 0xffff; -} - -static int bcmgenet_gmac_write_hwaddr(void) -{ - rt_uint8_t addr[6]; - rt_uint32_t reg; - bcm271x_mbox_hardware_get_mac_address(&addr[0]); - - reg = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3]; - write32(mac_reg_base_addr + UMAC_MAC0, reg); - - reg = addr[4] << 8 | addr[5]; - write32(mac_reg_base_addr + UMAC_MAC1, reg); - return 0; -} - -static int get_ethernet_uid(void) -{ - rt_uint32_t uid_high = 0; - rt_uint32_t uid_low = 0; - rt_uint32_t uid = 0; - - uid_high = bcmgenet_mdio_read(1, BCM54213PE_PHY_IDENTIFIER_HIGH); - uid_low = bcmgenet_mdio_read(1, BCM54213PE_PHY_IDENTIFIER_LOW); - uid = (uid_high << 16 | uid_low); - - if (BCM54213PE_VERSION_B1 == uid) - { - LOG_I("version is B1\n"); - } - return uid; -} - -static void bcmgenet_mdio_init(void) -{ - rt_uint32_t ret = 0; - /*get ethernet uid*/ - ret = get_ethernet_uid(); - if (ret == 0) return; - - /* reset phy */ - bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, MII_CONTROL_PHY_RESET); - /* read control reg */ - bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL); - /* reset phy again */ - bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, MII_CONTROL_PHY_RESET); - /* read control reg */ - bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL); - /* read status reg */ - bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS); - /* read status reg */ - bcmgenet_mdio_read(1, BCM54213PE_IEEE_EXTENDED_STATUS); - bcmgenet_mdio_read(1, BCM54213PE_AUTO_NEGOTIATION_ADV); - - bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS); - bcmgenet_mdio_read(1, BCM54213PE_CONTROL); - /* half full duplex capability */ - bcmgenet_mdio_write(1, BCM54213PE_CONTROL, (CONTROL_HALF_DUPLEX_CAPABILITY | CONTROL_FULL_DUPLEX_CAPABILITY)); - bcmgenet_mdio_read(1, BCM54213PE_MII_CONTROL); - - /* set mii control */ - bcmgenet_mdio_write(1, BCM54213PE_MII_CONTROL, (MII_CONTROL_AUTO_NEGOTIATION_ENABLED | MII_CONTROL_AUTO_NEGOTIATION_RESTART | MII_CONTROL_PHY_FULL_DUPLEX | MII_CONTROL_SPEED_SELECTION)); -} - -static void rx_ring_init(void) -{ - write32(mac_reg_base_addr + RDMA_REG_BASE + DMA_SCB_BURST_SIZE, DMA_MAX_BURST_LENGTH); - write32(mac_reg_base_addr + RDMA_RING_REG_BASE + DMA_START_ADDR, 0x0); - write32(mac_reg_base_addr + RDMA_READ_PTR, 0x0); - write32(mac_reg_base_addr + RDMA_WRITE_PTR, 0x0); - write32(mac_reg_base_addr + RDMA_RING_REG_BASE + DMA_END_ADDR, RX_DESCS * DMA_DESC_SIZE / 4 - 1); - - write32(mac_reg_base_addr + RDMA_PROD_INDEX, 0x0); - write32(mac_reg_base_addr + RDMA_CONS_INDEX, 0x0); - write32(mac_reg_base_addr + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE, (RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH); - write32(mac_reg_base_addr + RDMA_XON_XOFF_THRESH, DMA_FC_THRESH_VALUE); - write32(mac_reg_base_addr + RDMA_REG_BASE + DMA_RING_CFG, 1 << DEFAULT_Q); -} - -static void tx_ring_init(void) -{ - write32(mac_reg_base_addr + TDMA_REG_BASE + DMA_SCB_BURST_SIZE, DMA_MAX_BURST_LENGTH); - write32(mac_reg_base_addr + TDMA_RING_REG_BASE + DMA_START_ADDR, 0x0); - write32(mac_reg_base_addr + TDMA_READ_PTR, 0x0); - write32(mac_reg_base_addr + TDMA_READ_PTR, 0x0); - write32(mac_reg_base_addr + TDMA_READ_PTR, 0x0); - write32(mac_reg_base_addr + TDMA_WRITE_PTR, 0x0); - write32(mac_reg_base_addr + TDMA_RING_REG_BASE + DMA_END_ADDR, TX_DESCS * DMA_DESC_SIZE / 4 - 1); - write32(mac_reg_base_addr + TDMA_PROD_INDEX, 0x0); - write32(mac_reg_base_addr + TDMA_CONS_INDEX, 0x0); - write32(mac_reg_base_addr + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH, 0x1); - write32(mac_reg_base_addr + TDMA_FLOW_PERIOD, 0x0); - write32(mac_reg_base_addr + TDMA_RING_REG_BASE + DMA_RING_BUF_SIZE, (TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH); - write32(mac_reg_base_addr + TDMA_REG_BASE + DMA_RING_CFG, 1 << DEFAULT_Q); -} - -static void rx_descs_init(void) -{ - char *rxbuffs = (char *)RECV_DATA_NO_CACHE; - rt_uint32_t len_stat, i; - void *desc_base = (void *)RX_DESC_BASE; - - len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN; - for (i = 0; i < RX_DESCS; i++) - { - write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_LO), lower_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH])); - write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_HI), upper_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH])); - write32((desc_base + i * DMA_DESC_SIZE + DMA_DESC_LENGTH_STATUS), len_stat); - } -} - -static int bcmgenet_adjust_link(void) -{ - rt_uint32_t speed; - rt_uint32_t phy_dev_speed = link_speed; - - switch (phy_dev_speed) - { - case SPEED_1000: - speed = UMAC_SPEED_1000; - break; - case SPEED_100: - speed = UMAC_SPEED_100; - break; - case SPEED_10: - speed = UMAC_SPEED_10; - break; - default: - rt_kprintf("bcmgenet: Unsupported PHY speed: %d\n", phy_dev_speed); - return -1; - } - - rt_uint32_t reg1 = read32(mac_reg_base_addr + EXT_RGMII_OOB_CTRL); - //reg1 &= ~(1UL << OOB_DISABLE); - - //rt_kprintf("OOB_DISABLE is %d\n", OOB_DISABLE); - reg1 |= (RGMII_LINK | RGMII_MODE_EN | ID_MODE_DIS); - write32(mac_reg_base_addr + EXT_RGMII_OOB_CTRL, reg1); - DELAY_MICROS(1000); - write32(mac_reg_base_addr + UMAC_CMD, speed << CMD_SPEED_SHIFT); - return 0; -} - -void link_irq(void *param) -{ - if ((bcmgenet_mdio_read(1, BCM54213PE_MII_STATUS) & MII_STATUS_LINK_UP) != 0) - { - rt_sem_release(&link_ack); - } -} - -static int bcmgenet_gmac_eth_start(void) -{ - rt_uint32_t ret; - rt_uint32_t count = 10000; - - bcmgenet_umac_reset(); - - bcmgenet_gmac_write_hwaddr(); - /* Disable RX/TX DMA and flush TX queues */ - bcmgenet_disable_dma(); - rx_ring_init(); - rx_descs_init(); - tx_ring_init(); - - /* Enable RX/TX DMA */ - bcmgenet_enable_dma(); - - /* Update MAC registers based on PHY property */ - ret = bcmgenet_adjust_link(); - if(ret) - { - rt_kprintf("bcmgenet: adjust PHY link failed: %d\n", ret); - return ret; - } - - /* wait tx index clear */ - while ((read32(mac_reg_base_addr + TDMA_CONS_INDEX) != 0) && (--count)) - DELAY_MICROS(1); - - tx_index = read32(mac_reg_base_addr + TDMA_CONS_INDEX); - write32(mac_reg_base_addr + TDMA_PROD_INDEX, tx_index); - - index_flag = read32(mac_reg_base_addr + RDMA_PROD_INDEX); - - rx_index = index_flag % 256; - - write32(mac_reg_base_addr + RDMA_CONS_INDEX, index_flag); - write32(mac_reg_base_addr + RDMA_PROD_INDEX, index_flag); - - /* Enable Rx/Tx */ - rt_uint32_t rx_tx_en; - rx_tx_en = read32(mac_reg_base_addr + UMAC_CMD); - rx_tx_en |= (CMD_TX_EN | CMD_RX_EN); - - write32(mac_reg_base_addr + UMAC_CMD, rx_tx_en); - - // eanble IRQ for TxDMA done and RxDMA done - write32(mac_reg_base_addr + GENET_INTRL2_CPU_CLEAR_MASK, GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); - return 0; -} - -static rt_uint32_t prev_recv_cnt = 0; -static rt_uint32_t cur_recv_cnt = 0; -static rt_uint32_t bcmgenet_gmac_eth_recv(rt_uint8_t **packetp) -{ - void* desc_base; - rt_uint32_t length = 0; - size_t addr = 0; - rt_uint32_t prod_index = read32(mac_reg_base_addr + RDMA_PROD_INDEX); - //get next - if(prod_index == index_flag) - { - cur_recv_cnt = index_flag; - index_flag = 0x7fffffff; - //no buff - return 0; - } - else - { - if(prev_recv_cnt == (prod_index & 0xffffUL)) - { - return 0; - } - - desc_base = RX_DESC_BASE + rx_index * DMA_DESC_SIZE; - length = read32(desc_base + DMA_DESC_LENGTH_STATUS); - length = (length >> DMA_BUFLENGTH_SHIFT) & DMA_BUFLENGTH_MASK; - addr = read32(desc_base + DMA_DESC_ADDRESS_LO); - /* To cater for the IP headepr alignment the hardware does. - * This would actually not be needed if we don't program - * RBUF_ALIGN_2B - */ - *packetp = (rt_uint8_t *)(addr + RX_BUF_OFFSET); - - rx_index = rx_index + 1; - if(rx_index >= 256) - { - rx_index = 0; - } - write32(mac_reg_base_addr + RDMA_CONS_INDEX, cur_recv_cnt); - - cur_recv_cnt = cur_recv_cnt + 1; - - if(cur_recv_cnt > 0xffff) - { - cur_recv_cnt = 0; - } - prev_recv_cnt = cur_recv_cnt; - - return length; - } -} - -static int bcmgenet_gmac_eth_send(void *packet, int length) -{ - rt_ubase_t level; - void *desc_base = (TX_DESC_BASE + tx_index * DMA_DESC_SIZE); - rt_uint32_t len_stat = length << DMA_BUFLENGTH_SHIFT; - - rt_uint32_t prod_index, cons; - rt_uint32_t tries = 100; - - prod_index = read32(mac_reg_base_addr + TDMA_PROD_INDEX); - - len_stat |= 0x3F << DMA_TX_QTAG_SHIFT; - len_stat |= DMA_TX_APPEND_CRC | DMA_SOP | DMA_EOP; - - write32((desc_base + DMA_DESC_ADDRESS_LO), SEND_DATA_NO_CACHE); - write32((desc_base + DMA_DESC_ADDRESS_HI), 0); - write32((desc_base + DMA_DESC_LENGTH_STATUS), len_stat); - - tx_index = tx_index == 255? 0 : tx_index + 1; - prod_index = prod_index + 1; - - if (prod_index == 0xe000) - { - write32(mac_reg_base_addr + TDMA_PROD_INDEX, 0); - prod_index = 0; - } - - /* Start Transmisson */ - write32(mac_reg_base_addr + TDMA_PROD_INDEX, prod_index); - - level = rt_hw_interrupt_disable(); - do - { - cons = read32(mac_reg_base_addr + TDMA_CONS_INDEX); - } while ((cons & 0xffff) < prod_index && --tries); - rt_hw_interrupt_enable(level); - - if (!tries) - { - rt_kprintf("send err! tries is %d\n", tries); - return -1; - } - - return 0; -} - -static void link_task_entry(void *param) -{ - struct eth_device *eth_device = (struct eth_device *)param; - RT_ASSERT(eth_device != RT_NULL); - struct rt_eth_dev *dev = ð_dev; - - //start mdio - bcmgenet_mdio_init(); - - //start timer link - rt_timer_init(&dev->link_timer, "link_timer", - link_irq, - NULL, - 100, - RT_TIMER_FLAG_PERIODIC); - rt_timer_start(&dev->link_timer); - - //link wait forever - rt_sem_take(&link_ack, RT_WAITING_FOREVER); - eth_device_linkchange(ð_dev.parent, RT_TRUE); //link up - rt_timer_stop(&dev->link_timer); - - //set mac - // bcmgenet_gmac_write_hwaddr(); - bcmgenet_gmac_write_hwaddr(); - - //check link speed - if ((bcmgenet_mdio_read(1, BCM54213PE_STATUS) & (1 << 10)) || (bcmgenet_mdio_read(1, BCM54213PE_STATUS) & (1 << 11))) - { - link_speed = 1000; - LOG_I("Support link mode Speed 1000M\n"); - } - else if ((bcmgenet_mdio_read(1, 0x05) & (1 << 7)) || (bcmgenet_mdio_read(1, 0x05) & (1 << 8)) || (bcmgenet_mdio_read(1, 0x05) & (1 << 9))) - { - link_speed = 100; - LOG_I("Support link mode Speed 100M\n"); - } - else - { - link_speed = 10; - LOG_I("Support link mode Speed 10M\n"); - } - - bcmgenet_gmac_eth_start(); - - rt_hw_interrupt_install(ETH_IRQ, eth_rx_irq, NULL, "eth_irq"); - rt_hw_interrupt_umask(ETH_IRQ); - - link_flag = 1; -} - -static rt_err_t bcmgenet_eth_init(rt_device_t device) -{ - rt_uint32_t ret = 0; - rt_uint32_t hw_reg = 0; - - /* Read GENET HW version */ - rt_uint8_t major = 0; - hw_reg = read32(mac_reg_base_addr + SYS_REV_CTRL); - major = (hw_reg >> 24) & 0x0f; - if (major != 6) - { - if (major == 5) - major = 4; - else if (major == 0) - major = 1; - - LOG_W("Unsupported GENETv%d.%d\n", major, (hw_reg >> 16) & 0x0f); - return -RT_ERROR; - } - /* set interface */ - ret = bcmgenet_interface_set(); - if (ret) - { - return ret; - } - - /* rbuf clear */ - write32(mac_reg_base_addr + SYS_RBUF_FLUSH_CTRL, 0); - - /* disable MAC while updating its registers */ - write32(mac_reg_base_addr + UMAC_CMD, 0); - /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */ - write32(mac_reg_base_addr + UMAC_CMD, CMD_SW_RESET | CMD_LCL_LOOP_EN); - - link_thread_tid = rt_thread_create("link", link_task_entry, (void *)device, - LINK_THREAD_STACK_SIZE, - LINK_THREAD_PRIORITY, LINK_THREAD_TIMESLICE); - if (link_thread_tid != RT_NULL) - rt_thread_startup(link_thread_tid); - - return RT_EOK; -} - -static rt_err_t bcmgenet_eth_control(rt_device_t dev, int cmd, void *args) -{ - switch (cmd) - { - case NIOCTL_GADDR: - if (args) - rt_memcpy(args, eth_dev.dev_addr, 6); - else - return -RT_ERROR; - break; - default: - break; - } - return RT_EOK; -} - -rt_err_t rt_eth_tx(rt_device_t device, struct pbuf *p) -{ - int copy_len = 0; - - /* lock eth device */ - if (link_flag != 1) - { - LOG_I("link disconnected\n"); - return -RT_ERROR; - } - - copy_len = pbuf_copy_partial(p, eth_send_no_cache, p->tot_len, 0); - if (copy_len == 0) - { - - LOG_I("copy len is zero\n"); - return -RT_ERROR; - } - bcmgenet_gmac_eth_send((void *)eth_send_no_cache, p->tot_len); - - return RT_EOK; -} - -struct pbuf *rt_eth_rx(rt_device_t device) -{ - int recv_len = 0; - size_t addr_point; - struct pbuf *pbuf = RT_NULL; - if (link_flag != 1) - { - return RT_NULL; - } - - recv_len = bcmgenet_gmac_eth_recv((rt_uint8_t **)&addr_point); - if (recv_len > 0) - { - pbuf = pbuf_alloc(PBUF_LINK, ENET_FRAME_MAX_FRAMELEN, PBUF_POOL); - if (pbuf != RT_NULL) - { - //calc offset - addr_point= (size_t)(addr_point+ (eth_recv_no_cache - RECV_DATA_NO_CACHE)); - rt_memcpy(pbuf->payload, (char *)addr_point, recv_len); - } - } - - return pbuf; -} - -#ifdef RT_USING_DEVICE_OPS -static struct rt_device_ops eth_devops = { - .init = bcmgenet_eth_init, - .control = bcmgenet_eth_control, -}; -#endif /* RT_USING_DEVICE_OPS */ - -int rt_hw_eth_init(void) -{ - rt_uint8_t mac_addr[6] = {0xdc, 0xa6, 0x32, 0x28, 0x22, 0x50}; - - rt_sem_init(&link_ack, "link_ack", 0, RT_IPC_FLAG_FIFO); - - memset(ð_dev, 0, sizeof(eth_dev)); - memset((void *)eth_send_no_cache, 0, sizeof(DMA_DISC_ADDR_SIZE)); - memset((void *)eth_recv_no_cache, 0, sizeof(DMA_DISC_ADDR_SIZE)); - bcm271x_mbox_hardware_get_mac_address(&mac_addr[0]); - - eth_dev.iobase = mac_reg_base_addr; - eth_dev.name = "e0"; - eth_dev.dev_addr[0] = mac_addr[0]; - eth_dev.dev_addr[1] = mac_addr[1]; - eth_dev.dev_addr[2] = mac_addr[2]; - eth_dev.dev_addr[3] = mac_addr[3]; - eth_dev.dev_addr[4] = mac_addr[4]; - eth_dev.dev_addr[5] = mac_addr[5]; - - eth_dev.parent.parent.type = RT_Device_Class_NetIf; -#ifdef RT_USING_DEVICE_OPS - eth_dev.parent.parent.ops = ð_devops; -#else /* !RT_USING_DEVICE_OPS */ - eth_dev.parent.parent.init = bcmgenet_eth_init; - eth_dev.parent.parent.open = RT_NULL; - eth_dev.parent.parent.close = RT_NULL; - eth_dev.parent.parent.read = RT_NULL; - eth_dev.parent.parent.write = RT_NULL; - eth_dev.parent.parent.control = bcmgenet_eth_control; -#endif /* RT_USING_DEVICE_OPS */ - eth_dev.parent.parent.user_data = RT_NULL; - - eth_dev.parent.eth_tx = rt_eth_tx; - eth_dev.parent.eth_rx = rt_eth_rx; - - eth_device_init(&(eth_dev.parent), "e0"); - eth_device_linkchange(ð_dev.parent, RT_FALSE); //link down - return 0; -} -INIT_COMPONENT_EXPORT(rt_hw_eth_init); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.h deleted file mode 100644 index 952c8c5bc1..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_eth.h +++ /dev/null @@ -1,225 +0,0 @@ - -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-30 bigmagic first version - */ - -#ifndef __DRV_ETH_H__ -#define __DRV_ETH_H__ - - -//#define BIT(nr) (1UL << (nr)) -#define ENET_FRAME_MAX_FRAMELEN 1518U - -#define SYS_REV_CTRL (0x00) -#define SYS_PORT_CTRL (0x04) -#define PORT_MODE_EXT_GPHY (3) - -#define GENET_SYS_OFF (0x0000) -#define SYS_RBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x08) -#define SYS_TBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x0c) - -#define GENET_EXT_OFF (0x0080) -#define EXT_RGMII_OOB_CTRL (GENET_EXT_OFF + 0x0c) -#define RGMII_LINK BIT(4) -#define OOB_DISABLE BIT(5) -#define RGMII_MODE_EN BIT(6) -#define ID_MODE_DIS BIT(16) - -#define GENET_RBUF_OFF (0x0300) -#define RBUF_TBUF_SIZE_CTRL (GENET_RBUF_OFF + 0xb4) -#define RBUF_CTRL (GENET_RBUF_OFF + 0x00) -#define RBUF_ALIGN_2B BIT(1) - -#define GENET_UMAC_OFF (0x0800) -#define UMAC_MIB_CTRL (GENET_UMAC_OFF + 0x580) -#define UMAC_MAX_FRAME_LEN (GENET_UMAC_OFF + 0x014) -#define UMAC_MAC0 (GENET_UMAC_OFF + 0x00c) -#define UMAC_MAC1 (GENET_UMAC_OFF + 0x010) -#define UMAC_CMD (GENET_UMAC_OFF + 0x008) -#define MDIO_CMD (GENET_UMAC_OFF + 0x614) -#define UMAC_TX_FLUSH (GENET_UMAC_OFF + 0x334) -#define MDIO_START_BUSY BIT(29) -#define MDIO_READ_FAIL BIT(28) -#define MDIO_RD (2 << 26) -#define MDIO_WR BIT(26) -#define MDIO_PMD_SHIFT (21) -#define MDIO_PMD_MASK (0x1f) -#define MDIO_REG_SHIFT (16) -#define MDIO_REG_MASK (0x1f) - -#define GENET_INTRL2_OFF (0x0200) -#define GENET_INTRL2_CPU_STAT (GENET_INTRL2_OFF + 0x00) -#define GENET_INTRL2_CPU_CLEAR (GENET_INTRL2_OFF + 0x08) -#define GENET_INTRL2_CPU_STAT_MASK (GENET_INTRL2_OFF + 0x0c) -#define GENET_INTRL2_CPU_SET_MASK (GENET_INTRL2_OFF + 0x10) -#define GENET_INTRL2_CPU_CLEAR_MASK (GENET_INTRL2_OFF + 0x14) -#define GENET_IRQ_MDIO_ERROR BIT(24) -#define GENET_IRQ_MDIO_DONE BIT(23) -#define GENET_IRQ_TXDMA_DONE BIT(16) -#define GENET_IRQ_RXDMA_DONE BIT(13) - -#define CMD_TX_EN BIT(0) -#define CMD_RX_EN BIT(1) -#define UMAC_SPEED_10 (0) -#define UMAC_SPEED_100 (1) -#define UMAC_SPEED_1000 (2) -#define UMAC_SPEED_2500 (3) -#define CMD_SPEED_SHIFT (2) -#define CMD_SPEED_MASK (3) -#define CMD_SW_RESET BIT(13) -#define CMD_LCL_LOOP_EN BIT(15) -#define CMD_TX_EN BIT(0) -#define CMD_RX_EN BIT(1) - -#define MIB_RESET_RX BIT(0) -#define MIB_RESET_RUNT BIT(1) -#define MIB_RESET_TX BIT(2) - -/* total number of Buffer Descriptors, same for Rx/Tx */ -#define TOTAL_DESCS (256) -#define RX_DESCS TOTAL_DESCS -#define TX_DESCS TOTAL_DESCS - -#define DEFAULT_Q (0x10) - -#define ETH_DATA_LEN (1500) -#define ETH_HLEN (14) -#define VLAN_HLEN (4) -#define ETH_FCS_LEN (4) -/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528. - * 1536 is multiple of 256 bytes - */ -#define ENET_BRCM_TAG_LEN (6) -#define ENET_PAD (8) -#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + \ - VLAN_HLEN + ENET_BRCM_TAG_LEN + \ - ETH_FCS_LEN + ENET_PAD) - -/* Tx/Rx Dma Descriptor common bits */ -#define DMA_EN BIT(0) -#define DMA_RING_BUF_EN_SHIFT (0x01) -#define DMA_RING_BUF_EN_MASK (0xffff) -#define DMA_BUFLENGTH_MASK (0x0fff) -#define DMA_BUFLENGTH_SHIFT (16) -#define DMA_RING_SIZE_SHIFT (16) -#define DMA_OWN (0x8000) -#define DMA_EOP (0x4000) -#define DMA_SOP (0x2000) -#define DMA_WRAP (0x1000) -#define DMA_MAX_BURST_LENGTH (0x8) -/* Tx specific DMA descriptor bits */ -#define DMA_TX_UNDERRUN (0x0200) -#define DMA_TX_APPEND_CRC (0x0040) -#define DMA_TX_OW_CRC (0x0020) -#define DMA_TX_DO_CSUM (0x0010) -#define DMA_TX_QTAG_SHIFT (7) - -/* DMA rings size */ -#define DMA_RING_SIZE (0x40) -#define DMA_RINGS_SIZE (DMA_RING_SIZE * (DEFAULT_Q + 1)) - -/* DMA descriptor */ -#define DMA_DESC_LENGTH_STATUS (0x00) -#define DMA_DESC_ADDRESS_LO (0x04) -#define DMA_DESC_ADDRESS_HI (0x08) -#define DMA_DESC_SIZE (12) - -#define GENET_RX_OFF (0x2000) -#define GENET_RDMA_REG_OFF \ - (GENET_RX_OFF + TOTAL_DESCS * DMA_DESC_SIZE) -#define GENET_TX_OFF (0x4000) -#define GENET_TDMA_REG_OFF \ - (GENET_TX_OFF + TOTAL_DESCS * DMA_DESC_SIZE) - -#define DMA_FC_THRESH_HI (RX_DESCS >> 4) -#define DMA_FC_THRESH_LO (5) -#define DMA_FC_THRESH_VALUE ((DMA_FC_THRESH_LO << 16) | \ - DMA_FC_THRESH_HI) - -#define DMA_XOFF_THRESHOLD_SHIFT (16) - -#define TDMA_RING_REG_BASE \ - (GENET_TDMA_REG_OFF + DEFAULT_Q * DMA_RING_SIZE) -#define TDMA_READ_PTR (TDMA_RING_REG_BASE + 0x00) -#define TDMA_CONS_INDEX (TDMA_RING_REG_BASE + 0x08) -#define TDMA_PROD_INDEX (TDMA_RING_REG_BASE + 0x0c) -#define DMA_RING_BUF_SIZE (0x10) -#define DMA_START_ADDR (0x14) -#define DMA_END_ADDR (0x1c) -#define DMA_MBUF_DONE_THRESH (0x24) -#define TDMA_FLOW_PERIOD (TDMA_RING_REG_BASE + 0x28) -#define TDMA_WRITE_PTR (TDMA_RING_REG_BASE + 0x2c) - -#define RDMA_RING_REG_BASE \ - (GENET_RDMA_REG_OFF + DEFAULT_Q * DMA_RING_SIZE) -#define RDMA_WRITE_PTR (RDMA_RING_REG_BASE + 0x00) -#define RDMA_PROD_INDEX (RDMA_RING_REG_BASE + 0x08) -#define RDMA_CONS_INDEX (RDMA_RING_REG_BASE + 0x0c) -#define RDMA_XON_XOFF_THRESH (RDMA_RING_REG_BASE + 0x28) -#define RDMA_READ_PTR (RDMA_RING_REG_BASE + 0x2c) - -#define TDMA_REG_BASE (GENET_TDMA_REG_OFF + DMA_RINGS_SIZE) -#define RDMA_REG_BASE (GENET_RDMA_REG_OFF + DMA_RINGS_SIZE) -#define DMA_RING_CFG (0x00) -#define DMA_CTRL (0x04) -#define DMA_SCB_BURST_SIZE (0x0c) - -#define RX_BUF_LENGTH (2048) -#define RX_TOTAL_BUFSIZE (RX_BUF_LENGTH * RX_DESCS) -#define RX_BUF_OFFSET (2) - -#define PHY_INTERFACE_MODE_RGMII (7) -#define PHY_INTERFACE_MODE_RGMII_RXID (9) - -#define BCM54213PE_MII_CONTROL (0x00) -#define BCM54213PE_MII_STATUS (0x01) -#define BCM54213PE_PHY_IDENTIFIER_HIGH (0x02) -#define BCM54213PE_PHY_IDENTIFIER_LOW (0x03) - -#define BCM54213PE_AUTO_NEGOTIATION_ADV (0x04) -#define BCM54213PE_AUTO_NEGOTIATION_LINK (0x05) -#define BCM54213PE_AUTO_NEGOTIATION_EXPANSION (0x06) - -#define BCM54213PE_NEXT_PAGE_TX (0x07) - -#define BCM54213PE_PARTNER_RX (0x08) - -#define BCM54213PE_CONTROL (0x09) -#define BCM54213PE_STATUS (0x0A) - -#define BCM54213PE_IEEE_EXTENDED_STATUS (0x0F) -#define BCM54213PE_PHY_EXTENDED_CONTROL (0x10) -#define BCM54213PE_PHY_EXTENDED_STATUS (0x11) - -#define BCM54213PE_RECEIVE_ERROR_COUNTER (0x12) -#define BCM54213PE_FALSE_C_S_COUNTER (0x13) -#define BCM54213PE_RECEIVE_NOT_OK_COUNTER (0x14) - -#define BCM54213PE_VERSION_B1 (0x600d84a2) -#define BCM54213PE_VERSION_X (0x600d84a0) - -//BCM54213PE_MII_CONTROL -#define MII_CONTROL_PHY_RESET (1 << 15) -#define MII_CONTROL_AUTO_NEGOTIATION_ENABLED (1 << 12) -#define MII_CONTROL_AUTO_NEGOTIATION_RESTART (1 << 9) -#define MII_CONTROL_PHY_FULL_DUPLEX (1 << 8) -#define MII_CONTROL_SPEED_SELECTION (1 << 6) - -//BCM54213PE_MII_STATUS -#define MII_STATUS_LINK_UP (1 << 2) - -//BCM54213PE_CONTROL -#define CONTROL_FULL_DUPLEX_CAPABILITY (1 << 9) -#define CONTROL_HALF_DUPLEX_CAPABILITY (1 << 8) - -#define SPEED_1000 (1000) -#define SPEED_100 (100) -#define SPEED_10 (10) - -#endif/* __DRV_ETH_H__ */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.c deleted file mode 100644 index 602d508e6b..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - * 2020-06-16 bigmagic add gpio irq - */ - -#include "drv_gpio.h" - -#ifdef BSP_USING_PIN - -/* - * gpio_int[0] for BANK0 (pins 0-27) - * gpio_int[1] for BANK1 (pins 28-45) - * gpio_int[2] for BANK2 (pins 46-53) - */ -static struct gpio_irq_def _g_gpio_irq_tbl[GPIO_IRQ_NUM]; - -uint32_t raspi_get_pin_state(uint32_t fselnum) -{ - uint32_t gpfsel = 0; - - switch (fselnum) - { - case 0: - gpfsel = GPIO_REG_GPFSEL0(gpio_base_addr); - break; - case 1: - gpfsel = GPIO_REG_GPFSEL1(gpio_base_addr); - break; - case 2: - gpfsel = GPIO_REG_GPFSEL2(gpio_base_addr); - break; - case 3: - gpfsel = GPIO_REG_GPFSEL3(gpio_base_addr); - break; - case 4: - gpfsel = GPIO_REG_GPFSEL4(gpio_base_addr); - break; - case 5: - gpfsel = GPIO_REG_GPFSEL5(gpio_base_addr); - break; - default: - break; - } - return gpfsel; -} - -void raspi_set_pin_state(uint32_t fselnum, uint32_t gpfsel) -{ - switch (fselnum) - { - case 0: - GPIO_REG_GPFSEL0(gpio_base_addr) = gpfsel; - break; - case 1: - GPIO_REG_GPFSEL1(gpio_base_addr) = gpfsel; - break; - case 2: - GPIO_REG_GPFSEL2(gpio_base_addr) = gpfsel; - break; - case 3: - GPIO_REG_GPFSEL3(gpio_base_addr) = gpfsel; - break; - case 4: - GPIO_REG_GPFSEL4(gpio_base_addr) = gpfsel; - break; - case 5: - GPIO_REG_GPFSEL5(gpio_base_addr) = gpfsel; - break; - default: - break; - } -} - -static void gpio_set_pud(GPIO_PIN pin, GPIO_PUPD_FUNC mode) -{ - uint32_t fselnum = pin / 16; - uint32_t fselrest = pin % 16; - uint32_t reg_value = 0; - - switch (fselnum) - { - case 0: - reg_value = GPIO_PUP_PDN_CNTRL_REG0(gpio_base_addr); - GPIO_PUP_PDN_CNTRL_REG0(gpio_base_addr) = (reg_value | (mode << (fselrest*2))); - break; - case 1: - reg_value = GPIO_PUP_PDN_CNTRL_REG1(gpio_base_addr); - GPIO_PUP_PDN_CNTRL_REG1(gpio_base_addr) = (reg_value | (mode << (fselrest*2))); - break; - - case 2: - reg_value = GPIO_PUP_PDN_CNTRL_REG2(gpio_base_addr); - GPIO_PUP_PDN_CNTRL_REG2(gpio_base_addr) = (reg_value | (mode << (fselrest*2))); - break; - - case 3: - reg_value = GPIO_PUP_PDN_CNTRL_REG3(gpio_base_addr); - GPIO_PUP_PDN_CNTRL_REG3(gpio_base_addr) = (reg_value | (mode << (fselrest*2))); - break; - default: - break; - } -} - -void prev_raspi_pin_mode(GPIO_PIN pin, GPIO_FUNC mode) -{ - uint32_t fselnum = pin / 10; - uint32_t fselrest = pin % 10; - uint32_t gpfsel = 0; - - gpfsel = raspi_get_pin_state(fselnum); - gpfsel &= ~((uint32_t)(0x07 << (fselrest * 3))); - gpfsel |= (uint32_t)(mode << (fselrest * 3)); - raspi_set_pin_state(fselnum, gpfsel); -} - -void prev_raspi_pin_write(GPIO_PIN pin, int pin_value) -{ - uint32_t num = pin / 32; - - if(num == 0) - { - if(pin_value == 1) - { - GPIO_REG_GPSET0(gpio_base_addr) = 1 << (pin % 32); - } - else - { - GPIO_REG_GPCLR0(gpio_base_addr) = 1 << (pin % 32); - } - } - else - { - if(pin_value == 1) - { - GPIO_REG_GPSET1(gpio_base_addr) = 1 << (pin % 32); - } - else - { - GPIO_REG_GPCLR1(gpio_base_addr) = 1 << (pin % 32); - } - } -} - -static void raspi_pin_mode(struct rt_device *dev, rt_base_t pin, rt_uint8_t mode) -{ - GPIO_FUNC raspi_mode = OUTPUT; - - switch (mode) - { - case PIN_MODE_OUTPUT: - raspi_mode = OUTPUT; - break; - case PIN_MODE_INPUT: - raspi_mode = INPUT; - break; - case PIN_MODE_INPUT_PULLUP: - gpio_set_pud(pin, RASPI_PULL_UP); - raspi_mode = INPUT; - break; - case PIN_MODE_INPUT_PULLDOWN: - gpio_set_pud(pin, RASPI_PULL_DOWN); - raspi_mode = INPUT; - break; - case PIN_MODE_OUTPUT_OD: - raspi_mode = OUTPUT; - break; - } - prev_raspi_pin_mode((GPIO_PIN)pin, raspi_mode); -} - -static void raspi_pin_write(struct rt_device *dev, rt_base_t pin, rt_uint8_t value) -{ - prev_raspi_pin_write(pin, value); -} - -static rt_ssize_t raspi_pin_read(struct rt_device *device, rt_base_t pin) -{ - uint32_t num = pin / 32; - rt_ssize_t pin_level = 0; - - if(num == 0) - { - if(GPIO_REG_GPLEV0(gpio_base_addr) & (1 << pin)) - { - pin_level = 1; - } - else - { - pin_level = 0; - } - - } - else - { - if(GPIO_REG_GPLEV1(gpio_base_addr) & (1 << pin)) - { - pin_level = 1; - } - else - { - pin_level = 0; - } - } - - return pin_level; -} - -static rt_err_t raspi_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) -{ - rt_uint8_t index; - rt_uint32_t reg_value; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - _g_gpio_irq_tbl[index].irq_cb[pin] = hdr; - _g_gpio_irq_tbl[index].irq_arg[pin] = args; - _g_gpio_irq_tbl[index].irq_type[pin] = mode; - - rt_uint8_t shift = pin % 32; - rt_uint8_t pin_num = pin / 32; - rt_uint32_t mask = 1 << shift; - - switch (mode) - { - case PIN_IRQ_MODE_RISING: - if(pin_num == 0) - { - reg_value = GPIO_REG_GPREN0(gpio_base_addr); - GPIO_REG_GPREN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - else - { - reg_value = GPIO_REG_GPREN1(gpio_base_addr); - GPIO_REG_GPREN1(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - break; - case PIN_IRQ_MODE_FALLING: - if(pin_num == 0) - { - reg_value = GPIO_REG_GPFEN0(gpio_base_addr); - GPIO_REG_GPFEN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - else - { - reg_value = GPIO_REG_GPFEN1(gpio_base_addr); - GPIO_REG_GPFEN1(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - break; - case PIN_IRQ_MODE_RISING_FALLING: - if(pin_num == 0) - { - reg_value = GPIO_REG_GPAREN0(gpio_base_addr); - GPIO_REG_GPAREN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - reg_value = GPIO_REG_GPFEN0(gpio_base_addr); - GPIO_REG_GPFEN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - else - { - reg_value = GPIO_REG_GPAREN1(gpio_base_addr); - GPIO_REG_GPAREN1(gpio_base_addr) = (reg_value & ~ mask) | (mask); - reg_value = GPIO_REG_GPFEN1(gpio_base_addr); - GPIO_REG_GPFEN1(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - break; - case PIN_IRQ_MODE_HIGH_LEVEL: - if(pin_num == 0) - { - reg_value = GPIO_REG_GPHEN0(gpio_base_addr); - GPIO_REG_GPHEN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - else - { - reg_value = GPIO_REG_GPHEN1(gpio_base_addr); - GPIO_REG_GPHEN1(gpio_base_addr) = (reg_value & ~ mask) | ( mask); - } - break; - case PIN_IRQ_MODE_LOW_LEVEL: - if(pin_num == 0) - { - reg_value = GPIO_REG_GPLEN0(gpio_base_addr); - GPIO_REG_GPLEN0(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - else - { - reg_value = GPIO_REG_GPLEN1(gpio_base_addr); - GPIO_REG_GPLEN1(gpio_base_addr) = (reg_value & ~ mask) | (mask); - } - break; - } - return RT_EOK; -} - -static rt_err_t raspi_pin_detach_irq(struct rt_device *device, rt_base_t pin) -{ - rt_uint8_t index; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - - _g_gpio_irq_tbl[index].irq_cb[pin] = RT_NULL; - _g_gpio_irq_tbl[index].irq_arg[pin] = RT_NULL; - _g_gpio_irq_tbl[index].irq_type[pin] = RT_NULL; - _g_gpio_irq_tbl[index].state[pin] = RT_NULL; - - return RT_EOK; -} - -rt_err_t raspi_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) -{ - rt_uint8_t index; - if (pin <= 27) - index = 0; - else if (pin <= 45) - index = 1; - else - index = 2; - - if (enabled) - _g_gpio_irq_tbl[index].state[pin] = 1; - else - _g_gpio_irq_tbl[index].state[pin] = 0; - - return RT_EOK; -} - -static const struct rt_pin_ops ops = -{ - raspi_pin_mode, - raspi_pin_write, - raspi_pin_read, - raspi_pin_attach_irq, - raspi_pin_detach_irq, - raspi_pin_irq_enable, - RT_NULL, -}; - -static void gpio_irq_handler(int irq, void *param) -{ - struct gpio_irq_def *irq_def = (struct gpio_irq_def *)param; - rt_uint32_t pin; - rt_uint32_t value; - rt_uint32_t tmpvalue; - - if(irq == IRQ_GPIO0) - { - /* 0~27 */ - value = GPIO_REG_GPEDS0(gpio_base_addr); - value &= 0x0fffffff; - pin = 0; - GPIO_REG_GPEDS0(gpio_base_addr) = value; - } - else if(irq == IRQ_GPIO1) - { - /* 28-45 */ - tmpvalue = GPIO_REG_GPEDS0(gpio_base_addr); - tmpvalue &= (~0x0fffffff); - GPIO_REG_GPEDS0(gpio_base_addr) = tmpvalue; - - value = GPIO_REG_GPEDS1(gpio_base_addr); - value &= 0x3fff; - GPIO_REG_GPEDS1(gpio_base_addr) = value; - value = (value) | tmpvalue; - pin = 28; - } - else if (irq == IRQ_GPIO2) - { - /* 46-53 */ - value = GPIO_REG_GPEDS1(gpio_base_addr); - value &= (~0x3fff); - GPIO_REG_GPEDS1(gpio_base_addr) = value; - pin = 46; - } - - while (value) - { - if ((value & 0x1) && (irq_def->irq_cb[pin] != RT_NULL)) - { - if(irq_def->state[pin]) - { - irq_def->irq_cb[pin](irq_def->irq_arg[pin]); - } - } - pin++; - value = value >> 1; - } -} -#endif - -int rt_hw_gpio_init(void) -{ -#ifdef BSP_USING_PIN - rt_device_pin_register("gpio", &ops, RT_NULL); - - //disable all intr - GPIO_REG_GPEDS0(gpio_base_addr) = 0xffffffff; - GPIO_REG_GPEDS1(gpio_base_addr) = 0xffffffff; - - GPIO_REG_GPREN0(gpio_base_addr) = 0x0; - GPIO_REG_GPREN1(gpio_base_addr) = 0x0; - - GPIO_REG_GPFEN0(gpio_base_addr) = 0x0; - GPIO_REG_GPFEN1(gpio_base_addr) = 0x0; - - GPIO_REG_GPHEN0(gpio_base_addr) = 0x0; - GPIO_REG_GPHEN1(gpio_base_addr) = 0x0; - - GPIO_REG_GPAREN0(gpio_base_addr) = 0x0; - GPIO_REG_GPAREN1(gpio_base_addr) = 0x0; - - GPIO_REG_GPAFEN0(gpio_base_addr) = 0x0; - GPIO_REG_GPAFEN0(gpio_base_addr) = 0x0; - - rt_hw_interrupt_install(IRQ_GPIO0, gpio_irq_handler, &_g_gpio_irq_tbl[0], "gpio0_irq"); - rt_hw_interrupt_umask(IRQ_GPIO0); - - rt_hw_interrupt_install(IRQ_GPIO1, gpio_irq_handler, &_g_gpio_irq_tbl[1], "gpio1_irq"); - rt_hw_interrupt_umask(IRQ_GPIO1); - - rt_hw_interrupt_install(IRQ_GPIO2, gpio_irq_handler, &_g_gpio_irq_tbl[2], "gpio2_irq"); - rt_hw_interrupt_umask(IRQ_GPIO2); - -#endif - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_gpio_init); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.h deleted file mode 100644 index 5f564e35d1..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_gpio.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - */ - -#ifndef __DRV_GPIO_H__ -#define __DRV_GPIO_H__ - -#include -#include - -#include "board.h" -#include "interrupt.h" - -struct gpio_irq_def -{ - void *irq_arg[32]; - void (*irq_cb[32])(void *param); - rt_uint8_t irq_type[32]; - rt_uint8_t state[32]; -}; - -#define GPIO_REG_GPFSEL0(BASE) HWREG32(BASE + 0x00) -#define GPIO_REG_GPFSEL1(BASE) HWREG32(BASE + 0x04) -#define GPIO_REG_GPFSEL2(BASE) HWREG32(BASE + 0x08) -#define GPIO_REG_GPFSEL3(BASE) HWREG32(BASE + 0x0C) -#define GPIO_REG_GPFSEL4(BASE) HWREG32(BASE + 0x10) -#define GPIO_REG_GPFSEL5(BASE) HWREG32(BASE + 0x14) -#define GPIO_REG_REV0(BASE) HWREG32(BASE + 0x18) -#define GPIO_REG_GPSET0(BASE) HWREG32(BASE + 0x1C) -#define GPIO_REG_GPSET1(BASE) HWREG32(BASE + 0x20) -#define GPIO_REG_REV1(BASE) HWREG32(BASE + 0x24) -#define GPIO_REG_GPCLR0(BASE) HWREG32(BASE + 0x28) -#define GPIO_REG_GPCLR1(BASE) HWREG32(BASE + 0x2C) -#define GPIO_REG_REV2(BASE) HWREG32(BASE + 0x30) -#define GPIO_REG_GPLEV0(BASE) HWREG32(BASE + 0x34) -#define GPIO_REG_GPLEV1(BASE) HWREG32(BASE + 0x38) -#define GPIO_REG_REV3(BASE) HWREG32(BASE + 0x3C) -#define GPIO_REG_GPEDS0(BASE) HWREG32(BASE + 0x40) -#define GPIO_REG_GPEDS1(BASE) HWREG32(BASE + 0x44) -#define GPIO_REG_REV4(BASE) HWREG32(BASE + 0x48) -#define GPIO_REG_GPREN0(BASE) HWREG32(BASE + 0x4C) -#define GPIO_REG_GPREN1(BASE) HWREG32(BASE + 0x50) -#define GPIO_REG_REV5(BASE) HWREG32(BASE + 0x54) -#define GPIO_REG_GPFEN0(BASE) HWREG32(BASE + 0x58) -#define GPIO_REG_GPFEN1(BASE) HWREG32(BASE + 0x5C) -#define GPIO_REG_REV6(BASE) HWREG32(BASE + 0x60) -#define GPIO_REG_GPHEN0(BASE) HWREG32(BASE + 0x64) -#define GPIO_REG_GPHEN1(BASE) HWREG32(BASE + 0x68) -#define GPIO_REG_REV7(BASE) HWREG32(BASE + 0x6C) -#define GPIO_REG_GPLEN0(BASE) HWREG32(BASE + 0x70) -#define GPIO_REG_GPLEN1(BASE) HWREG32(BASE + 0x74) -#define GPIO_REG_REV8(BASE) HWREG32(BASE + 0x78) -#define GPIO_REG_GPAREN0(BASE) HWREG32(BASE + 0x7C) -#define GPIO_REG_GPAREN1(BASE) HWREG32(BASE + 0x80) -#define GPIO_REG_REV11(BASE) HWREG32(BASE + 0x84) -#define GPIO_REG_GPAFEN0(BASE) HWREG32(BASE + 0x88) -#define GPIO_REG_GPAFEN1(BASE) HWREG32(BASE + 0x8C) -#define GPIO_REG_REV10(BASE) HWREG32(BASE + 0x90) -#define GPIO_REG_GPPUD(BASE) HWREG32(BASE + 0x94) -#define GPIO_REG_GPPUDCLK0(BASE) HWREG32(BASE + 0x98) -#define GPIO_REG_GPPUDCLK1(BASE) HWREG32(BASE + 0x9C) -#define GPIO_REG_REV9(BASE) HWREG32(BASE + 0xA0) -#define GPIO_REG_TEST(BASE) HWREG32(BASE + 0xA4) -#define GPIO_PUP_PDN_CNTRL_REG0(BASE) HWREG32(BASE + 0xE4) -#define GPIO_PUP_PDN_CNTRL_REG1(BASE) HWREG32(BASE + 0xE8) -#define GPIO_PUP_PDN_CNTRL_REG2(BASE) HWREG32(BASE + 0xEC) -#define GPIO_PUP_PDN_CNTRL_REG3(BASE) HWREG32(BASE + 0xF0) - -typedef enum { - GPIO_PIN_0, - GPIO_PIN_1, - GPIO_PIN_2, - GPIO_PIN_3, - GPIO_PIN_4, - GPIO_PIN_5, - GPIO_PIN_6, - GPIO_PIN_7, - GPIO_PIN_8, - GPIO_PIN_9, - GPIO_PIN_10, - GPIO_PIN_11, - GPIO_PIN_12, - GPIO_PIN_13, - GPIO_PIN_14, - GPIO_PIN_15, - GPIO_PIN_16, - GPIO_PIN_17, - GPIO_PIN_18, - GPIO_PIN_19, - GPIO_PIN_20, - GPIO_PIN_21, - GPIO_PIN_22, - GPIO_PIN_23, - GPIO_PIN_24, - GPIO_PIN_25, - GPIO_PIN_26, - GPIO_PIN_27, - GPIO_PIN_28, - GPIO_PIN_29, - GPIO_PIN_30, - GPIO_PIN_31, - GPIO_PIN_32, - GPIO_PIN_33, - GPIO_PIN_34, - GPIO_PIN_35, - GPIO_PIN_36, - GPIO_PIN_37, - GPIO_PIN_38, - GPIO_PIN_39, - GPIO_PIN_40, -} GPIO_PIN; - -typedef enum { - INPUT = 0b000, - OUTPUT = 0b001, - ALT0 = 0b100, - ALT1 = 0b101, - ALT2 = 0b110, - ALT3 = 0b111, - ALT4 = 0b011, - ALT5 = 0b010 -} GPIO_FUNC; - -typedef enum { - RASPI_NO_RESISTOR = 0x00, - RASPI_PULL_UP = 0x01, - RASPI_PULL_DOWN = 0x10 -} GPIO_PUPD_FUNC; - -void prev_raspi_pin_mode(GPIO_PIN pin, GPIO_FUNC mode); -void prev_raspi_pin_write(GPIO_PIN pin, int pin_value); -int rt_hw_gpio_init(void); - -#endif /* __DRV_GPIO_H__ */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_gtimer.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_gtimer.c deleted file mode 100644 index d8a1c77abd..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_gtimer.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include "interrupt.h" - -#ifndef RT_CPUS_NR -#define RT_CPUS_NR 1 -#endif - -#define GTIMER_IRQ (27) - -static uint64_t _tickval[RT_CPUS_NR]; -static uint64_t _increaseval[RT_CPUS_NR]; -#define tickval _tickval[cpu_id] -#define increaseval _increaseval[cpu_id] - -/** - * This function is the gtimer isr handler. - * - * @param vector interrupt ID - * @param parameter the parameter specified by rt_hw_interrupt_install - * - * @return none - */ -static void _hw_timer_isr(int vector, void *parameter) -{ -#ifdef RT_USING_SMP - int cpu_id = rt_hw_cpu_id(); -#else - int cpu_id = 0; -#endif - uint64_t cntvct_el0; - do - { - tickval += increaseval; - __asm__ volatile("msr CNTV_CVAL_EL0, %0"::"r"(tickval)); - __asm__ volatile("mrs %0, CNTVCT_EL0":"=r"(cntvct_el0)); - } while (cntvct_el0 >= tickval); - rt_tick_increase(); -} - -/** - * The function will initialize the general timer used for the system tick. - * - * @param none - * - * @return none - */ -rt_weak int rt_hw_gtimer_init(void) -{ -#ifdef RT_USING_SMP - int cpu_id = rt_hw_cpu_id(); -#else - int cpu_id = 0; -#endif - uint64_t val; - - rt_hw_interrupt_install(GTIMER_IRQ, _hw_timer_isr, RT_NULL, "tick"); - rt_hw_interrupt_umask(GTIMER_IRQ); - - __asm__ volatile("mrs %0, CNTFRQ_EL0":"=r"(val)); - increaseval = val / RT_TICK_PER_SECOND; - - __asm__ volatile("msr CNTV_CTL_EL0, %0"::"r"(val)); - tickval = increaseval; - __asm__ volatile("msr CNTV_CVAL_EL0, %0"::"r"(tickval)); - val = 1; - __asm__ volatile("msr CNTV_CTL_EL0, %0"::"r"(val)); - return 0; -} -INIT_BOARD_EXPORT(rt_hw_gtimer_init); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.c deleted file mode 100644 index 1ba43e9a48..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-26 bigmagic first version - */ - -#include -#include -#include - -#if defined(BSP_USING_HDMI) && defined(RT_USING_SMART) -#include -#include - -#include - -#include "mbox.h" -#include "drv_hdmi.h" - -#define LCD_WIDTH (800) -#define LCD_HEIGHT (480) -#define LCD_DEPTH (32) -#define LCD_BPP (32) - -#define TAG_ALLOCATE_BUFFER 0x00040001 -#define TAG_SET_PHYS_WIDTH_HEIGHT 0x00048003 -#define TAG_SET_VIRT_WIDTH_HEIGHT 0x00048004 -#define TAG_SET_DEPTH 0x00048005 -#define TAG_SET_PIXEL_ORDER 0x00048006 -#define TAG_GET_PITCH 0x00040008 -#define TAG_SET_VIRT_OFFSET 0x00048009 -#define TAG_END 0x00000000 - - -enum { - MBOX_TAG_FB_GET_GPIOVIRT = 0x00040010, - MBOX_TAG_FB_ALLOCATE_BUFFER = 0x00040001, - MBOX_TAG_FB_RELEASE_BUFFER = 0x00048001, - MBOX_TAG_FB_BLANK_SCREEN = 0x00040002, - MBOX_TAG_FB_GET_PHYS_WH = 0x00040003, - MBOX_TAG_FB_TEST_PHYS_WH = 0x00044003, - MBOX_TAG_FB_SET_PHYS_WH = 0x00048003, - MBOX_TAG_FB_GET_VIRT_WH = 0x00040004, - MBOX_TAG_FB_TEST_VIRT_WH = 0x00044004, - MBOX_TAG_FB_SET_VIRT_WH = 0x00048004, - MBOX_TAG_FB_GET_DEPTH = 0x00040005, - MBOX_TAG_FB_TEST_DEPTH = 0x00044005, - MBOX_TAG_FB_SET_DEPTH = 0x00048005, - MBOX_TAG_FB_GET_PIXEL_ORDER = 0x00040006, - MBOX_TAG_FB_TEST_PIXEL_ORDER = 0x00044006, - MBOX_TAG_FB_SET_PIXEL_ORDER = 0x00048006, - MBOX_TAG_FB_GET_ALPHA_MODE = 0x00040007, - MBOX_TAG_FB_TEST_ALPHA_MODE = 0x00044007, - MBOX_TAG_FB_SET_ALPHA_MODE = 0x00048007, - MBOX_TAG_FB_GET_PITCH = 0x00040008, - MBOX_TAG_FB_GET_VIRT_OFFSET = 0x00040009, - MBOX_TAG_FB_TEST_VIRT_OFFSET = 0x00044009, - MBOX_TAG_FB_SET_VIRT_OFFSET = 0x00048009, - MBOX_TAG_FB_GET_OVERSCAN = 0x0004000a, - MBOX_TAG_FB_TEST_OVERSCAN = 0x0004400a, - MBOX_TAG_FB_SET_OVERSCAN = 0x0004800a, - MBOX_TAG_FB_GET_PALETTE = 0x0004000b, - MBOX_TAG_FB_TEST_PALETTE = 0x0004400b, - MBOX_TAG_FB_SET_PALETTE = 0x0004800b, -}; - -#define LCD_DEVICE(dev) (struct rt_hdmi_fb_device*)(dev) - -static struct rt_hdmi_fb_device _hdmi; - -typedef rt_uint16_t color_t; - -rt_err_t hdmi_fb_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; -} - -rt_err_t hdmi_fb_close(rt_device_t dev) -{ - return RT_EOK; -} - -rt_ssize_t hdmi_fb_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size) -{ - return 0; -} - -rt_ssize_t hdmi_fb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - return size; -} - -rt_err_t hdmi_fb_control(rt_device_t dev, int cmd, void *args) -{ - static unsigned long smem_start = 0; - static unsigned long smem_len = 0; - struct rt_hdmi_fb_device *lcd = LCD_DEVICE(dev); - - switch (cmd) - { - case RTGRAPHIC_CTRL_RECT_UPDATE: - { - if (smem_start != 0) - { - rt_hw_cpu_dcache_clean_and_invalidate((void *)smem_start, smem_len); - } - } - break; - case RTGRAPHIC_CTRL_GET_INFO: - { - struct rt_device_graphic_info *lcd_info = (struct rt_device_graphic_info *)args; - lcd_info->bits_per_pixel = 32; - lcd_info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_ARGB888; /* should be coherent to adding layers */ - lcd_info->width = lcd->width; - lcd_info->height = lcd->height; - lcd_info->framebuffer = (void *)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb, lcd->width * lcd->height * sizeof(rt_uint32_t), 1); - } - break; -#define FBIOGET_FSCREENINFO 0x4602 - case FBIOGET_FSCREENINFO: - { - struct fb_fix_screeninfo - { - char id[16]; - unsigned long smem_start; - uint32_t smem_len; - - uint32_t line_length; - } *info = (struct fb_fix_screeninfo *)args; - rt_strncpy(info->id, "lcd", sizeof(info->id)); - info->smem_len = lcd->width * lcd->height * sizeof(rt_uint32_t); - info->smem_start = (size_t)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb, info->smem_len, 1); - info->line_length = lcd->width * sizeof(rt_uint32_t); - rt_memset((void *)info->smem_start, 0, info->smem_len); - smem_start = info->smem_start; - smem_len = info->smem_len; - } - break; - } - return RT_EOK; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops hdmi_fb_ops = -{ - RT_NULL, - hdmi_fb_open, - hdmi_fb_close, - hdmi_fb_read, - hdmi_fb_write, - hdmi_fb_control, -}; -#endif - -rt_err_t rt_hdmi_fb_device_init(struct rt_hdmi_fb_device *hdmi_fb, const char *name) -{ - struct rt_device *device; - RT_ASSERT(hdmi_fb != RT_NULL); - - device = &hdmi_fb->parent; - - /* set device type */ - device->type = RT_Device_Class_Graphic; - /* initialize device interface */ -#ifdef RT_USING_DEVICE_OPS - device->ops = &hdmi_fb_ops; -#else - device->init = RT_NULL; - device->open = hdmi_fb_open; - device->close = hdmi_fb_close; - device->read = hdmi_fb_read; - device->write = hdmi_fb_write; - device->control = hdmi_fb_control; -#endif - - /* register to device manager */ - rt_device_register(device, name, RT_DEVICE_FLAG_RDWR); - - return RT_EOK; -} - -rt_uint32_t bcm271x_mbox_fb_get_gpiovirt(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_GET_GPIOVIRT; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return (mbox[5] & 0x3fffffff); -} - -rt_uint32_t bcm271x_mbox_fb_get_pitch(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_GET_PITCH; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return mbox[5]; -} - -void bcm271x_mbox_fb_set_porder(int rgb) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_PIXEL_ORDER; - mbox[3] = 4; // buffer size - mbox[4] = 4; // len - - mbox[5] = rgb; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - -void bcm271x_mbox_fb_setoffset(int xoffset, int yoffset) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_VIRT_OFFSET; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = xoffset; // id - mbox[6] = yoffset; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - - -void bcm271x_mbox_fb_setalpha(int alpha) -{ - - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_FB_SET_ALPHA_MODE; - mbox[3] = 4; // buffer size - mbox[4] = 4; // len - - mbox[5] = alpha; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); -} - -void *bcm271x_mbox_fb_alloc(int width, int height, int bpp, int nrender) -{ - mbox[0] = 4 * 35; - mbox[1] = MBOX_REQUEST; - - mbox[2] = TAG_ALLOCATE_BUFFER;//get framebuffer, gets alignment on request - mbox[3] = 8; //size - mbox[4] = 4; //len - mbox[5] = 4096; //The design of MBOX driver forces us to give the virtual address 0x3C100000 - mbox[6] = 0; //FrameBufferInfo.size - - mbox[7] = TAG_SET_PHYS_WIDTH_HEIGHT; - mbox[8] = 8; - mbox[9] = 8; - mbox[10] = width; - mbox[11] = height; - - mbox[12] = TAG_SET_VIRT_WIDTH_HEIGHT; - mbox[13] = 8; - mbox[14] = 8; - mbox[15] = width; - mbox[16] = height * nrender; - - mbox[17] = TAG_SET_DEPTH; - mbox[18] = 4; - mbox[19] = 4; - mbox[20] = bpp; - - mbox[21] = TAG_SET_PIXEL_ORDER; - mbox[22] = 4; - mbox[23] = 0; - mbox[24] = 0; //RGB, not BGR preferably - - mbox[25] = TAG_GET_PITCH; - mbox[26] = 4; - mbox[27] = 0; - mbox[28] = 0; - - mbox[29] = TAG_SET_VIRT_OFFSET; - mbox[30] = 8; - mbox[31] = 8; - mbox[32] = 0; - mbox[33] = 0; - - mbox[34] = TAG_END; - - mbox_call(8, MMU_DISABLE); - return (void *)((size_t)(mbox[5] & 0x3fffffff)); -} - -int hdmi_fb_init(void) -{ - _hdmi.fb = (rt_uint8_t *)bcm271x_mbox_fb_alloc(LCD_WIDTH, LCD_HEIGHT, LCD_BPP, 1); - - if (_hdmi.fb == RT_NULL) - { - rt_kprintf("init hdmi fb err!\n"); - return -RT_ERROR; - } - -#ifdef BSP_USING_VM_MODE - if (rt_hv_stage2_map((unsigned long)_hdmi.fb, 0x1400000)) - { - rt_kprintf("alloc mmio from hyper fail!\n"); - return -RT_ERROR; - } -#endif - - bcm271x_mbox_fb_setoffset(0, 0); - bcm271x_mbox_fb_set_porder(0); - _hdmi.width = LCD_WIDTH; - _hdmi.height = LCD_HEIGHT; - _hdmi.depth = LCD_DEPTH; - _hdmi.pitch = 0; - _hdmi.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888; - - //rt_kprintf("_hdmi.fb is %p\n", _hdmi.fb); - rt_hdmi_fb_device_init(&_hdmi, "lcd"); - - return 0; -} - -INIT_DEVICE_EXPORT(hdmi_fb_init); -#endif /*BSP_USING_HDMI */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.h deleted file mode 100644 index c9a06358d0..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_hdmi.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-26 bigmagic first version - */ -#ifndef __DRV_HDMI_H__ -#define __DRV_HDMI_H__ - -#define RGB(r, g, b) ((((r))<<16) | (((g))<<8) | ((b))) - -struct rt_hdmi_fb_device -{ - struct rt_device parent; - - rt_uint32_t width; - rt_uint32_t height; - rt_uint32_t depth; - rt_uint32_t pitch; - rt_uint32_t pixel_format; - - rt_uint8_t *fb; -}; -#endif/* __DRV_HDMI_H__ */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c deleted file mode 100644 index 6206165098..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-27 bigmagic first version - */ - -#include "mbox.h" -#include "raspi4.h" -#include "drv_sdio.h" - -static rt_uint32_t mmc_base_clock = 0; - -static rt_uint32_t sdCommandTable[] = { - SD_CMD_INDEX(0), - SD_CMD_RESERVED(1), - SD_CMD_INDEX(2) | SD_RESP_R2, - SD_CMD_INDEX(3) | SD_RESP_R1, - SD_CMD_INDEX(4), - SD_CMD_RESERVED(5), //SD_CMD_INDEX(5) | SD_RESP_R4, - SD_CMD_INDEX(6) | SD_RESP_R1, - SD_CMD_INDEX(7) | SD_RESP_R1b, - SD_CMD_INDEX(8) | SD_RESP_R1, - SD_CMD_INDEX(9) | SD_RESP_R2, - SD_CMD_INDEX(10) | SD_RESP_R2, - SD_CMD_INDEX(11) | SD_RESP_R1, - SD_CMD_INDEX(12) | SD_RESP_R1b | SD_CMD_TYPE_ABORT, - SD_CMD_INDEX(13) | SD_RESP_R1, - SD_CMD_RESERVED(14), - SD_CMD_INDEX(15), - SD_CMD_INDEX(16) | SD_RESP_R1, - SD_CMD_INDEX(17) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_INDEX(18) | SD_RESP_R1 | SD_DATA_READ | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN, - SD_CMD_INDEX(19) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_INDEX(20) | SD_RESP_R1b, - SD_CMD_RESERVED(21), - SD_CMD_RESERVED(22), - SD_CMD_INDEX(23) | SD_RESP_R1, - SD_CMD_INDEX(24) | SD_RESP_R1 | SD_DATA_WRITE, - SD_CMD_INDEX(25) | SD_RESP_R1 | SD_DATA_WRITE | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN, - SD_CMD_INDEX(26) | SD_RESP_R1 | SD_DATA_WRITE, //add - SD_CMD_INDEX(27) | SD_RESP_R1 | SD_DATA_WRITE, - SD_CMD_INDEX(28) | SD_RESP_R1b, - SD_CMD_INDEX(29) | SD_RESP_R1b, - SD_CMD_INDEX(30) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_RESERVED(31), - SD_CMD_INDEX(32) | SD_RESP_R1, - SD_CMD_INDEX(33) | SD_RESP_R1, - SD_CMD_RESERVED(34), - SD_CMD_INDEX(35) | SD_RESP_R1, //add - SD_CMD_INDEX(36) | SD_RESP_R1, //add - SD_CMD_RESERVED(37), - SD_CMD_INDEX(38) | SD_RESP_R1b, - SD_CMD_INDEX(39) | SD_RESP_R4, //add - SD_CMD_INDEX(40) | SD_RESP_R5, //add - SD_CMD_INDEX(41) | SD_RESP_R3, //add, mov from harbote - SD_CMD_RESERVED(42) | SD_RESP_R1, - SD_CMD_RESERVED(43), - SD_CMD_RESERVED(44), - SD_CMD_RESERVED(45), - SD_CMD_RESERVED(46), - SD_CMD_RESERVED(47), - SD_CMD_RESERVED(48), - SD_CMD_RESERVED(49), - SD_CMD_RESERVED(50), - SD_CMD_INDEX(51) | SD_RESP_R1 | SD_DATA_READ, - SD_CMD_RESERVED(52), - SD_CMD_RESERVED(53), - SD_CMD_RESERVED(54), - SD_CMD_INDEX(55) | SD_RESP_R3, - SD_CMD_INDEX(56) | SD_RESP_R1 | SD_CMD_ISDATA, - SD_CMD_RESERVED(57), - SD_CMD_RESERVED(58), - SD_CMD_RESERVED(59), - SD_CMD_RESERVED(60), - SD_CMD_RESERVED(61), - SD_CMD_RESERVED(62), - SD_CMD_RESERVED(63) -}; - -static inline rt_uint32_t read32(size_t addr) -{ - return (*((volatile unsigned int*)(addr))); -} - -static inline void write32(size_t addr, rt_uint32_t value) -{ - (*((volatile unsigned int*)(addr))) = value; -} - -rt_err_t sd_int(struct sdhci_pdata_t * pdat, rt_uint32_t mask) -{ - rt_uint32_t r; - rt_uint32_t m = mask | INT_ERROR_MASK; - int cnt = 1000000; - while (!(read32(pdat->virt + EMMC_INTERRUPT) & (m | INT_ERROR_MASK)) && cnt--) - DELAY_MICROS(1); - r = read32(pdat->virt + EMMC_INTERRUPT); - if (cnt <= 0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT)) - { - write32(pdat->virt + EMMC_INTERRUPT, r); - //qemu maybe can not use sdcard - rt_kprintf("send cmd/data timeout wait for %x int: %x, status: %x\n",mask, r, read32(pdat->virt + EMMC_STATUS)); - return -RT_ETIMEOUT; - } - else if (r & INT_ERROR_MASK) - { - write32(pdat->virt + EMMC_INTERRUPT, r); - rt_kprintf("send cmd/data error %x -> %x\n",r, read32(pdat->virt + EMMC_INTERRUPT)); - return -RT_ERROR; - } - write32(pdat->virt + EMMC_INTERRUPT, mask); - return RT_EOK; -} - -rt_err_t sd_status(struct sdhci_pdata_t * pdat, unsigned int mask) -{ - int cnt = 500000; - while ((read32(pdat->virt + EMMC_STATUS) & mask) && !(read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) && cnt--) - DELAY_MICROS(1); - if (cnt <= 0) - { - return -RT_ETIMEOUT; - } - else if (read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) - { - return -RT_ERROR; - } - - return RT_EOK; -} - -static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd) -{ - rt_uint32_t cmdidx; - rt_err_t ret = RT_EOK; - ret = sd_status(pdat, SR_CMD_INHIBIT); - if (ret) - { - rt_kprintf("ERROR: EMMC busy %d\n", ret); - return ret; - } - - cmdidx = sdCommandTable[cmd->cmdidx]; - if (cmdidx == 0xFFFFFFFF) - return -RT_EINVAL; - if (cmd->datarw == DATA_READ) - cmdidx |= SD_DATA_READ; - if (cmd->datarw == DATA_WRITE) - cmdidx |= SD_DATA_WRITE; - mmcsd_dbg("transfer cmd %x(%d) %x %x\n", cmdidx, cmd->cmdidx, cmd->cmdarg, read32(pdat->virt + EMMC_INTERRUPT)); - write32(pdat->virt + EMMC_INTERRUPT,read32(pdat->virt + EMMC_INTERRUPT)); - write32(pdat->virt + EMMC_ARG1, cmd->cmdarg); - write32(pdat->virt + EMMC_CMDTM, cmdidx); - if (cmd->cmdidx == SD_APP_OP_COND) - DELAY_MICROS(1000); - else if ((cmd->cmdidx == SD_SEND_IF_COND) || (cmd->cmdidx == APP_CMD)) - DELAY_MICROS(100); - - ret = sd_int(pdat, INT_CMD_DONE); - if (ret) - { - return ret; - } - if (cmd->resptype & RESP_MASK) - { - - if (cmd->resptype & RESP_R2) - { - rt_uint32_t resp[4]; - resp[0] = read32(pdat->virt + EMMC_RESP0); - resp[1] = read32(pdat->virt + EMMC_RESP1); - resp[2] = read32(pdat->virt + EMMC_RESP2); - resp[3] = read32(pdat->virt + EMMC_RESP3); - if (cmd->resptype == RESP_R2) - { - cmd->response[0] = resp[3]<<8 |((resp[2]>>24)&0xff); - cmd->response[1] = resp[2]<<8 |((resp[1]>>24)&0xff); - cmd->response[2] = resp[1]<<8 |((resp[0]>>24)&0xff); - cmd->response[3] = resp[0]<<8 ; - } - else - { - cmd->response[0] = resp[0]; - cmd->response[1] = resp[1]; - cmd->response[2] = resp[2]; - cmd->response[3] = resp[3]; - } - } - else - cmd->response[0] = read32(pdat->virt + EMMC_RESP0); - } - mmcsd_dbg("response: %x: %x %x %x %x (%x, %x)\n", cmd->resptype, cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], read32(pdat->virt + EMMC_STATUS),read32(pdat->virt + EMMC_INTERRUPT)); - return ret; -} - -static rt_err_t read_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) -{ - int c = 0; - rt_err_t ret; - int d; - while (c < blkcount) - { - if ((ret = sd_int(pdat, INT_READ_RDY))) - { - rt_kprintf("timeout happens when reading block %d\n",c); - return ret; - } - for (d=0; d < blksize / 4; d++) - if (read32(pdat->virt + EMMC_STATUS) & SR_READ_AVAILABLE) - buf[d] = read32(pdat->virt + EMMC_DATA); - c++; - buf += blksize / 4; - } - return RT_EOK; -} - -static rt_err_t write_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) -{ - int c = 0; - rt_err_t ret; - int d; - while (c < blkcount) - { - if ((ret = sd_int(pdat, INT_WRITE_RDY))) - { - return ret; - } - for (d=0; d < blksize / 4; d++) - write32(pdat->virt + EMMC_DATA, buf[d]); - c++; - buf += blksize / 4; - } - - if ((ret = sd_int(pdat, INT_DATA_DONE))) - { - return ret; - } - return RT_EOK; -} - -static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) -{ - rt_uint32_t dlen = (rt_uint32_t)(dat->blkcnt * dat->blksz); - rt_err_t ret = sd_status(pdat, SR_DAT_INHIBIT); - if (ret) - { - rt_kprintf("ERROR: EMMC busy\n"); - return ret; - } - if (dat->blkcnt > 1) - { - struct sdhci_cmd_t newcmd; - newcmd.cmdidx = SET_BLOCK_COUNT; - newcmd.cmdarg = dat->blkcnt; - newcmd.resptype = RESP_R1; - ret = raspi_transfer_command(pdat, &newcmd); - if (ret) return ret; - } - - if(dlen < 512) - { - write32(pdat->virt + EMMC_BLKSIZECNT, dlen | 1 << 16); - } - else - { - write32(pdat->virt + EMMC_BLKSIZECNT, 512 | (dat->blkcnt) << 16); - } - if (dat->flag & DATA_DIR_READ) - { - cmd->datarw = DATA_READ; - ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("read_block %d, %d\n", dat->blkcnt, dat->blksz ); - ret = read_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); - } - else if (dat->flag & DATA_DIR_WRITE) - { - cmd->datarw = DATA_WRITE; - ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("write_block %d, %d", dat->blkcnt, dat->blksz ); - ret = write_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); - } - return ret; -} - -static rt_err_t sdhci_transfer(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) -{ - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; - if (!dat) - return raspi_transfer_command(pdat, cmd); - - return raspi_transfer_data(pdat, cmd, dat); -} - -static void mmc_request_send(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req) -{ - struct sdhci_t *sdhci = (struct sdhci_t *)host->private_data; - struct sdhci_cmd_t cmd; - struct sdhci_cmd_t stop; - struct sdhci_data_t dat; - rt_memset(&cmd, 0, sizeof(struct sdhci_cmd_t)); - rt_memset(&stop, 0, sizeof(struct sdhci_cmd_t)); - rt_memset(&dat, 0, sizeof(struct sdhci_data_t)); - - cmd.cmdidx = req->cmd->cmd_code; - cmd.cmdarg = req->cmd->arg; - cmd.resptype =resp_type(req->cmd); - if (req->data) - { - dat.buf = (rt_uint8_t *)req->data->buf; - dat.flag = req->data->flags; - dat.blksz = req->data->blksize; - dat.blkcnt = req->data->blks; - - req->cmd->err = sdhci_transfer(sdhci, &cmd, &dat); - } - else - { - req->cmd->err = sdhci_transfer(sdhci, &cmd, RT_NULL); - } - - req->cmd->resp[3] = cmd.response[3]; - req->cmd->resp[2] = cmd.response[2]; - req->cmd->resp[1] = cmd.response[1]; - req->cmd->resp[0] = cmd.response[0]; - - if (req->stop) - { - stop.cmdidx = req->stop->cmd_code; - stop.cmdarg = req->stop->arg; - cmd.resptype =resp_type(req->stop); - req->stop->err = sdhci_transfer(sdhci, &stop, RT_NULL); - } - - mmcsd_req_complete(host); -} - -rt_int32_t mmc_card_status(struct rt_mmcsd_host *host) -{ - return 0; -} - -static rt_err_t sdhci_detect(struct sdhci_t * sdhci) -{ - return RT_EOK; -} - -static rt_err_t sdhci_setwidth(struct sdhci_t * sdhci, rt_uint32_t width) -{ - rt_uint32_t temp = 0; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; - if (width == MMCSD_BUS_WIDTH_4) - { - temp = read32((pdat->virt + EMMC_CONTROL0)); - temp |= C0_HCTL_HS_EN; - temp |= C0_HCTL_DWITDH; // always use 4 data lines: - write32((pdat->virt + EMMC_CONTROL0), temp); - } - return RT_EOK; -} - - -static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer ,rt_uint32_t base_clock, rt_uint32_t target_rate) -{ - rt_uint32_t targetted_divisor = 0; - rt_uint32_t freq_select = 0; - rt_uint32_t upper_bits = 0; - rt_uint32_t ret = 0; - - if(target_rate > base_clock) - targetted_divisor = 1; - else - { - targetted_divisor = base_clock / target_rate; - rt_uint32_t mod = base_clock % target_rate; - if(mod) - targetted_divisor--; - } - - // Decide on the clock mode to use - - // Currently only 10-bit divided clock mode is supported - - // HCI version 3 or greater supports 10-bit divided clock mode - // This requires a power-of-two divider - - // Find the first bit set - int divisor = -1; - for(int first_bit = 31; first_bit >= 0; first_bit--) - { - rt_uint32_t bit_test = (1 << first_bit); - if(targetted_divisor & bit_test) - { - divisor = first_bit; - targetted_divisor &= ~bit_test; - if(targetted_divisor) - { - // The divisor is not a power-of-two, increase it - divisor++; - } - break; - } - } - - if(divisor == -1) - divisor = 31; - if(divisor >= 32) - divisor = 31; - - if(divisor != 0) - divisor = (1 << (divisor - 1)); - - if(divisor >= 0x400) - divisor = 0x3ff; - - freq_select = divisor & 0xff; - upper_bits = (divisor >> 8) & 0x3; - ret = (freq_select << 8) | (upper_bits << 6) | (0 << 5); - - return ret; -} - -static rt_err_t sdhci_setclock(struct sdhci_t * sdhci, rt_uint32_t clock) -{ - rt_uint32_t temp = 0; - rt_uint32_t sdHostVer = 0; - int count = 100000; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)(sdhci->priv); - - while ((read32(pdat->virt + EMMC_STATUS) & (SR_CMD_INHIBIT | SR_DAT_INHIBIT)) && (--count)) - DELAY_MICROS(1); - if (count <= 0) - { - rt_kprintf("EMMC: Set clock: timeout waiting for inhibit flags. Status %08x.\n",read32(pdat->virt + EMMC_STATUS)); - return -RT_ERROR; - } - - // Switch clock off. - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp &= ~C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - // Request the new clock setting and enable the clock - temp = read32(pdat->virt + EMMC_SLOTISR_VER); - sdHostVer = (temp & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; - int cdiv = sd_get_clock_divider(sdHostVer, mmc_base_clock, clock); - temp = read32((pdat->virt + EMMC_CONTROL1)); - temp |= 1; - temp |= cdiv; - temp |= (7 << 16); - - temp = (temp & 0xffff003f) | cdiv; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - - // Enable the clock. - temp = read32(pdat->virt + EMMC_CONTROL1); - temp |= C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); - DELAY_MICROS(10); - - // Wait for clock to be stable. - count = 10000; - while (!(read32(pdat->virt + EMMC_CONTROL1) & C1_CLK_STABLE) && count--) - DELAY_MICROS(10); - if (count <= 0) - { - rt_kprintf("EMMC: ERROR: failed to get stable clock %d.\n", clock); - return -RT_ERROR; - } - - mmcsd_dbg("set stable clock %d.\n", clock); - return RT_EOK; -} - -static void mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg) -{ - struct sdhci_t * sdhci = (struct sdhci_t *)host->private_data; - sdhci_setclock(sdhci, io_cfg->clock); - sdhci_setwidth(sdhci, io_cfg->bus_width); -} - -static const struct rt_mmcsd_host_ops ops = -{ - mmc_request_send, - mmc_set_iocfg, - RT_NULL, - RT_NULL, -}; - -static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) -{ - rt_uint32_t control1; - - //Reset the controller - control1 = read32((pdat->virt + EMMC_CONTROL1)); - control1 |= (1 << 24); - // Disable clock - control1 &= ~(1 << 2); - control1 &= ~(1 << 0); - //temp |= C1_CLK_INTLEN | C1_TOUNIT_MAX; - write32((pdat->virt + EMMC_CONTROL1),control1); - int cnt = 10000; - do - { - DELAY_MICROS(10); - cnt = cnt - 1; - if(cnt == 0) - { - break; - } - } while ((read32(pdat->virt + EMMC_CONTROL1) & (0x7 << 24)) != 0); - - // Enable SD Bus Power VDD1 at 3.3V - rt_uint32_t control0 = read32(pdat->virt + EMMC_CONTROL0); - control0 |= 0x0F << 8; - write32(pdat->virt + EMMC_CONTROL0, control0); - - rt_thread_delay(100); - //usleep(2000); - - - // Check for a valid card - mmcsd_dbg("EMMC: checking for an inserted card\n"); - cnt = 10000; - do - { - DELAY_MICROS(10); - cnt = cnt - 1; - if(cnt == 0) - { - break; - } - } while ((read32(pdat->virt + EMMC_STATUS) & (0x1 << 16)) == 0); - - rt_uint32_t status_reg = read32(pdat->virt + EMMC_STATUS); - - if((status_reg & (1 << 16)) == 0) - { - rt_kprintf("EMMC: no card inserted\n"); - return -1; - } - else - { - mmcsd_dbg("EMMC: status: %08x\n", status_reg); - } - - // Clear control2 - write32(pdat->virt + EMMC_CONTROL2, 0); - // Get the base clock rate //12 - mmc_base_clock = bcm271x_mbox_clock_get_rate(EMMC_CLK_ID); - if(mmc_base_clock == 0) - { - rt_kprintf("EMMC: assuming clock rate to be 100MHz\n"); - mmc_base_clock = 100000000; - } - mmcsd_dbg("EMMC: setting clock rate is %d\n", mmc_base_clock); - return RT_EOK; -} - -#ifdef RT_MMCSD_DBG -void dump_registers(struct sdhci_pdata_t * pdat) -{ - rt_kprintf("EMMC registers:"); - int i = EMMC_ARG2; - for (; i <= EMMC_CONTROL2; i += 4) - rt_kprintf("\t%x:%x\n", i, read32(pdat->virt + i)); - rt_kprintf("\t%x:%x\n", 0x50, read32(pdat->virt + 0x50)); - rt_kprintf("\t%x:%x\n", 0x70, read32(pdat->virt + 0x70)); - rt_kprintf("\t%x:%x\n", 0x74, read32(pdat->virt + 0x74)); - rt_kprintf("\t%x:%x\n", 0x80, read32(pdat->virt + 0x80)); - rt_kprintf("\t%x:%x\n", 0x84, read32(pdat->virt + 0x84)); - rt_kprintf("\t%x:%x\n", 0x88, read32(pdat->virt + 0x88)); - rt_kprintf("\t%x:%x\n", 0x8c, read32(pdat->virt + 0x8c)); - rt_kprintf("\t%x:%x\n", 0x90, read32(pdat->virt + 0x90)); - rt_kprintf("\t%x:%x\n", 0xf0, read32(pdat->virt + 0xf0)); - rt_kprintf("\t%x:%x\n", 0xfc, read32(pdat->virt + 0xfc)); -} -#endif - -int raspi_sdmmc_init(void) -{ - size_t virt; - struct rt_mmcsd_host * host = RT_NULL; - struct sdhci_pdata_t * pdat = RT_NULL; - struct sdhci_t * sdhci = RT_NULL; - -#ifdef BSP_USING_SDIO0 - host = mmcsd_alloc_host(); - if (!host) - { - rt_kprintf("alloc host failed"); - goto err; - } - sdhci = rt_malloc(sizeof(struct sdhci_t)); - if (!sdhci) - { - rt_kprintf("alloc sdhci failed"); - goto err; - } - rt_memset(sdhci, 0, sizeof(struct sdhci_t)); - - virt = mmc2_base_addr; - pdat = (struct sdhci_pdata_t *)rt_malloc(sizeof(struct sdhci_pdata_t)); - RT_ASSERT(pdat != RT_NULL); - - pdat->virt = virt; - reset_emmc(pdat); - sdhci->name = "sd0"; - sdhci->voltages = VDD_33_34; - sdhci->width = MMCSD_BUSWIDTH_4; - sdhci->clock = 1000 * 1000 * 1000; - sdhci->removeable = RT_TRUE; - - sdhci->detect = sdhci_detect; - sdhci->setwidth = sdhci_setwidth; - sdhci->setclock = sdhci_setclock; - sdhci->transfer = sdhci_transfer; - sdhci->priv = pdat; - host->ops = &ops; - host->freq_min = 400000; - host->freq_max = 50000000; - host->valid_ocr = VDD_32_33 | VDD_33_34; - host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ | MMCSD_BUSWIDTH_4; - host->max_seg_size = 2048; - host->max_dma_segs = 10; - host->max_blk_size = 512; - host->max_blk_count = 1; - - host->private_data = sdhci; - write32((pdat->virt + EMMC_IRPT_EN),0xffffffff); - write32((pdat->virt + EMMC_IRPT_MASK),0xffffffff); -#ifdef RT_MMCSD_DBG - dump_registers(pdat); -#endif - mmcsd_change(host); -#endif - return RT_EOK; -err: - if (host) rt_free(host); - if (sdhci) rt_free(sdhci); - - return -RT_EIO; -} - -INIT_DEVICE_EXPORT(raspi_sdmmc_init); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h deleted file mode 100644 index 6dc566fcac..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-27 bigmagic first version - */ - -#ifndef __DRV_SDIO_H__ -#define __DRV_SDIO_H__ - -#include -#include -#include - -#include "board.h" -#include "raspi4.h" - -/* Struct for Intrrrupt Information */ -#define SDXC_CmdDone BIT(0) -#define SDXC_DataDone BIT(1) -#define SDXC_BlockGap BIT(2) -#define SDXC_WriteRdy BIT(4) -#define SDXC_ReadRdy BIT(5) -#define SDXC_Card BIT(8) -#define SDXC_Retune BIT(12) -#define SDXC_BootAck BIT(13) -#define SDXC_EndBoot BIT(14) -#define SDXC_Err BIT(15) -#define SDXC_CTOErr BIT(16) -#define SDXC_CCRCErr BIT(17) -#define SDXC_CENDErr BIT(18) -#define SDXC_CBADErr BIT(19) -#define SDXC_DTOErr BIT(20) -#define SDXC_DCRCErr BIT(21) -#define SDXC_DENDErr BIT(22) -#define SDXC_ACMDErr BIT(24) - -#define SDXC_BLKCNT_EN BIT(1) -#define SDXC_AUTO_CMD12_EN BIT(2) -#define SDXC_AUTO_CMD23_EN BIT(3) -#define SDXC_DAT_DIR BIT(4) //from card to host -#define SDXC_MULTI_BLOCK BIT(5) -#define SDXC_CMD_RSPNS_136 BIT(16) -#define SDXC_CMD_RSPNS_48 BIT(17) -#define SDXC_CMD_RSPNS_48busy BIT(16)|BIT(17) -#define SDXC_CHECK_CRC_CMD BIT(19) -#define SDXC_CMD_IXCHK_EN BIT(20) -#define SDXC_CMD_ISDATA BIT(21) -#define SDXC_CMD_SUSPEND BIT(22) -#define SDXC_CMD_RESUME BIT(23) -#define SDXC_CMD_ABORT BIT(23)|BIT(22) - -#define SDXC_CMD_INHIBIT BIT(0) -#define SDXC_DAT_INHIBIT BIT(1) -#define SDXC_DAT_ACTIVE BIT(2) -#define SDXC_WRITE_TRANSFER BIT(8) -#define SDXC_READ_TRANSFER BIT(9) - -struct sdhci_cmd_t -{ - rt_uint32_t cmdidx; - rt_uint32_t cmdarg; - rt_uint32_t resptype; - rt_uint32_t datarw; -#define DATA_READ 1 -#define DATA_WRITE 2 - rt_uint32_t response[4]; -}; - -struct sdhci_data_t -{ - rt_uint8_t * buf; - rt_uint32_t flag; - rt_uint32_t blksz; - rt_uint32_t blkcnt; -}; - -struct sdhci_t -{ - char * name; - rt_uint32_t voltages; - rt_uint32_t width; - rt_uint32_t clock; - rt_err_t removeable; - void * sdcard; - - rt_err_t (*detect)(struct sdhci_t * sdhci); - rt_err_t (*setwidth)(struct sdhci_t * sdhci, rt_uint32_t width); - rt_err_t (*setclock)(struct sdhci_t * sdhci, rt_uint32_t clock); - rt_err_t (*transfer)(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat); - void * priv; -}; - -struct sdhci_pdata_t -{ - size_t virt; -}; - -// EMMC command flags -#define CMD_TYPE_NORMAL (0x00000000) -#define CMD_TYPE_SUSPEND (0x00400000) -#define CMD_TYPE_RESUME (0x00800000) -#define CMD_TYPE_ABORT (0x00c00000) -#define CMD_IS_DATA (0x00200000) -#define CMD_IXCHK_EN (0x00100000) -#define CMD_CRCCHK_EN (0x00080000) -#define CMD_RSPNS_NO (0x00000000) -#define CMD_RSPNS_136 (0x00010000) -#define CMD_RSPNS_48 (0x00020000) -#define CMD_RSPNS_48B (0x00030000) -#define TM_MULTI_BLOCK (0x00000020) -#define TM_DAT_DIR_HC (0x00000000) -#define TM_DAT_DIR_CH (0x00000010) -#define TM_AUTO_CMD23 (0x00000008) -#define TM_AUTO_CMD12 (0x00000004) -#define TM_BLKCNT_EN (0x00000002) -#define TM_MULTI_DATA (CMD_IS_DATA|TM_MULTI_BLOCK|TM_BLKCNT_EN) - -#define RCA_NO (1) -#define RCA_YES (2) - -// INTERRUPT register settings -#define INT_AUTO_ERROR (0x01000000) -#define INT_DATA_END_ERR (0x00400000) -#define INT_DATA_CRC_ERR (0x00200000) -#define INT_DATA_TIMEOUT (0x00100000) -#define INT_INDEX_ERROR (0x00080000) -#define INT_END_ERROR (0x00040000) -#define INT_CRC_ERROR (0x00020000) -#define INT_CMD_TIMEOUT (0x00010000) -#define INT_ERR (0x00008000) -#define INT_ENDBOOT (0x00004000) -#define INT_BOOTACK (0x00002000) -#define INT_RETUNE (0x00001000) -#define INT_CARD (0x00000100) -#define INT_READ_RDY (0x00000020) -#define INT_WRITE_RDY (0x00000010) -#define INT_BLOCK_GAP (0x00000004) -#define INT_DATA_DONE (0x00000002) -#define INT_CMD_DONE (0x00000001) -#define INT_ERROR_MASK (INT_CRC_ERROR|INT_END_ERROR|INT_INDEX_ERROR| \ - INT_DATA_TIMEOUT|INT_DATA_CRC_ERR|INT_DATA_END_ERR| \ - INT_ERR|INT_AUTO_ERROR) -#define INT_ALL_MASK (INT_CMD_DONE|INT_DATA_DONE|INT_READ_RDY|INT_WRITE_RDY|INT_ERROR_MASK) - -#define EMMC_ARG2 (0x00) -#define EMMC_BLKSIZECNT (0x04) -#define EMMC_ARG1 (0x08) -#define EMMC_CMDTM (0x0c) -#define EMMC_RESP0 (0x10) -#define EMMC_RESP1 (0x14) -#define EMMC_RESP2 (0x18) -#define EMMC_RESP3 (0x1c) -#define EMMC_DATA (0x20) -#define EMMC_STATUS (0x24) -#define EMMC_CONTROL0 (0x28) -#define EMMC_CONTROL1 (0x2c) -#define EMMC_INTERRUPT (0x30) -#define EMMC_IRPT_MASK (0x34) -#define EMMC_IRPT_EN (0x38) -#define EMMC_CONTROL2 (0x3c) -#define EMMC_CAPABILITIES_0 (0x40) -#define EMMC_CAPABILITIES_1 (0x44) -#define EMMC_BOOT_TIMEOUT (0x70) -#define EMMC_EXRDFIFO_EN (0x84) -#define EMMC_SPI_INT_SPT (0xf0) -#define EMMC_SLOTISR_VER (0xfc) - -// CONTROL register settings -#define C0_SPI_MODE_EN (0x00100000) -#define C0_HCTL_HS_EN (0x00000004) -#define C0_HCTL_DWITDH (0x00000002) - -#define C1_SRST_DATA (0x04000000) -#define C1_SRST_CMD (0x02000000) -#define C1_SRST_HC (0x01000000) -#define C1_TOUNIT_DIS (0x000f0000) -#define C1_TOUNIT_MAX (0x000e0000) -#define C1_CLK_GENSEL (0x00000020) -#define C1_CLK_EN (0x00000004) -#define C1_CLK_STABLE (0x00000002) -#define C1_CLK_INTLEN (0x00000001) - -#define FREQ_SETUP (400000) // 400 Khz -#define FREQ_NORMAL (25000000) // 25 Mhz - -// SLOTISR_VER values -#define HOST_SPEC_NUM 0x00ff0000 -#define HOST_SPEC_NUM_SHIFT 16 -#define HOST_SPEC_V3 2 -#define HOST_SPEC_V2 1 -#define HOST_SPEC_V1 0 - -// STATUS register settings -#define SR_DAT_LEVEL1 (0x1e000000) -#define SR_CMD_LEVEL (0x01000000) -#define SR_DAT_LEVEL0 (0x00f00000) -#define SR_DAT3 (0x00800000) -#define SR_DAT2 (0x00400000) -#define SR_DAT1 (0x00200000) -#define SR_DAT0 (0x00100000) -#define SR_WRITE_PROT (0x00080000) // From SDHC spec v2, BCM says reserved -#define SR_READ_AVAILABLE (0x00000800) // ???? undocumented -#define SR_WRITE_AVAILABLE (0x00000400) // ???? undocumented -#define SR_READ_TRANSFER (0x00000200) -#define SR_WRITE_TRANSFER (0x00000100) -#define SR_DAT_ACTIVE (0x00000004) -#define SR_DAT_INHIBIT (0x00000002) -#define SR_CMD_INHIBIT (0x00000001) - -#define CONFIG_MMC_USE_DMA -#define DMA_ALIGN (32U) - -#define SD_CMD_INDEX(a) ((a) << 24) -#define SD_CMD_RESERVED(a) (0xffffffff) -#define SD_CMD_INDEX(a) ((a) << 24) -#define SD_CMD_TYPE_NORMAL (0x0) -#define SD_CMD_TYPE_SUSPEND (1 << 22) -#define SD_CMD_TYPE_RESUME (2 << 22) -#define SD_CMD_TYPE_ABORT (3 << 22) -#define SD_CMD_TYPE_MASK (3 << 22) -#define SD_CMD_ISDATA (1 << 21) -#define SD_CMD_IXCHK_EN (1 << 20) -#define SD_CMD_CRCCHK_EN (1 << 19) -#define SD_CMD_RSPNS_TYPE_NONE (0) // For no response -#define SD_CMD_RSPNS_TYPE_136 (1 << 16) // For response R2 (with CRC), R3,4 (no CRC) -#define SD_CMD_RSPNS_TYPE_48 (2 << 16) // For responses R1, R5, R6, R7 (with CRC) -#define SD_CMD_RSPNS_TYPE_48B (3 << 16) // For responses R1b, R5b (with CRC) -#define SD_CMD_RSPNS_TYPE_MASK (3 << 16) -#define SD_CMD_MULTI_BLOCK (1 << 5) -#define SD_CMD_DAT_DIR_HC (0) -#define SD_CMD_DAT_DIR_CH (1 << 4) -#define SD_CMD_AUTO_CMD_EN_NONE (0) -#define SD_CMD_AUTO_CMD_EN_CMD12 (1 << 2) -#define SD_CMD_AUTO_CMD_EN_CMD23 (2 << 2) -#define SD_CMD_BLKCNT_EN (1 << 1) -#define SD_CMD_DMA (1) -#define SD_RESP_NONE SD_CMD_RSPNS_TYPE_NONE -#define SD_RESP_R1 (SD_CMD_RSPNS_TYPE_48) // | SD_CMD_CRCCHK_EN) -#define SD_RESP_R1b (SD_CMD_RSPNS_TYPE_48B) // | SD_CMD_CRCCHK_EN) -#define SD_RESP_R2 (SD_CMD_RSPNS_TYPE_136) // | SD_CMD_CRCCHK_EN) -#define SD_RESP_R3 SD_CMD_RSPNS_TYPE_48 -#define SD_RESP_R4 SD_CMD_RSPNS_TYPE_136 -#define SD_RESP_R5 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_RESP_R5b (SD_CMD_RSPNS_TYPE_48B | SD_CMD_CRCCHK_EN) -#define SD_RESP_R6 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_RESP_R7 (SD_CMD_RSPNS_TYPE_48 | SD_CMD_CRCCHK_EN) -#define SD_DATA_READ (SD_CMD_ISDATA | SD_CMD_DAT_DIR_CH) -#define SD_DATA_WRITE (SD_CMD_ISDATA | SD_CMD_DAT_DIR_HC) -#endif diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.c deleted file mode 100644 index 5f9921958b..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-06-22 bigmagic first version - */ -#include -#include -#include - -#include "raspi4.h" -#include "drv_spi.h" - -#ifdef BSP_USING_SPI - -#define RPI_CORE_CLK_HZ (250000000) -#define BSP_SPI_MAX_HZ (30* 1000 *1000) -#define SPITIMEOUT 0x0FFF - -static rt_uint8_t raspi_byte_reverse_table[] = -{ - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -#if defined (BSP_USING_SPI0_BUS) -#define SPI0_BUS_NAME "spi0" -#define SPI0_DEVICE0_NAME "spi0.0" -#define SPI0_DEVICE1_NAME "spi0.1" - -struct rt_spi_bus spi0_bus; - -#if defined (BSP_USING_SPI0_DEVICE0) -static struct rt_spi_device spi0_device0; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) -static struct rt_spi_device spi0_device1; -#endif -#endif - -static rt_err_t raspi_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg) -{ - RT_ASSERT(cfg != RT_NULL); - RT_ASSERT(device != RT_NULL); - rt_uint16_t divider; - struct raspi_spi_device* hw_config = (struct raspi_spi_device *)(device->parent.user_data); - struct raspi_spi_hw_config *hwcfg = (struct raspi_spi_hw_config *)hw_config->spi_hw_config; - // spi clear fifo - SPI_REG_CS(hwcfg->hw_base) = (SPI_CS_CLEAR_TX | SPI_CS_CLEAR_RX); - if(cfg->mode & RT_SPI_CPOL) - { - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_CPOL; - } - - if(cfg->mode & RT_SPI_CPHA) - { - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_CPHA; - } - - if(cfg->mode & RT_SPI_CS_HIGH) - { - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_CSPOL_HIGH; - } - - //set clk - if (cfg->max_hz > BSP_SPI_MAX_HZ) - cfg->max_hz = BSP_SPI_MAX_HZ; - - divider = (rt_uint16_t) ((rt_uint32_t) RPI_CORE_CLK_HZ / cfg->max_hz); - divider &= 0xFFFE; - - SPI_REG_CLK(hwcfg->hw_base) = divider; - - return RT_EOK; -} - -rt_uint8_t correct_order(rt_uint8_t b, rt_uint8_t flag) -{ - if (flag) - return raspi_byte_reverse_table[b];//reverse - else - return b; -} - -static rt_err_t spi_transfernb(struct raspi_spi_hw_config *hwcfg, rt_uint8_t* tbuf, rt_uint8_t* rbuf, rt_uint32_t len, rt_uint8_t flag) -{ - rt_uint32_t TXCnt=0; - rt_uint32_t RXCnt=0; - - /* Clear TX and RX fifos */ - SPI_REG_CS(hwcfg->hw_base) |= (SPI_CS_CLEAR_TX | SPI_CS_CLEAR_RX); - - /* Set TA = 1 */ - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_TA; - - /* Use the FIFO's to reduce the interbyte times */ - while ((TXCnt < len) || (RXCnt < len)) - { - /* TX fifo not full, so add some more bytes */ - while (((SPI_REG_CS(hwcfg->hw_base) & SPI_CS_TX_DATA)) && (TXCnt < len)) - { - SPI_REG_FIFO(hwcfg->hw_base) = correct_order(tbuf[TXCnt],flag); - TXCnt++; - } - /* Rx fifo not empty, so get the next received bytes */ - while (((SPI_REG_CS(hwcfg->hw_base) & SPI_CS_RX_DATA)) && (RXCnt < len)) - { - rbuf[RXCnt] = correct_order(SPI_REG_FIFO(hwcfg->hw_base), flag); - RXCnt++; - } - } - /* Wait for DONE to be set */ - while (!(SPI_REG_CS(hwcfg->hw_base) & SPI_CS_DONE)); - /* Set TA = 0, and also set the barrier */ - SPI_REG_CS(hwcfg->hw_base) |= (0 & SPI_CS_TA); - - return RT_EOK; -} - -static rt_uint32_t raspi_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message) -{ - rt_err_t res; - rt_uint8_t flag; - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->bus != RT_NULL); - RT_ASSERT(device->parent.user_data != RT_NULL); - RT_ASSERT(message->send_buf != RT_NULL || message->recv_buf != RT_NULL); - - struct rt_spi_configuration config = device->config; - struct raspi_spi_device * hw_config = (struct raspi_spi_device *)device->parent.user_data; - GPIO_PIN cs_pin = (GPIO_PIN)hw_config->cs_pin; - struct raspi_spi_hw_config *hwcfg = (struct raspi_spi_hw_config *)hw_config->spi_hw_config; - - if (config.mode & RT_SPI_MSB) - { - flag = 0; - } - else - { - flag = 1; - } - - if (message->cs_take) - { - (config.mode & RT_SPI_CS_HIGH)?prev_raspi_pin_write(cs_pin, 1):prev_raspi_pin_write(cs_pin, 0); - } - - res = spi_transfernb(hwcfg, (rt_uint8_t *)message->send_buf, (rt_uint8_t *)message->recv_buf, (rt_int32_t)message->length, flag); - if (message->cs_release) - { - (config.mode & RT_SPI_CS_HIGH)?prev_raspi_pin_write(cs_pin, 0):prev_raspi_pin_write(cs_pin, 1); - } - if (res != RT_EOK) - return -RT_ERROR; - - return message->length; -} - -rt_err_t raspi_spi_bus_attach_device(const char *bus_name, struct raspi_spi_device *device) -{ - rt_err_t ret; - RT_ASSERT(device != RT_NULL); - ret = rt_spi_bus_attach_device(device->spi_device, device->device_name, bus_name, (void *)(device)); - return ret; -} - -rt_err_t raspi_spi_hw_init(struct raspi_spi_hw_config *hwcfg) -{ - prev_raspi_pin_mode(hwcfg->sclk_pin, hwcfg->sclk_mode); - prev_raspi_pin_mode(hwcfg->miso_pin, hwcfg->miso_mode); - prev_raspi_pin_mode(hwcfg->mosi_pin, hwcfg->mosi_mode); -#if defined (BSP_USING_SPI0_DEVICE0) - prev_raspi_pin_mode(hwcfg->ce0_pin, hwcfg->ce0_mode); -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - prev_raspi_pin_mode(hwcfg->ce1_pin, hwcfg->ce1_mode); -#endif - //clear rx and tx - SPI_REG_CS(hwcfg->hw_base) = (SPI_CS_CLEAR_TX | SPI_CS_CLEAR_RX); - //enable chip select -#if defined (BSP_USING_SPI0_DEVICE0) - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_CHIP_SELECT_0; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - SPI_REG_CS(hwcfg->hw_base) |= SPI_CS_CHIP_SELECT_1; -#endif - -#if defined (BSP_USING_SPI0_DEVICE0) && defined (BSP_USING_SPI0_DEVICE1) - HWREG32(SPI_REG_CS(hwcfg->hw_base)) |= (SPI_CS_CHIP_SELECT_0 | SPI_CS_CHIP_SELECT_1); -#endif - return RT_EOK; -} - -static struct rt_spi_ops raspi_spi_ops = -{ - .configure = raspi_spi_configure, - .xfer = raspi_spi_xfer -}; - -struct raspi_spi_hw_config raspi_spi0_hw = -{ - .spi_num = 0, - .sclk_pin = GPIO_PIN_11, - .sclk_mode = ALT0, - .mosi_pin = GPIO_PIN_10, - .mosi_mode = ALT0, - .miso_pin = GPIO_PIN_9, - .miso_mode = ALT0, - -#if defined (BSP_USING_SPI0_DEVICE0) - .ce0_pin = GPIO_PIN_8, - .ce0_mode = ALT0, -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - .ce1_pin = GPIO_PIN_7, - .ce1_mode = ALT0, -#endif - .hw_base = SPI_0_BASE, -}; -#endif - -#if defined (BSP_USING_SPI0_DEVICE0) -struct raspi_spi_device raspi_spi0_device0 = -{ - .device_name = SPI0_DEVICE0_NAME, - .spi_bus = &spi0_bus, - .spi_device = &spi0_device0, - .spi_hw_config = &raspi_spi0_hw, - .cs_pin = GPIO_PIN_8, -}; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) -struct raspi_spi_device raspi_spi0_device1 = -{ - .device_name = SPI0_DEVICE1_NAME, - .spi_bus = &spi0_bus, - .spi_device = &spi0_device1, - .cs_pin = GPIO_PIN_7, -}; -#endif - -int rt_hw_spi_init(void) -{ -#if defined (BSP_USING_SPI0_BUS) - raspi_spi_hw_init(&raspi_spi0_hw); - rt_spi_bus_register(&spi0_bus, SPI0_BUS_NAME, &raspi_spi_ops); - -#if defined (BSP_USING_SPI0_DEVICE0) - raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device0); -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) - raspi_spi_bus_attach_device(SPI0_BUS_NAME, &raspi_spi0_device1); -#endif -#endif - return RT_EOK; -} -INIT_DEVICE_EXPORT(rt_hw_spi_init); diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.h deleted file mode 100644 index 80876a43c6..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_spi.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-06-16 bigmagic first version - */ -#ifndef __DRV_SPI_H__ -#define __DRV_SPI_H__ - -#include "drv_gpio.h" - -#define SPI_REG_CS(BASE) HWREG32(BASE + 0x00) -#define SPI_REG_FIFO(BASE) HWREG32(BASE + 0x04) -#define SPI_REG_CLK(BASE) HWREG32(BASE + 0x08) -#define SPI_REG_DLEN(BASE) HWREG32(BASE + 0x0C) -#define SPI_REG_LTOH(BASE) HWREG32(BASE + 0x10) -#define SPI_REG_DC(BASE) HWREG32(BASE + 0x14) - -/* CS Register */ -#define SPI_CS_LOSSI_LONG_32BIT (1 << 25) -#define SPI_CS_LOSSI_DMA_MODE (1 << 24) -#define SPI_CS_CSPOL2 (1 << 23) -#define SPI_CS_CSPOL1 (1 << 22) -#define SPI_CS_CSPOL0 (1 << 21) -#define SPI_CS_RX_FIFO_FULL (1 << 20) -#define SPI_CS_RX_FIFO_3_QUARTER (1 << 19) -#define SPI_CS_TX_DATA (1 << 18) -#define SPI_CS_RX_DATA (1 << 17) -#define SPI_CS_DONE (1 << 16) -#define SPI_CS_LOSSI_EN (1 << 13) -#define SPI_CS_READ_EN (1 << 12) -#define SPI_CS_AUTO_CS (1 << 11) -#define SPI_CS_INTR_RXR (1 << 10) -#define SPI_CS_INTR_DONE (1 << 9) -#define SPI_CS_DMA_EN (1 << 8) -#define SPI_CS_TA (1 << 7) -#define SPI_CS_CSPOL_HIGH (1 << 6) -#define SPI_CS_CLEAR_RX (2 << 4) -#define SPI_CS_CLEAR_TX (1 << 4) -#define SPI_CS_CPOL (1 << 3) -#define SPI_CS_CPHA (1 << 2) -#define SPI_CS_CHIP_SELECT_2 (2 << 0) -#define SPI_CS_CHIP_SELECT_1 (1 << 0) -#define SPI_CS_CHIP_SELECT_0 (0 << 0) - -struct raspi_spi_hw_config -{ - rt_uint8_t spi_num; - GPIO_PIN sclk_pin; - GPIO_FUNC sclk_mode; - GPIO_PIN mosi_pin; - GPIO_FUNC mosi_mode; - GPIO_PIN miso_pin; - GPIO_FUNC miso_mode; -#if defined (BSP_USING_SPI0_DEVICE0) || defined (BSP_USING_SPI1_DEVICE0) - GPIO_PIN ce0_pin; - GPIO_FUNC ce0_mode; -#endif - -#if defined (BSP_USING_SPI0_DEVICE1) || defined (BSP_USING_SPI1_DEVICE1) - GPIO_PIN ce1_pin; - GPIO_FUNC ce1_mode; -#endif - -#if defined (BSP_USING_SPI1_DEVICE2) - GPIO_PIN ce2_pin; - GPIO_FUNC ce2_mode; -#endif - rt_ubase_t hw_base; - -}; - -struct raspi_spi_device -{ - char *device_name; - struct rt_spi_bus *spi_bus; - struct rt_spi_device *spi_device; - struct raspi_spi_hw_config *spi_hw_config; - GPIO_PIN cs_pin; -}; - -int rt_hw_spi_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.c deleted file mode 100644 index 5d4b07a9fb..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - * 2020-05-26 bigmagic add other uart - */ - -#include -#include -#include - -#include "board.h" -#include "drv_uart.h" -#include "drv_gpio.h" -#include - -size_t uart0_addr = 0; -size_t uart3_addr = 0; -size_t uart4_addr = 0; -size_t uart5_addr = 0; - -#ifdef RT_USING_UART0 -static struct rt_serial_device _serial0; -#endif - -#ifdef RT_USING_UART1 -static struct rt_serial_device _serial1; -#endif - -#ifdef RT_USING_UART3 -static struct rt_serial_device _serial3; -#endif - -#ifdef RT_USING_UART4 -static struct rt_serial_device _serial4; -#endif - -#ifdef RT_USING_UART5 -static struct rt_serial_device _serial5; -#endif - -struct hw_uart_device -{ - rt_ubase_t hw_base; - rt_uint32_t irqno; -}; - -static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) -{ - struct hw_uart_device *uart; - uint32_t bauddiv = (UART_REFERENCE_CLOCK / cfg->baud_rate)* 1000 / 16; - uint32_t ibrd = bauddiv / 1000; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - if(uart->hw_base == AUX_BASE) - { - prev_raspi_pin_mode(GPIO_PIN_14, ALT5); - prev_raspi_pin_mode(GPIO_PIN_15, ALT5); - - AUX_ENABLES(uart->hw_base) = 1; /* Enable UART1 */ - AUX_MU_IER_REG(uart->hw_base) = 0; /* Disable interrupt */ - AUX_MU_CNTL_REG(uart->hw_base) = 0; /* Disable Transmitter and Receiver */ - AUX_MU_LCR_REG(uart->hw_base) = 3; /* Works in 8-bit mode */ - AUX_MU_MCR_REG(uart->hw_base) = 0; /* Disable RTS */ - AUX_MU_IIR_REG(uart->hw_base) = 0xC6; /* Enable FIFO, Clear FIFO */ - AUX_MU_BAUD_REG(uart->hw_base) = 270; /* 115200 = system clock 250MHz / (8 * (baud + 1)), baud = 270 */ - AUX_MU_CNTL_REG(uart->hw_base) = 3; /* Enable Transmitter and Receiver */ - return RT_EOK; - } - - if(uart->hw_base == uart0_addr) - { - prev_raspi_pin_mode(GPIO_PIN_14, ALT0); - prev_raspi_pin_mode(GPIO_PIN_15, ALT0); - } - - if(uart->hw_base == uart3_addr) - { - prev_raspi_pin_mode(GPIO_PIN_4, ALT4); - prev_raspi_pin_mode(GPIO_PIN_5, ALT4); - } - - if(uart->hw_base == uart4_addr) - { - prev_raspi_pin_mode(GPIO_PIN_8, ALT4); - prev_raspi_pin_mode(GPIO_PIN_9, ALT4); - } - - if(uart->hw_base == uart5_addr) - { - prev_raspi_pin_mode(GPIO_PIN_12, ALT4); - prev_raspi_pin_mode(GPIO_PIN_13, ALT4); - } - - PL011_REG_CR(uart->hw_base) = 0;/*Clear UART setting*/ - PL011_REG_LCRH(uart->hw_base) = 0;/*disable FIFO*/ - PL011_REG_IBRD(uart->hw_base) = ibrd; - PL011_REG_FBRD(uart->hw_base) = (((bauddiv - ibrd * 1000) * 64 + 500) / 1000); - PL011_REG_LCRH(uart->hw_base) = PL011_LCRH_WLEN_8;/*FIFO*/ - PL011_REG_CR(uart->hw_base) = PL011_CR_UARTEN | PL011_CR_TXE | PL011_CR_RXE;/*art enable, TX/RX enable*/ - - return RT_EOK; -} - -static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - switch (cmd) - { - case RT_DEVICE_CTRL_CLR_INT: - break; - - case RT_DEVICE_CTRL_SET_INT: - /* enable rx irq */ - if(uart->hw_base == AUX_BASE) - { - AUX_MU_IER_REG(uart->hw_base) = 0x1; - } - else - { - PL011_REG_IMSC(uart->hw_base) |= PL011_IMSC_RXIM; - } - rt_hw_interrupt_umask(uart->irqno); - break; - } - return RT_EOK; -} - -static int uart_putc(struct rt_serial_device *serial, char c) -{ - struct hw_uart_device *uart; - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - if(uart->hw_base == AUX_BASE) - { - while (!(AUX_MU_LSR_REG(uart->hw_base) & 0x20)); - AUX_MU_IO_REG(uart->hw_base) = c; - } - else - { - while ((PL011_REG_FR(uart->hw_base) & PL011_FR_TXFF)); - PL011_REG_DR(uart->hw_base) = (uint8_t)c; - } - return 1; -} - -static int uart_getc(struct rt_serial_device *serial) -{ - int ch = -1; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - if(uart->hw_base == AUX_BASE) - { - if ((AUX_MU_LSR_REG(uart->hw_base) & 0x01)) - { - ch = AUX_MU_IO_REG(uart->hw_base) & 0xff; - } - } - else - { - if((PL011_REG_FR(uart->hw_base) & PL011_FR_RXFE) == 0) - { - ch = PL011_REG_DR(uart->hw_base) & 0xff; - } - } - - return ch; -} - -static const struct rt_uart_ops _uart_ops = -{ - uart_configure, - uart_control, - uart_putc, - uart_getc, -}; - -volatile void *earlycon_base = 0; -const size_t earlycon_size = 0x1000; - -extern void early_putc(int c) -{ - if (c == '\n') - { - early_putc('\r'); - } - while (!(AUX_MU_LSR_REG(earlycon_base) & 0x20)); - AUX_MU_IO_REG(earlycon_base) = c; -} - -void rt_hw_earlycon_ioremap_early(void) -{ - earlycon_base = rt_ioremap_early((void *)AUX_BASE, earlycon_size); -} - -void rt_hw_console_output(const char *str) -{ - if (earlycon_base) - { - while (*str) - { - early_putc(*str++); - } - } -} - -void early_printhex(rt_ubase_t number) -{ - char str[sizeof("0123456789abcdef")]; - - str[16] = 0; - - for (int i = 15; i >= 0; --i) - { - str[i] = "0123456789abcdef"[(number & 0xf)]; - - number >>= 4; - } - - rt_kputs(str); -} - -#ifdef RT_USING_UART1 -static void rt_hw_aux_uart_isr(int irqno, void *param) -{ - struct rt_serial_device *serial = (struct rt_serial_device*)param; - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); -} -#endif - -static void rt_hw_uart_isr(int irqno, void *param) -{ -#ifdef RT_USING_UART0 - if((PACTL_CS & IRQ_UART0) == IRQ_UART0) - { - PACTL_CS &= ~(IRQ_UART0); - rt_hw_serial_isr(&_serial0, RT_SERIAL_EVENT_RX_IND); - PL011_REG_ICR(uart0_addr) = PL011_INTERRUPT_RECEIVE; - } -#endif - -#ifdef RT_USING_UART3 - if((PACTL_CS & IRQ_UART3) == IRQ_UART3) - { - PACTL_CS &= ~(IRQ_UART3); - rt_hw_serial_isr(&_serial3, RT_SERIAL_EVENT_RX_IND); - PL011_REG_ICR(uart3_addr) = PL011_INTERRUPT_RECEIVE; - } -#endif - -#ifdef RT_USING_UART4 - if((PACTL_CS & IRQ_UART4) == IRQ_UART4) - { - PACTL_CS &= ~(IRQ_UART4); - rt_hw_serial_isr(&_serial4, RT_SERIAL_EVENT_RX_IND); - PL011_REG_ICR(uart4_addr) = PL011_INTERRUPT_RECEIVE; - } -#endif - -#ifdef RT_USING_UART5 - if((PACTL_CS & IRQ_UART5) == IRQ_UART5) - { - PACTL_CS &= ~(IRQ_UART5); - rt_hw_serial_isr(&_serial5, RT_SERIAL_EVENT_RX_IND); - PL011_REG_ICR(uart5_addr) = PL011_INTERRUPT_RECEIVE; - } -#endif -} - -#ifdef RT_USING_UART0 -/* UART device driver structure */ -static struct hw_uart_device _uart0_device = -{ - UART0_BASE, - IRQ_PL011, -}; -#endif - -#ifdef RT_USING_UART1 -/* UART device driver structure */ -static struct hw_uart_device _uart1_device = -{ - AUX_BASE, - IRQ_AUX_UART, -}; -#endif - -#ifdef RT_USING_UART3 -static struct hw_uart_device _uart3_device = -{ - UART3_BASE, - IRQ_PL011, -}; -#endif - -#ifdef RT_USING_UART4 -static struct hw_uart_device _uart4_device = -{ - UART4_BASE, - IRQ_PL011, -}; -#endif - -#ifdef RT_USING_UART5 -static struct hw_uart_device _uart5_device = -{ - UART5_BASE, - IRQ_PL011, -}; -#endif - -int rt_hw_uart_init(void) -{ - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; -#ifdef RT_USING_UART0 - struct hw_uart_device *uart0; - uart0 = &_uart0_device; - - _serial0.ops = &_uart_ops; - _serial0.config = config; - - uart0_addr = UART0_BASE; -#ifdef RT_USING_SMART - uart0_addr = (size_t)rt_ioremap((void*)UART0_BASE, 0x1000); -#endif - earlycon_base = (void *)uart0_addr; - uart0->hw_base = uart0_addr; - - - /* register UART0 device */ - rt_hw_serial_register(&_serial0, "uart0", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart0); - rt_hw_interrupt_install(uart0->irqno, rt_hw_uart_isr, &_serial0, "uart0"); - -#endif - -#ifdef RT_USING_UART1 - struct hw_uart_device *uart1; - uart1 = &_uart1_device; - - _serial1.ops = &_uart_ops; - _serial1.config = config; - - uart1->hw_base = (size_t)rt_ioremap((void*)AUX_BASE, 0x1000); - - /* register UART1 device */ - rt_hw_serial_register(&_serial1, "uart1", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart1); - rt_hw_interrupt_install(uart1->irqno, rt_hw_aux_uart_isr, &_serial1, "uart1"); -#endif - -#ifdef RT_USING_UART3 - struct hw_uart_device *uart3; - uart3 = &_uart3_device; - - _serial3.ops = &_uart_ops; - _serial3.config = config; - - uart3_addr = (size_t)rt_ioremap((void*)UART3_BASE, 0x1000); - uart3->hw_base = uart3_addr; - - /* register UART3 device */ - rt_hw_serial_register(&_serial3, "uart3", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart3); - rt_hw_interrupt_install(uart3->irqno, rt_hw_uart_isr, &_serial3, "uart3"); -#endif - -#ifdef RT_USING_UART4 - struct hw_uart_device *uart4; - uart4 = &_uart4_device; - - _serial4.ops = &_uart_ops; - _serial4.config = config; - - uart4_addr = (size_t)rt_ioremap((void*)UART4_BASE, 0x1000); - uart4->hw_base = uart4_addr; - - /* register UART4 device */ - rt_hw_serial_register(&_serial4, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart4); - rt_hw_interrupt_install(uart4->irqno, rt_hw_uart_isr, &_serial4, "uart4"); -#endif - -#ifdef RT_USING_UART5 - struct hw_uart_device *uart5; - uart5 = &_uart5_device; - - _serial5.ops = &_uart_ops; - _serial5.config = config; - - uart5_addr = (size_t)rt_ioremap((void*)UART5_BASE, 0x1000); - uart5->hw_base = uart5_addr; - - /* register UART5 device */ - rt_hw_serial_register(&_serial5, "uart5", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart5); - rt_hw_interrupt_install(uart5->irqno, rt_hw_uart_isr, &_serial5, "uart5"); -#endif - return 0; -} - diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.h deleted file mode 100644 index 4b2c565c31..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_uart.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-04-16 bigmagic first version - */ - -#ifndef DRV_UART_H__ -#define DRV_UART_H__ - -// register's bit -#define PL011_FR_RI (1 << 8) -#define PL011_FR_TXFE (1 << 7) -#define PL011_FR_RXFF (1 << 6) -#define PL011_FR_TXFF (1 << 5) -#define PL011_FR_RXFE (1 << 4) -#define PL011_FR_BUSY (1 << 3) -#define PL011_FR_DCD (1 << 2) -#define PL011_FR_DSR (1 << 1) -#define PL011_FR_CTS (1 << 0) - -#define PL011_LCRH_SPS (1 << 7) -#define PL011_LCRH_WLEN_8 (3 << 5) -#define PL011_LCRH_WLEN_7 (2 << 5) -#define PL011_LCRH_WLEN_6 (1 << 5) -#define PL011_LCRH_WLEN_5 (0 << 5) -#define PL011_LCRH_FEN (1 << 4) -#define PL011_LCRH_STP2 (1 << 3) -#define PL011_LCRH_EPS (1 << 2) -#define PL011_LCRH_PEN (1 << 1) -#define PL011_LCRH_BRK (1 << 0) - -#define PL011_CR_CTSEN (1 << 15) -#define PL011_CR_RTSEN (1 << 14) -#define PL011_CR_RTS (1 << 11) -#define PL011_CR_DTR (1 << 10) -#define PL011_CR_RXE (1 << 9) -#define PL011_CR_TXE (1 << 8) -#define PL011_CR_LBE (1 << 7) -#define PL011_CR_SIRLP (1 << 2) -#define PL011_CR_SIREN (1 << 1) -#define PL011_CR_UARTEN (1 << 0) - -#define PL011_IMSC_TXIM (1 << 5) -#define PL011_IMSC_RXIM (1 << 4) - -#define PL011_INTERRUPT_OVERRUN_ERROR (1 << 10) -#define PL011_INTERRUPT_BREAK_ERROR (1 << 9) -#define PL011_INTERRUPT_PARITY_ERROR (1 << 8) -#define PL011_INTERRUPT_FRAMING_ERROR (1 << 7) -#define PL011_INTERRUPT_RECEIVE_TIMEOUT (1 << 6) -#define PL011_INTERRUPT_TRANSMIT (1 << 5) -#define PL011_INTERRUPT_RECEIVE (1 << 4) -#define PL011_INTERRUPT_nUARTCTS (1 << 1) - -#define PL011_REG_DR(BASE) HWREG32(BASE + 0x00) -#define PL011_REG_RSRECR(BASE) HWREG32(BASE + 0x04) -#define PL011_REG_RESERVED0(BASE) HWREG32(BASE + 0x08) -#define PL011_REG_FR(BASE) HWREG32(BASE + 0x18) -#define PL011_REG_RESERVED1(BASE) HWREG32(BASE + 0x1C) -#define PL011_REG_ILPR(BASE) HWREG32(BASE + 0x20) -#define PL011_REG_IBRD(BASE) HWREG32(BASE + 0x24) -#define PL011_REG_FBRD(BASE) HWREG32(BASE + 0x28) -#define PL011_REG_LCRH(BASE) HWREG32(BASE + 0x2C) -#define PL011_REG_CR(BASE) HWREG32(BASE + 0x30) -#define PL011_REG_IFLS(BASE) HWREG32(BASE + 0x34) -#define PL011_REG_IMSC(BASE) HWREG32(BASE + 0x38) -#define PL011_REG_RIS(BASE) HWREG32(BASE + 0x3C) -#define PL011_REG_MIS(BASE) HWREG32(BASE + 0x40) -#define PL011_REG_ICR(BASE) HWREG32(BASE + 0x44) -#define PL011_REG_DMACR(BASE) HWREG32(BASE + 0x48) -#define PL011_REG_RESERVED2(BASE) HWREG32(BASE + 0x4C) -#define PL011_REG_ITCR(BASE) HWREG32(BASE + 0x80) -#define PL011_REG_ITIP(BASE) HWREG32(BASE + 0x84) -#define PL011_REG_ITOP(BASE) HWREG32(BASE + 0x88) -#define PL011_REG_TDR(BASE) HWREG32(BASE + 0x8C) - -/* - * Auxiliary - */ -#define AUX_IRQ(BASE) HWREG32(BASE + 0x00) /* Auxiliary Interrupt status 3 */ -#define AUX_ENABLES(BASE) HWREG32(BASE + 0x04) /* Auxiliary enables 3bit */ -#define AUX_MU_IO_REG(BASE) HWREG32(BASE + 0x40) /* Mini Uart I/O Data 8bit */ -#define AUX_MU_IER_REG(BASE) HWREG32(BASE + 0x44) /* Mini Uart Interrupt Enable 8bit */ -#define AUX_MU_IIR_REG(BASE) HWREG32(BASE + 0x48) /* Mini Uart Interrupt Identify 8bit */ -#define AUX_MU_LCR_REG(BASE) HWREG32(BASE + 0x4C) /* Mini Uart Line Control 8bit */ -#define AUX_MU_MCR_REG(BASE) HWREG32(BASE + 0x50) /* Mini Uart Modem Control 8bit */ -#define AUX_MU_LSR_REG(BASE) HWREG32(BASE + 0x54) /* Mini Uart Line Status 8bit */ -#define AUX_MU_MSR_REG(BASE) HWREG32(BASE + 0x58) /* Mini Uart Modem Status 8bit */ -#define AUX_MU_SCRATCH(BASE) HWREG32(BASE + 0x5C) /* Mini Uart Scratch 8bit */ -#define AUX_MU_CNTL_REG(BASE) HWREG32(BASE + 0x60) /* Mini Uart Extra Control 8bit */ -#define AUX_MU_STAT_REG(BASE) HWREG32(BASE + 0x64) /* Mini Uart Extra Status 32bit */ -#define AUX_MU_BAUD_REG(BASE) HWREG32(BASE + 0x68) /* Mini Uart Baudrate 16bit */ -#define AUX_SPI0_CNTL0_REG(BASE) HWREG32(BASE + 0x80) /* SPI 1 Control register 0 32bit */ -#define AUX_SPI0_CNTL1_REG(BASE) HWREG32(BASE + 0x84) /* SPI 1 Control register 1 8bit */ -#define AUX_SPI0_STAT_REG(BASE) HWREG32(BASE + 0x88) /* SPI 1 Status 32bit */ -#define AUX_SPI0_IO_REG(BASE) HWREG32(BASE + 0x90) /* SPI 1 Data 32bit */ -#define AUX_SPI0_PEEK_REG(BASE) HWREG32(BASE + 0x94) /* SPI 1 Peek 16bit */ -#define AUX_SPI1_CNTL0_REG(BASE) HWREG32(BASE + 0xC0) /* SPI 2 Control register 0 32bit */ -#define AUX_SPI1_CNTL1_REG(BASE) HWREG32(BASE + 0xC4) /* SPI 2 Control register 1 8bit */ - -int rt_hw_uart_init(void); -void rt_hw_earlycon_ioremap_early(void); - -#endif /* DRV_UART_H__ */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.c deleted file mode 100644 index ce7e8c2a6c..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2006-2020, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-26 bigmagic first version - */ -#include -#include "drv_wdt.h" -#include "raspi4.h" - -#ifdef BSP_USING_WDT - -#define SECS_TO_WDOG_TICKS(x) ((x) << 16) -#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) - -static struct raspi_wdt_driver bcm_wdt; - -void raspi_watchdog_init(rt_uint32_t time_init) -{ - bcm_wdt.timeout = time_init; -} - -void raspi_watchdog_start() -{ - volatile rt_uint32_t cur; - PM_WDOG = PM_PASSWORD | (SECS_TO_WDOG_TICKS(bcm_wdt.timeout) & PM_WDOG_TIME_SET); - cur = (PM_RSTC); - PM_RSTC = PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET; -} - -void raspi_watchdog_stop() -{ - PM_RSTC = PM_PASSWORD | PM_RSTC_RESET; -} - -void raspi_watchdog_clr() -{ - bcm_wdt.timeout = 0; -} - -void raspi_watchdog_set_timeout(rt_uint32_t timeout_us) -{ - bcm_wdt.timeout = timeout_us; -} - -rt_uint64_t raspi_watchdog_get_timeout() -{ - return bcm_wdt.timeout; -} - -rt_uint64_t raspi_watchdog_get_timeleft() -{ - rt_uint32_t ret = (PM_WDOG); - return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); -} - -static rt_err_t raspi_wdg_init(rt_watchdog_t *wdt) -{ - /*init for 10S*/ - raspi_watchdog_init(1000000); - raspi_watchdog_start(); - raspi_watchdog_stop(); - return RT_EOK; -} - -static rt_err_t raspi_wdg_control(rt_watchdog_t *wdt, int cmd, void *arg) -{ - rt_uint64_t timeout_us = 0; - switch (cmd) - { - case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: - timeout_us = *((rt_uint32_t *)arg) * 1000000; - if (timeout_us >= 0xFFFFFFFF) - timeout_us = 0xFFFFFFFF; - raspi_watchdog_set_timeout((rt_uint32_t)timeout_us); - break; - case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: - timeout_us = raspi_watchdog_get_timeout(); - *((rt_uint32_t *)arg) = timeout_us / 1000000; - break; - case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: - timeout_us = raspi_watchdog_get_timeleft(); - *((rt_uint32_t *)arg) = timeout_us / 1000000; - break; - case RT_DEVICE_CTRL_WDT_KEEPALIVE: - raspi_watchdog_clr(); - break; - case RT_DEVICE_CTRL_WDT_START: - raspi_watchdog_start(); - break; - case RT_DEVICE_CTRL_WDT_STOP: - raspi_watchdog_stop(); - break; - default: - return -RT_EIO; - } - return RT_EOK; -} - -static const struct rt_watchdog_ops raspi_wdg_pos = -{ - raspi_wdg_init, - raspi_wdg_control, -}; - -static rt_watchdog_t raspi_wdg; - -int rt_hw_wdt_init(void) -{ - raspi_wdg.ops = &raspi_wdg_pos; - rt_hw_watchdog_register(&raspi_wdg, "wdg", 0, RT_NULL); - return RT_EOK; -} -INIT_DEVICE_EXPORT(rt_hw_wdt_init); - -void rt_hw_cpu_reset(void) -{ - unsigned int r; - - rt_kprintf("reboot system...\n"); - rt_thread_mdelay(100); - r = PM_RSTS; - // trigger a restart by instructing the GPU to boot from partition 0 - r &= ~0xfffffaaa; - PM_RSTS |= (PM_PASSWORD | r); // boot from partition 0 - PM_WDOG |= (PM_PASSWORD | 0x0A); - PM_RSTC |= (PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET); - - while (1); -} -MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_reset, reboot, reboot system...); -#endif /*BSP_USING_WDT */ diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.h deleted file mode 100644 index 58c48d3d77..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_wdt.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-10-26 bigmagic first version - */ -#ifndef __DRV_WDT_H__ -#define __DRV_WDT_H__ - -#include -#include - -#include "board.h" - -struct raspi_wdt_driver -{ - rt_uint32_t timeout; -}; - -int rt_hw_wdt_init(void); - -#endif diff --git a/bsp/raspberry-pi/raspi4-64/drivers/mbox.c b/bsp/raspberry-pi/raspi4-64/drivers/mbox.c deleted file mode 100644 index 0bbbdd6665..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/mbox.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2019-08-29 zdzn first version - * 2020-09-10 bigmagic add other mbox option - */ - -/* mailbox message buffer */ -#include -#include "mbox.h" -#include "mmu.h" -//volatile unsigned int __attribute__((aligned(16))) mbox[36]; - -#define BUS_ADDRESS(phys) (((phys) & ~0xC0000000) | 0xC0000000) -volatile unsigned int *mbox; - -/** - * Make a mailbox call. Returns 0 on failure, non-zero on success - */ -int mbox_call(unsigned char ch, int mmu_enable) -{ - unsigned int r = ((((rt_uint32_t)MBOX_ADDR)&~0xF) | (ch&0xF)); - if(mmu_enable) - r = BUS_ADDRESS(r); - /* wait until we can write to the mailbox */ - do - { - asm volatile("nop"); - } while (*MBOX_STATUS & MBOX_FULL); - /* write the address of our message to the mailbox with channel identifier */ - *MBOX_WRITE = r; - /* now wait for the response */ - while(1) - { - /* is there a response? */ - do - { - asm volatile("nop"); - } while (*MBOX_STATUS & MBOX_EMPTY); - /* is it a response to our message? */ - if (r == *MBOX_READ){ - /* is it a valid successful response? */ - return mbox[1] == MBOX_RESPONSE; - } - } - return 0; -} - -int bcm271x_mbox_get_touch(void) -{ - mbox[0] = 8 * 4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_GET_TOUCHBUF; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - return (int)(mbox[5] & ~0xC0000000); -} - -int bcm271x_notify_reboot(void) -{ - mbox[0] = 7*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - mbox[2] = MBOX_TAG_NOTIFY_REBOOT; // (the tag id) - mbox[3] = 0x00000004; // length + 4 - mbox[4] = 0x00000000; // size of the data - mbox[5] = 0x00000000; // request - - mbox[6] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return 0; -} - -int bcm271x_notify_xhci_reset(void) -{ - mbox[0] = 7*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - mbox[2] = MBOX_TAG_NOTIFY_XHCI_RESET; // (the tag id) - mbox[3] = 0x00000004; // length + 4 - mbox[4] = 0x00000004; // size of the data - mbox[5] = 0x00100000; // request - mbox[6] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - return 0; -} - -int bcm271x_gpu_enable(void) -{ - mbox[0] = 12*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_RATE; - mbox[3] = 0x00000008; // (the tag id) - mbox[4] = 0x00000008; // (the tag id) - mbox[5] = 5; // V3D - mbox[6] = 250 * 1000 * 1000; - mbox[7] = MBOX_TAG_ENABLE_QPU; // (the tag id) - mbox[8] = 0x00000004; // (size of the buffer) - mbox[9] = 0x00000004; // (size of the data) - mbox[10] = 0x00000001; - mbox[11] = MBOX_TAG_LAST; // end tag - mbox_call(8, MMU_DISABLE); - return mbox[1]; -} - -int bcm271x_mbox_hardware_get_model(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_MODEL; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - return mbox[5]; -} - -int bcm271x_mbox_hardware_get_revison(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_REV; - mbox[3] = 4; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - return mbox[5]; -} - -int bcm271x_mbox_hardware_get_mac_address(uint8_t * mac) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_MAC_ADDRESS; - mbox[3] = 6; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - char * mac_str = (char *)&mbox[5]; - mac[0] = mac_str[0]; - mac[1] = mac_str[1]; - mac[2] = mac_str[2]; - mac[3] = mac_str[3]; - mac[4] = mac_str[4]; - mac[5] = mac_str[5]; - return 0; -} - - -int bcm271x_mbox_hardware_get_serial(rt_uint64_t* sn) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_SERIAL; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - *sn = *(rt_uint64_t *)&mbox[5]; - - return 0; -} - -int bcm271x_mbox_hardware_get_arm_memory(rt_uint32_t * base, rt_uint32_t * size) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_ARM_MEMORY; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - *base = mbox[5]; - *size = mbox[6]; - - return 0; - -} - -int bcm271x_mbox_hardware_get_vc_memory(rt_uint32_t * base, rt_uint32_t * size) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_HARDWARE_GET_VC_MEMORY; - mbox[3] = 8; // buffer size - mbox[4] = 0; // len - - mbox[5] = 0; - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - *base = mbox[5]; - *size = mbox[6]; - - return 0; -} - -int bcm271x_mbox_clock_get_turbo(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_TURBO; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; // id - mbox[6] = 0; // val - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_clock_set_turbo(int level) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_TURBO; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = 0; // id - mbox[6] = level ? 1 : 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_clock_get_state(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm271x_mbox_clock_set_state(int id, int state) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = state & 0x3; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm271x_mbox_clock_get_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_clock_set_rate(int id, int rate) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_SET_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = rate; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_clock_get_max_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_MAX_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_clock_get_min_rate(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_CLOCK_GET_MIN_RATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_power_get_state(int id) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_POWER_GET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = id; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm271x_mbox_power_set_state(int id, int state) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_POWER_SET_STATE; - mbox[3] = 8; // buffer size - mbox[4] = 8; // len - - mbox[5] = id; // id - mbox[6] = state & 0x3; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != id) - { - return -1; - } - - return (mbox[6] & 0x3); -} - -int bcm271x_mbox_temp_get(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_TEMP_GET; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; //id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} - -int bcm271x_mbox_temp_get_max(void) -{ - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_TEMP_GET_MAX; - mbox[3] = 8; // buffer size - mbox[4] = 4; // len - - mbox[5] = 0; // id - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - mbox_call(8, MMU_DISABLE); - - if(mbox[5] != 0) - { - return -1; - } - - return mbox[6]; -} diff --git a/bsp/raspberry-pi/raspi4-64/drivers/mbox.h b/bsp/raspberry-pi/raspi4-64/drivers/mbox.h deleted file mode 100644 index 291cd77cf0..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/mbox.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2020-09-10 bigmagic first version - */ - -#ifndef __MBOX_H__ -#define __MBOX_H__ - -#include - -//https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface -//https://github.com/hermanhermitage/videocoreiv - -/* a properly aligned buffer */ -extern volatile unsigned int* mbox; - -#define MBOX_REQUEST 0 - -/* channels */ -#define MBOX_CH_POWER 0 -#define MBOX_CH_FB 1 -#define MBOX_CH_VUART 2 -#define MBOX_CH_VCHIQ 3 -#define MBOX_CH_LEDS 4 -#define MBOX_CH_BTNS 5 -#define MBOX_CH_TOUCH 6 -#define MBOX_CH_COUNT 7 -#define MBOX_CH_PROP 8 - -/* tags */ -#define MBOX_TAG_SETPOWER 0x28001 -#define MBOX_TAG_SETCLKRATE 0x38002 -#define MBOX_GET_MAC_ADDRESS 0x10003 -#define MBOX_TAG_LAST 0 - -#define MMIO_BASE 0xFE000000 -#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) -extern size_t videocore_mbox; -#define MBOX_READ ((volatile unsigned int*)(videocore_mbox+0x0)) -#define MBOX_POLL ((volatile unsigned int*)(videocore_mbox+0x10)) -#define MBOX_SENDER ((volatile unsigned int*)(videocore_mbox+0x14)) -#define MBOX_STATUS ((volatile unsigned int*)(videocore_mbox+0x18)) -#define MBOX_CONFIG ((volatile unsigned int*)(videocore_mbox+0x1C)) -#define MBOX_WRITE ((volatile unsigned int*)(videocore_mbox+0x20)) -#define MBOX_RESPONSE 0x80000000 -#define MBOX_FULL 0x80000000 -#define MBOX_EMPTY 0x40000000 - -#define DEVICE_ID_SD_CARD (0) -#define DEVICE_ID_USB_HCD (3) -#define POWER_STATE_OFF (0 << 0) -#define POWER_STATE_ON (1 << 0) -#define POWER_STATE_WAIT (1 << 1) -#define POWER_STATE_NO_DEVICE (1 << 1) // in response -#define MMU_ENABLE (1) -#define MMU_DISABLE (0) - -/* - * raspi hardware info - */ -enum { - MBOX_TAG_HARDWARE_GET_MODEL = 0x00010001, - MBOX_TAG_HARDWARE_GET_REV = 0x00010002, - MBOX_TAG_HARDWARE_GET_MAC_ADDRESS = 0x00010003, - MBOX_TAG_HARDWARE_GET_SERIAL = 0x00010004, - MBOX_TAG_HARDWARE_GET_ARM_MEMORY = 0x00010005, - MBOX_TAG_HARDWARE_GET_VC_MEMORY = 0x00010006, - MBOX_TAG_HARDWARE_GET_CLOCKS = 0x00010007, -}; - -/* - * raspi clock - */ -enum { - MBOX_TAG_CLOCK_GET_TURBO = 0x00030009, - MBOX_TAG_CLOCK_SET_TURBO = 0x00038009, - MBOX_TAG_CLOCK_GET_STATE = 0x00030001, - MBOX_TAG_CLOCK_SET_STATE = 0x00038001, - MBOX_TAG_CLOCK_GET_RATE = 0x00030002, - MBOX_TAG_CLOCK_SET_RATE = 0x00038002, - MBOX_TAG_CLOCK_GET_MAX_RATE = 0x00030004, - MBOX_TAG_CLOCK_GET_MIN_RATE = 0x00030007, -}; - -/* - * raspi power - */ -enum { - MBOX_TAG_POWER_GET_STATE = 0x00020001, - MBOX_TAG_POWER_SET_STATE = 0x00028001, -}; - -/* - * raspi temperature - */ -enum { - MBOX_TAG_TEMP_GET = 0x00030006, - MBOX_TAG_TEMP_GET_MAX = 0x0003000A, -}; - -/* - * raspi Memory - */ -enum { - MBOX_TAG_ALLOCATE_MEMORY = 0x0003000C, // Memory: Allocates Contiguous Memory On The GPU (Response: Handle) - MBOX_TAG_LOCK_MEMORY = 0x0003000D, // Memory: Unlock Buffer (Response: Status) - MBOX_TAG_UNLOCK_MEMORY = 0x0003000E, // Memory: Unlock Buffer (Response: Status) - MBOX_TAG_RELEASE_MEMORY = 0x0003000F, // Memory: Free The Memory Buffer (Response: Status) - MBOX_TAG_EXECUTE_CODE = 0x00030010, // Memory: Calls The Function At Given (Bus) Address And With Arguments Given -}; - -/* - * raspi GPU - */ -enum { - MBOX_TAG_EXECUTE_QPU = 0x00030011, // QPU: Calls The QPU Function At Given (Bus) Address And With Arguments Given (Response: Number Of QPUs, Control, No Flush, Timeout In ms) - MBOX_TAG_ENABLE_QPU = 0x00030012, // QPU: Enables The QPU (Response: Enable State) -}; - -/* - * raspi HDMI - */ -#define MBOX_TAG_GET_EDID_BLOCK 0x00030020 // HDMI: Read Specificed EDID Block From Attached HDMI/DVI Device (Response: Block Number, Status, EDID Block (128 Bytes)) - -/* - * raspi NOTIFY - */ -#define MBOX_TAG_NOTIFY_REBOOT 0x00030048 -#define MBOX_TAG_NOTIFY_XHCI_RESET 0x00030058 - -/* -* touch -*/ -#define MBOX_TAG_GET_TOUCHBUF (0x0004000F) - -#define MBOX_ADDR 0x08000000 -extern size_t mbox_addr; - -#define RES_CLK_ID (0x000000000) -#define EMMC_CLK_ID (0x000000001) -#define UART_CLK_ID (0x000000002) -#define ARM_CLK_ID (0x000000003) -#define CORE_CLK_ID (0x000000004) -#define V3D_CLK_ID (0x000000005) -#define H264_CLK_ID (0x000000006) -#define ISP_CLK_ID (0x000000007) -#define SDRAM_CLK_ID (0x000000008) -#define PIXEL_CLK_ID (0x000000009) -#define PWM_CLK_ID (0x00000000a) - -int mbox_call(unsigned char ch, int mmu_enable); -int bcm271x_mbox_get_touch(void); -int bcm271x_notify_reboot(void); -int bcm271x_notify_xhci_reset(void); -int bcm271x_gpu_enable(void); -int bcm271x_mbox_hardware_get_model(void); -int bcm271x_mbox_hardware_get_revison(void); -int bcm271x_mbox_hardware_get_mac_address(uint8_t * mac); -int bcm271x_mbox_hardware_get_serial(rt_uint64_t* sn); -int bcm271x_mbox_hardware_get_arm_memory(rt_uint32_t * base, rt_uint32_t * size); -int bcm271x_mbox_hardware_get_vc_memory(rt_uint32_t * base, rt_uint32_t * size); -int bcm271x_mbox_clock_get_turbo(void); -int bcm271x_mbox_clock_set_turbo(int level); -int bcm271x_mbox_clock_get_state(int id); -int bcm271x_mbox_clock_set_state(int id, int state); -int bcm271x_mbox_clock_get_rate(int id); -int bcm271x_mbox_clock_set_rate(int id, int rate); -int bcm271x_mbox_clock_get_max_rate(int id); -int bcm271x_mbox_clock_get_min_rate(int id); -int bcm271x_mbox_power_get_state(int id); -int bcm271x_mbox_power_set_state(int id, int state); -int bcm271x_mbox_temp_get(void); -int bcm271x_mbox_temp_get_max(void); - -#endif diff --git a/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h b/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h deleted file mode 100644 index 64b40d3753..0000000000 --- a/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-02-06 RT-Thread first version - */ -#ifndef __RASPI4_H__ -#define __RASPI4_H__ - -#include - -//https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0.pdf - -#define __REG32(x) (*((volatile unsigned int *)(x))) -#define __REG16(x) (*((volatile unsigned short *)(x))) - -/* GIC IRQ MAX */ -#define MAX_HANDLERS (256) - -/* base address */ -#define PER_BASE (0xFE000000) - -//gpio offset -#define GPIO_BASE_OFFSET (0x00200000) - - -#define PL011_UART_BASE_OFFSET (0x00201000) -//pl011 offset -#define PL011_UART0_BASE_OFFSET (0x00201000) -#define PL011_UART2_BASE_OFFSET (0x00201400) -#define PL011_UART3_BASE_OFFSET (0x00201600) -#define PL011_UART4_BASE_OFFSET (0x00201800) -#define PL011_UART5_BASE_OFFSET (0x00201A00) - -//pactl cs offset -#define PACTL_CS_OFFSET (0x00204E00) - -//aux offset -#define AUX_BASE_OFFSET (0x00215000) - -/* GPIO */ -#define GPIO_BASE_ADDR (PER_BASE + GPIO_BASE_OFFSET) -extern size_t gpio_base_addr; -#define GPIO_BASE (gpio_base_addr) -#define GPIO_IRQ_NUM (3) //40 pin mode -#define IRQ_GPIO0 (96 + 49) //bank0 (0 to 27) -#define IRQ_GPIO1 (96 + 50) //bank1 (28 to 45) -#define IRQ_GPIO2 (96 + 51) //bank2 (46 to 57) -#define IRQ_GPIO3 (96 + 52) //bank3 - -/* Timer (ARM side) */ -#define ARM_TIMER_IRQ (64) -extern size_t arm_timer_base; -#define ARM_TIMER_BASE (PER_BASE + 0xB000) -#define ARM_TIMER_LOAD HWREG32(arm_timer_base + 0x400) -#define ARM_TIMER_VALUE HWREG32(arm_timer_base + 0x404) -#define ARM_TIMER_CTRL HWREG32(arm_timer_base + 0x408) -#define ARM_TIMER_IRQCLR HWREG32(arm_timer_base + 0x40C) -#define ARM_TIMER_RAWIRQ HWREG32(arm_timer_base + 0x410) -#define ARM_TIMER_MASKIRQ HWREG32(arm_timer_base + 0x414) -#define ARM_TIMER_RELOAD HWREG32(arm_timer_base + 0x418) -#define ARM_TIMER_PREDIV HWREG32(arm_timer_base + 0x41C) -#define ARM_TIMER_CNTR HWREG32(arm_timer_base + 0x420) - -/* UART PL011 */ -#define UART_BASE (PER_BASE + PL011_UART_BASE_OFFSET) -//extern uint32_t uart_base_addr; -#define UART0_BASE (UART_BASE + 0x0) -#define UART2_BASE (UART_BASE + 0x400) -#define UART3_BASE (UART_BASE + 0x600) -#define UART4_BASE (UART_BASE + 0x800) -#define UART5_BASE (UART_BASE + 0xA00) -#define IRQ_AUX_UART (96 + 29) -#define UART_REFERENCE_CLOCK (48000000) - -/* AUX */ -//#define AUX_BASE_ADDR (PER_BASE + AUX_BASE_OFFSET) -//extern uint32_t aux_addr; -//#define AUX_BASE (aux_addr + 0x0) - -#define AUX_BASE (PER_BASE + AUX_BASE_OFFSET) -#define IRQ_PL011 (96 + 57) - -/* Peripheral IRQ OR-ing */ -#define PACTL_CS_ADDR (PER_BASE + PACTL_CS_OFFSET) -extern size_t pactl_cs_base; -#define PACTL_CS HWREG32(pactl_cs_base) -typedef enum -{ - IRQ_SPI0 = 0x00000000, - IRQ_SPI1 = 0x00000002, - IRQ_SPI2 = 0x00000004, - IRQ_SPI3 = 0x00000008, - IRQ_SPI4 = 0x00000010, - IRQ_SPI5 = 0x00000020, - IRQ_SPI6 = 0x00000040, - IRQ_I2C0 = 0x00000100, - IRQ_I2C1 = 0x00000200, - IRQ_I2C2 = 0x00000400, - IRQ_I2C3 = 0x00000800, - IRQ_I2C4 = 0x00001000, - IRQ_I2C5 = 0x00002000, - IRQ_I2C6 = 0x00004000, - IRQ_I2C7 = 0x00008000, - IRQ_UART5 = 0x00010000, - IRQ_UART4 = 0x00020000, - IRQ_UART3 = 0x00040000, - IRQ_UART2 = 0x00080000, - IRQ_UART0 = 0x00100000 -} PACTL_CS_VAL; - -// 0x40, 0x44, 0x48, 0x4c: Core 0~3 Timers interrupt control -#define CORE0_TIMER_IRQ_CTRL HWREG32(0xFF800040) -#define TIMER_IRQ 30 -#define NON_SECURE_TIMER_IRQ (1 << 1) - -/* GIC */ -#define INTC_BASE (0xff800000) -#define ARM_GIC_NR_IRQS (512) -#define ARM_GIC_MAX_NR (512) -#define GIC_V2_BASE (INTC_BASE + 0x00040000) -extern size_t gic_base_addr; -#define GIC_V2_DISTRIBUTOR_BASE (gic_base_addr + 0x1000) -#define GIC_V2_CPU_INTERFACE_BASE (gic_base_addr + 0x2000) -#define GIC_V2_HYPERVISOR_BASE (gic_base_addr + 0x4000) -#define GIC_V2_VIRTUAL_CPU_BASE (gic_base_addr + 0x6000) - -#define GIC_PL400_DISTRIBUTOR_PPTR GIC_V2_DISTRIBUTOR_BASE -#define GIC_PL400_CONTROLLER_PPTR GIC_V2_CPU_INTERFACE_BASE - -#define GIC_IRQ_START 0 - -#define GIC_ACK_INTID_MASK 0x000003ff - - -//watchdog -#define WDT_BASE (PER_BASE + 0x00100000) -extern size_t wdt_base_addr; -#define PM_RSTC HWREG32(wdt_base_addr + 0x1c) -#define PM_RSTS HWREG32(wdt_base_addr + 0x20) -#define PM_WDOG HWREG32(wdt_base_addr + 0x24) - -#define PM_PASSWORD (0x5A000000) -#define PM_WDOG_TIME_SET (0x000fffff) -#define PM_RSTS_HADWRH_SET (0x00000040) -#define PM_RSTC_WRCFG_FULL_RESET (0x00000020) -#define PM_RSTC_WRCFG_CLR (0xffffffcf) -#define PM_RSTC_RESET (0x00000102) - -//timer -#define ST_BASE_OFFSET (0x003000) -#define STIMER_BASE (PER_BASE + ST_BASE_OFFSET) -extern size_t stimer_base_addr; -#define STIMER_CS __REG32(stimer_base_addr + 0x0000) -#define STIMER_CLO __REG32(stimer_base_addr + 0x0004) -#define STIMER_CHI __REG32(stimer_base_addr + 0x0008) -#define STIMER_C0 __REG32(stimer_base_addr + 0x000C) -#define STIMER_C1 __REG32(stimer_base_addr + 0x0010) -#define STIMER_C2 __REG32(stimer_base_addr + 0x0014) -#define STIMER_C3 __REG32(stimer_base_addr + 0x0018) - -#define DELAY_MICROS(micros) \ - do{ \ - rt_uint32_t compare = STIMER_CLO + micros * 25; \ - while (STIMER_CLO < compare); \ - } while (0) - -//External Mass Media Controller (SD Card) -#define MMC0_BASE_ADDR (PER_BASE+0x300000) -extern size_t mmc0_base_addr; -#define MMC2_BASE_ADDR (PER_BASE+0x340000) -extern size_t mmc2_base_addr; - -//mac -#define MAC_REG (void *)(0xfd580000) -extern uint8_t * mac_reg_base_addr; - -#define ETH_IRQ (160+29) - -#define SEND_DATA_NO_CACHE (0x08200000) -extern uint8_t * eth_send_no_cache; - -#define RECV_DATA_NO_CACHE (0x08400000) -extern uint8_t * eth_recv_no_cache; - -/* the basic constants and interfaces needed by gic */ -rt_inline size_t platform_get_gic_dist_base(void) -{ - return GIC_PL400_DISTRIBUTOR_PPTR; -} - -rt_inline size_t platform_get_gic_cpu_base(void) -{ - return GIC_PL400_CONTROLLER_PPTR; -} - -#endif diff --git a/bsp/raspberry-pi/raspi4-64/qemu.py b/bsp/raspberry-pi/raspi4-64/qemu.py new file mode 100755 index 0000000000..247119f25d --- /dev/null +++ b/bsp/raspberry-pi/raspi4-64/qemu.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import os, sys, re, shutil + +if os.getenv('RTT_QEMU_ROOT'): + RTT_QEMU_ROOT = os.getenv('RTT_QEMU_ROOT') +else: + RTT_QEMU_ROOT = "" + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.join(os.getcwd(), '..', '..', '..') + +sys.path.append(RTT_ROOT + '/tools') + +from building import * +import dtc + +dts_name = "bcm2711-rpi-4-b" + +dtc.dts_to_dtb(RTT_ROOT, ["../dm/dts/" + dts_name + ".dts"], include_paths = [os.getcwd() + '/../dm/include'], + ignore_warning = ["simple_bus_reg", "unit_address_vs_reg", "clocks_is_cell", "gpios_property"]) +try: + shutil.move("../dm/dts/" + dts_name + ".dtb", dts_name + ".dtb") +except: + exit(-1) + +opt = sys.argv + +q_graphic = "-nographic" +q_debug = "" + +def is_opt(key, inkey): + if str("-" + key) == inkey: + return True + return False + +for i in range(len(opt)): + if i == 0: + continue + inkey = opt[i] + + if is_opt("debug", inkey): q_debug = "-S -s" + if is_opt("graphic", inkey): q_graphic = "-usb -device usb-mouse -device usb-kbd" + +disk = "sd.qcow2" +if not os.path.exists(disk): + os.system("qemu-img create -f qcow2 {} 64M".format(disk)) + +flash = "flash.bin" +if not os.path.exists(flash): + os.system("qemu-img create -f raw {} 1M".format(flash)) + +os.system(""" +{}qemu-system-aarch64 \ + -M raspi4b \ + -m 2G \ + -kernel rtthread.bin \ + -dtb {}.dtb \ + -append "console=ttyAMA0 earlycon=pl011,0xfe201000 cma=8M coherent_pool=2M root=sd0p0 rootfstype=elm rootwait rw" \ + -serial mon:stdio \ + -drive if=sd,file={},format=qcow2 \ + -device ds1338,address=0x68,bus=i2c-bus.0 \ + -device m25p80,write-enable=true,drive=flash0,bus=spi \ + -blockdev node-name=flash0,driver=file,filename={} \ + -device usb-net,netdev=net0 -netdev user,id=net0 \ + {} \ + {} +""".format(RTT_QEMU_ROOT, dts_name, disk, flash, q_graphic, q_debug)) diff --git a/bsp/raspberry-pi/raspi4-64/rtconfig.h b/bsp/raspberry-pi/raspi4-64/rtconfig.h index 03c771e6b3..deaa70e437 100644 --- a/bsp/raspberry-pi/raspi4-64/rtconfig.h +++ b/bsp/raspberry-pi/raspi4-64/rtconfig.h @@ -8,16 +8,6 @@ /* rt_vsnprintf options */ #define RT_KLIBC_USING_VSNPRINTF_LONGLONG -#define RT_KLIBC_USING_VSNPRINTF_STANDARD -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6 -#define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 -#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4 /* end of rt_vsnprintf options */ /* rt_vsscanf options */ @@ -72,7 +62,7 @@ /* end of rt_strnlen options */ /* end of klibc options */ -#define RT_NAME_MAX 12 +#define RT_NAME_MAX 24 #define RT_USING_SMP #define RT_CPUS_NR 4 #define RT_ALIGN_SIZE 4 @@ -89,6 +79,8 @@ #define RT_USING_TIMER_SOFT #define RT_TIMER_THREAD_PRIO 4 #define RT_TIMER_THREAD_STACK_SIZE 8192 +#define RT_USING_CPU_USAGE_TRACER +#define RT_CPU_USAGE_CALC_INTERVAL_MS 200 /* kservice options */ @@ -109,6 +101,7 @@ /* Memory Management */ +#define RT_USING_MEMPOOL #define RT_USING_SLAB #define RT_USING_SLAB_AS_HEAP #define RT_USING_HEAP @@ -127,10 +120,11 @@ /* AArch64 Architecture Configuration */ -#define ARCH_TEXT_OFFSET 0x200000 +#define ARCH_TEXT_OFFSET 0x208000 #define ARCH_RAM_OFFSET 0 #define ARCH_SECONDARY_CPU_STACK_SIZE 4096 #define ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS +#define ARCH_USING_GENERIC_CPUID #define ARCH_HEAP_SIZE 0x4000000 #define ARCH_INIT_PAGE_SIZE 0x200000 /* end of AArch64 Architecture Configuration */ @@ -142,13 +136,14 @@ #define ARCH_ARM_MMU #define ARCH_ARMV8 #define ARCH_USING_ASID +#define ARCH_USING_HW_THREAD_SELF #define ARCH_USING_IRQ_CTX_LIST /* RT-Thread Components */ #define RT_USING_COMPONENTS_INIT #define RT_USING_USER_MAIN -#define RT_MAIN_THREAD_STACK_SIZE 8192 +#define RT_MAIN_THREAD_STACK_SIZE 16384 #define RT_MAIN_THREAD_PRIORITY 10 #define RT_USING_MSH #define RT_USING_FINSH @@ -194,6 +189,7 @@ /* Device Drivers */ +#define RT_USING_DM #define RT_USING_DEV_BUS #define RT_USING_DEVICE_IPC #define RT_UNAMED_PIPE_NUMBER 64 @@ -204,25 +200,86 @@ #define RT_USING_SERIAL_V1 #define RT_SERIAL_USING_DMA #define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_SERIAL_BYPASS +#define RT_SERIAL_PL011 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_BCM2835AUX #define RT_USING_CLOCK_TIME +#define RT_CLOCK_TIME_ARM_ARCH +#define RT_CLOCK_TIME_BCM2835 +#define RT_USING_ETHERNET +#define RT_ETHERNET_BCMGENET #define RT_USING_I2C -#define RT_USING_I2C_BITOPS +#define RT_I2C_BCM2835 +#define RT_I2C_BRCMSTB +#define RT_USING_PHY_V2 +#define RT_PHY_MDIO_BCM_UNIMAC +#define RT_PHY_BCM54213 #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM +#define RT_USING_PWM +#define RT_PWM_BCM2835 +#define RT_PWM_BRCMSTB #define RT_USING_RTC -#define RT_USING_SOFT_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 8192 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_DS1307 #define RT_USING_SDIO #define RT_SDIO_STACK_SIZE 8192 #define RT_SDIO_THREAD_PRIORITY 15 -#define RT_MMCSD_STACK_SIZE 8192 +#define RT_MMCSD_STACK_SIZE 16384 #define RT_MMCSD_THREAD_PRIORITY 22 #define RT_MMCSD_MAX_PARTITION 16 +#define RT_USING_SDHCI +#define RT_SDIO_SDHCI_BRCMSTB +#define RT_SDIO_SDHCI_IPROC #define RT_USING_SPI #define RT_USING_SPI_ISR +#define RT_SPI_BCM2835 +#define RT_SPI_BCM2835AUX #define RT_USING_WDT +#define RT_WDT_BCM2835 +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#define RT_AUDIO_RECORD_PIPE_SIZE 2048 +#define RT_AUDIO_BCM2835_I2S #define RT_USING_TOUCH #define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_BACKLIGHT +#define RT_GRAPHIC_BACKLIGHT_RPI +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_ILI9486 +#define RT_GRAPHIC_FB_SIMPLE +#define RT_GRAPHIC_FB_BCM2708 +#define RT_GRAPHIC_FB_RPISENSE +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RASPI_CLUT224 +#define RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH "../dm/graphic/logo/logo-raspi-clut224.ppm" +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_RNG_BCM2835 +#define RT_HWCRYPTO_RNG_IPROC_RNG200 +#define RT_USING_LED +#define RT_LED_GPIO +#define RT_USING_INPUT +#define RT_INPUT_POWER +#define RT_INPUT_JOYSTICK +#define RT_INPUT_JOYSTICK_RPISENSE +#define RT_INPUT_TOUCHSCREEN +#define RT_INPUT_TOUCHSCREEN_ADS7846 +#define RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW +#define RT_USING_MBOX +#define RT_MBOX_BCM2835 +#define RT_USING_PHYE +#define RT_PHYE_GENERIC_USB #define RT_USING_BLK /* Partition Types */ @@ -230,7 +287,88 @@ #define RT_BLK_PARTITION_DFS #define RT_BLK_PARTITION_EFI /* end of Partition Types */ +#define RT_USING_SCSI +#define RT_SCSI_SD +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_RASPBERRYPI +#define RT_USING_DVFS +#define RT_USING_DVFS_EVENT +#define RT_USING_DVFS_OPP_RETRY_MAX 10 + +/* DVFS Event Drivers */ + +/* DVFS CPUfreq Drivers */ + +#define RT_DVFS_RASPBERRY_CPUFREQ + +/* DVFS Devfreq Drivers */ + +#define RT_USING_REGULATOR +#define RT_REGULATOR_FIXED +#define RT_REGULATOR_GPIO +#define RT_USING_RESET +#define RT_RESET_SIMPLE +#define RT_RESET_BRCMSTB_RESCAL +#define RT_RESET_BRCMSTB +#define RT_RESET_RASPBERRYPI + +/* Power Management (PM) Domains device drivers */ + +#define RT_PMDOMAIN_RASPBERRYPI +/* end of Power Management (PM) Domains device drivers */ +#define RT_USING_THERMAL + +/* Thermal Sensors Drivers */ + +#define RT_THERMAL_BCM2835 +#define RT_THERMAL_BCM2711 + +/* Thermal Cool Drivers */ + +#define RT_USING_NVMEM +#define RT_NVMEM_RASPBERRYPI_OTP +#define RT_USING_DMA +#define RT_DMA_BCM2835 +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_BCM2835_PM +#define RT_MFD_RPI_SENSE +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 + +/* PCI Device Drivers */ + +#define RT_PCI_ECAM +#define RT_PCI_HOST_COMMON +#define RT_PCI_HOST_GENERIC +#define RT_PCIE_BRCMSTB +#define RT_USING_PIC +#define MAX_HANDLERS 512 +#define RT_PIC_ARM_GIC +#define RT_PIC_ARM_GIC_MAX_NR 1 +#define RT_PIC_BCM2835_INTC +#define RT_PIC_BCM2836_L1_INTC +#define RT_PIC_BRCMSTB_L2_IRQ #define RT_USING_PIN +#define RT_PIN_BCM_VIRT +#define RT_PIN_BRCMSTB +#define RT_PIN_RASPBERRYPI_EXP +#define RT_USING_PINCTRL +#define RT_PINCTRL_BCM2835 +#define RT_USING_CLK +#define RT_CLK_BCM2711_DVP +#define RT_CLK_BCM2835 +#define RT_CLK_RASPBERRYPI + +/* SoC (System on Chip) Drivers */ + +#define RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR +/* end of SoC (System on Chip) Drivers */ /* end of Device Drivers */ /* C/C++ and POSIX layer */ @@ -354,6 +492,8 @@ #define RT_PAGE_AFFINITY_BLOCK_SIZE 0x1000 #define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMBLOCK +#define RT_INIT_MEMORY_REGIONS 128 /* Debugging */ @@ -490,14 +630,6 @@ /* GD32 Drivers */ /* end of GD32 Drivers */ - -/* HPMicro SDK */ - -/* end of HPMicro SDK */ - -/* FT32 HAL & SDK Drivers */ - -/* end of FT32 HAL & SDK Drivers */ /* end of HAL & SDK Drivers */ /* sensors drivers */ @@ -577,30 +709,6 @@ /* end of Arduino libraries */ /* end of RT-Thread online packages */ -#define BCM2711_SOC -#define BSP_SUPPORT_FPU - -/* Hardware Drivers Config */ - -/* BCM Peripheral Drivers */ - -#define BSP_USING_UART -#define RT_USING_UART0 -#define RT_USING_UART3 -#define RT_USING_UART4 -#define BSP_USING_GIC -#define BSP_USING_GICV2 -#define BSP_USING_PIN -#define BSP_USING_CORETIMER -#define BSP_USING_WDT -#define BSP_USING_SDIO -#define BSP_USING_SDIO0 -/* end of BCM Peripheral Drivers */ - -/* Board Peripheral Drivers */ - -#define BSP_USING_HDMI -/* end of Board Peripheral Drivers */ -/* end of Hardware Drivers Config */ +#define SOC_BCM2711 #endif diff --git a/bsp/raspberry-pi/raspi4-64/rtconfig.py b/bsp/raspberry-pi/raspi4-64/rtconfig.py index 17edd896c5..f15aa8b502 100644 --- a/bsp/raspberry-pi/raspi4-64/rtconfig.py +++ b/bsp/raspberry-pi/raspi4-64/rtconfig.py @@ -25,7 +25,8 @@ if PLATFORM == 'gcc': # toolchains PREFIX = os.getenv('RTT_CC_PREFIX') or 'aarch64-none-elf-' CC = PREFIX + 'gcc' - CPP = PREFIX + 'g++' + CXX = PREFIX + 'g++' + CPP = PREFIX + 'cpp' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' @@ -34,8 +35,8 @@ if PLATFORM == 'gcc': OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' - DEVICE = ' -march=armv8-a -mtune=cortex-a72' - CPPFLAGS = ' -E -P -x assembler-with-cpp' + DEVICE = ' -march=armv8-a -mtune=cortex-a72 -fdiagnostics-color=always -ftree-vectorize -ffast-math -funwind-tables -fno-strict-aliasing' + CPPFLAGS = ' -nostdinc -undef -E -P -x assembler-with-cpp' CFLAGS = DEVICE + ' -Wall -Wno-cpp -D_POSIX_SOURCE' AFLAGS = ' -c' + ' -x assembler-with-cpp -D__ASSEMBLY__' LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds' @@ -52,3 +53,10 @@ if PLATFORM == 'gcc': DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' + + +def dist_handle(BSP_ROOT, dist_dir): + import sys + sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools')) + from sdk_dist import dist_do_building + dist_do_building(BSP_ROOT, dist_dir) diff --git a/bsp/raspberry-pi/raspi-dm2.0/.config b/bsp/raspberry-pi/raspi5/.config similarity index 86% rename from bsp/raspberry-pi/raspi-dm2.0/.config rename to bsp/raspberry-pi/raspi5/.config index 0988715951..c272203b32 100644 --- a/bsp/raspberry-pi/raspi-dm2.0/.config +++ b/bsp/raspberry-pi/raspi5/.config @@ -12,17 +12,7 @@ # # CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y -# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6 -CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9 -CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set # end of rt_vsnprintf options # @@ -116,30 +106,30 @@ CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 # end of rt_strnlen options # end of klibc options -CONFIG_RT_NAME_MAX=12 +CONFIG_RT_NAME_MAX=24 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set # CONFIG_RT_USING_NANO is not set CONFIG_RT_USING_SMART=y # CONFIG_RT_USING_AMP is not set CONFIG_RT_USING_SMP=y CONFIG_RT_CPUS_NR=4 -CONFIG_RT_ALIGN_SIZE=4 +CONFIG_RT_ALIGN_SIZE=8 # CONFIG_RT_THREAD_PRIORITY_8 is not set CONFIG_RT_THREAD_PRIORITY_32=y # CONFIG_RT_THREAD_PRIORITY_256 is not set CONFIG_RT_THREAD_PRIORITY_MAX=32 -CONFIG_RT_TICK_PER_SECOND=1000 +CONFIG_RT_TICK_PER_SECOND=100 CONFIG_RT_USING_OVERFLOW_CHECK=y CONFIG_RT_USING_HOOK=y CONFIG_RT_HOOK_USING_FUNC_PTR=y # CONFIG_RT_USING_HOOKLIST is not set CONFIG_RT_USING_IDLE_HOOK=y CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 -CONFIG_IDLE_THREAD_STACK_SIZE=16384 -CONFIG_SYSTEM_THREAD_STACK_SIZE=16384 +CONFIG_IDLE_THREAD_STACK_SIZE=8192 +CONFIG_SYSTEM_THREAD_STACK_SIZE=8192 CONFIG_RT_USING_TIMER_SOFT=y CONFIG_RT_TIMER_THREAD_PRIO=4 -CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=8192 # CONFIG_RT_USING_TIMER_ALL_SOFT is not set CONFIG_RT_USING_CPU_USAGE_TRACER=y CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 @@ -151,12 +141,12 @@ CONFIG_RT_CPU_USAGE_CALC_INTERVAL_MS=200 # end of kservice options CONFIG_RT_USING_DEBUG=y -# CONFIG_RT_DEBUGING_ASSERT is not set +CONFIG_RT_DEBUGING_ASSERT=y CONFIG_RT_DEBUGING_COLOR=y CONFIG_RT_DEBUGING_CONTEXT=y # CONFIG_RT_DEBUGING_AUTO_INIT is not set # CONFIG_RT_DEBUGING_SPINLOCK is not set -# CONFIG_RT_DEBUGING_CRITICAL is not set +CONFIG_RT_DEBUGING_CRITICAL=y # CONFIG_RT_USING_CI_ACTION is not set # @@ -174,27 +164,29 @@ CONFIG_RT_USING_MESSAGEQUEUE=y # # Memory Management # -# CONFIG_RT_USING_MEMPOOL is not set +CONFIG_RT_USING_MEMPOOL=y # CONFIG_RT_USING_SMALL_MEM is not set CONFIG_RT_USING_SLAB=y -# CONFIG_RT_USING_MEMHEAP is not set +CONFIG_RT_USING_MEMHEAP=y +CONFIG_RT_MEMHEAP_FAST_MODE=y +# CONFIG_RT_MEMHEAP_BEST_MODE is not set # CONFIG_RT_USING_SMALL_MEM_AS_HEAP is not set # CONFIG_RT_USING_MEMHEAP_AS_HEAP is not set CONFIG_RT_USING_SLAB_AS_HEAP=y # CONFIG_RT_USING_USERHEAP is not set # CONFIG_RT_USING_NOHEAP is not set # CONFIG_RT_USING_MEMTRACE is not set -# CONFIG_RT_USING_HEAP_ISR is not set +CONFIG_RT_USING_HEAP_ISR=y CONFIG_RT_USING_HEAP=y # end of Memory Management CONFIG_RT_USING_DEVICE=y CONFIG_RT_USING_DEVICE_OPS=y CONFIG_RT_USING_INTERRUPT_INFO=y -# CONFIG_RT_USING_THREADSAFE_PRINTF is not set +CONFIG_RT_USING_THREADSAFE_PRINTF=y CONFIG_RT_USING_CONSOLE=y CONFIG_RT_CONSOLEBUF_SIZE=256 -CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" +CONFIG_RT_CONSOLE_DEVICE_NAME="uart10" CONFIG_RT_USING_CONSOLE_OUTPUT_CTL=y CONFIG_RT_VER_NUM=0x50300 CONFIG_RT_USING_STDC_ATOMIC=y @@ -204,13 +196,14 @@ CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32 # # AArch64 Architecture Configuration # -CONFIG_ARCH_TEXT_OFFSET=0x200000 -CONFIG_ARCH_RAM_OFFSET=0x0 -CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=65536 +CONFIG_ARCH_TEXT_OFFSET=0x210000 +CONFIG_ARCH_RAM_OFFSET=0x200000 +CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -# CONFIG_ARCH_USING_GENERIC_CPUID is not set +CONFIG_ARCH_USING_GENERIC_CPUID=y CONFIG_ARCH_HEAP_SIZE=0x4000000 CONFIG_ARCH_INIT_PAGE_SIZE=0x200000 +# CONFIG_ARCH_USING_CPUIDLE is not set # end of AArch64 Architecture Configuration CONFIG_ARCH_CPU_64BIT=y @@ -222,6 +215,7 @@ CONFIG_ARCH_ARM_MMU=y CONFIG_KERNEL_VADDR_START=0xffff000000000000 CONFIG_ARCH_ARMV8=y CONFIG_ARCH_USING_ASID=y +CONFIG_ARCH_USING_HW_THREAD_SELF=y CONFIG_ARCH_USING_IRQ_CTX_LIST=y # @@ -239,11 +233,11 @@ CONFIG_FINSH_THREAD_NAME="tshell" CONFIG_FINSH_THREAD_PRIORITY=20 CONFIG_FINSH_THREAD_STACK_SIZE=8192 CONFIG_FINSH_USING_HISTORY=y -CONFIG_FINSH_HISTORY_LINES=5 +CONFIG_FINSH_HISTORY_LINES=10 # CONFIG_FINSH_USING_WORD_OPERATION is not set # CONFIG_FINSH_USING_FUNC_EXT is not set CONFIG_FINSH_USING_SYMTAB=y -CONFIG_FINSH_CMD_SIZE=80 +CONFIG_FINSH_CMD_SIZE=256 CONFIG_MSH_USING_BUILT_IN_COMMANDS=y CONFIG_FINSH_USING_DESCRIPTION=y # CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set @@ -257,7 +251,7 @@ CONFIG_FINSH_USING_OPTION_COMPLETION=y CONFIG_RT_USING_DFS=y CONFIG_DFS_USING_POSIX=y CONFIG_DFS_USING_WORKDIR=y -CONFIG_DFS_FD_MAX=64 +CONFIG_DFS_FD_MAX=32 CONFIG_RT_USING_DFS_V2=y CONFIG_RT_USING_DFS_ELMFAT=y @@ -286,11 +280,11 @@ CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 # end of elm-chan's FatFs, Generic FAT Filesystem Module CONFIG_RT_USING_DFS_DEVFS=y -# CONFIG_RT_USING_DFS_ROMFS is not set +CONFIG_RT_USING_DFS_ROMFS=y CONFIG_RT_USING_DFS_PTYFS=y -CONFIG_RT_USING_DFS_PROCFS=y +# CONFIG_RT_USING_DFS_PROCFS is not set # CONFIG_RT_USING_DFS_CROMFS is not set -CONFIG_RT_USING_DFS_TMPFS=y +# CONFIG_RT_USING_DFS_TMPFS is not set # CONFIG_RT_USING_DFS_MQUEUE is not set CONFIG_RT_USING_PAGECACHE=y @@ -316,57 +310,91 @@ CONFIG_RT_USING_DEV_BUS=y CONFIG_RT_USING_DEVICE_IPC=y CONFIG_RT_UNAMED_PIPE_NUMBER=64 CONFIG_RT_USING_SYSTEM_WORKQUEUE=y -CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=16384 +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 CONFIG_RT_USING_SERIAL=y CONFIG_RT_USING_SERIAL_V1=y # CONFIG_RT_USING_SERIAL_V2 is not set CONFIG_RT_SERIAL_USING_DMA=y -CONFIG_RT_SERIAL_RB_BUFSZ=64 +CONFIG_RT_SERIAL_RB_BUFSZ=256 CONFIG_RT_USING_SERIAL_BYPASS=y # CONFIG_RT_SERIAL_EARLY_HVC is not set -# CONFIG_RT_SERIAL_PL011 is not set -# CONFIG_RT_SERIAL_8250 is not set +CONFIG_RT_SERIAL_PL011=y +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +# CONFIG_RT_SERIAL_VIRTUAL is not set +CONFIG_RT_SERIAL_8250_BCM2835AUX=y +CONFIG_RT_SERIAL_8250_BCM7271=y # CONFIG_RT_USING_CAN is not set +CONFIG_RT_USING_ADC=y +# CONFIG_RT_USING_ADC_V2 is not set +CONFIG_RT_USING_ADC_V1=y +CONFIG_RT_ADC_RP1=y CONFIG_RT_USING_CLOCK_TIME=y -# CONFIG_RT_CLOCK_TIME_ARM_ARCH is not set +# CONFIG_RT_USING_CLOCK_TIMER_TRIGGER is not set +CONFIG_RT_CLOCK_TIME_ARM_ARCH=y +CONFIG_RT_CLOCK_TIME_BCM2835=y +CONFIG_RT_USING_ETHERNET=y +CONFIG_RT_ETHERNET_CADENCE=y +# CONFIG_RT_ETHERNET_CADENCE_PCI is not set +CONFIG_RT_ETHERNET_CADENCE_PTP=y +# CONFIG_RT_ETHERNET_DWMAC is not set +# CONFIG_RT_ETHERNET_BCMGENET 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_SOFT_I2C is not set +CONFIG_RT_I2C_BCM2835=y +CONFIG_RT_I2C_BRCMSTB=y # CONFIG_RT_USING_PHY is not set -# CONFIG_RT_USING_PHY_V2 is not set -# CONFIG_RT_USING_ADC is not set +CONFIG_RT_USING_PHY_V2=y +# CONFIG_RT_PHY_V2_REALTEK is not set +# CONFIG_RT_PHY_MDIO_BCM_UNIMAC is not set +CONFIG_RT_PHY_BCM54213=y # CONFIG_RT_USING_DAC is not set CONFIG_RT_USING_NULL=y CONFIG_RT_USING_ZERO=y CONFIG_RT_USING_RANDOM=y -# CONFIG_RT_USING_PWM is not set +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_BCM2835=y +CONFIG_RT_PWM_BRCMSTB=y +CONFIG_RT_PWM_RP1=y # CONFIG_RT_USING_PULSE_ENCODER is not set # CONFIG_RT_USING_INPUT_CAPTURE is not set # CONFIG_RT_USING_MTD_NOR is not set # CONFIG_RT_USING_MTD_NAND is not set # CONFIG_RT_USING_PM is not set CONFIG_RT_USING_RTC=y -# CONFIG_RT_USING_ALARM is not set -CONFIG_RT_USING_SOFT_RTC=y -# CONFIG_RT_RTC_DS1302 is not set -# CONFIG_RT_RTC_DS1307 is not set +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=8192 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set +CONFIG_RT_RTC_DS1302=y +CONFIG_RT_RTC_DS1307=y # CONFIG_RT_RTC_GOLDFISH is not set # CONFIG_RT_RTC_HYM8563 is not set -# CONFIG_RT_RTC_PCF8523 is not set +CONFIG_RT_RTC_PCF8523=y # CONFIG_RT_RTC_PCF8563 is not set # CONFIG_RT_RTC_PL031 is not set # CONFIG_RT_RTC_RX8010 is not set +CONFIG_RT_RTC_RPI=y CONFIG_RT_USING_SDIO=y -CONFIG_RT_SDIO_STACK_SIZE=16384 +CONFIG_RT_SDIO_STACK_SIZE=8192 CONFIG_RT_SDIO_THREAD_PRIORITY=15 CONFIG_RT_MMCSD_STACK_SIZE=8192 CONFIG_RT_MMCSD_THREAD_PRIORITY=22 CONFIG_RT_MMCSD_MAX_PARTITION=16 # CONFIG_RT_SDIO_DEBUG is not set CONFIG_RT_USING_SDHCI=y +# CONFIG_RT_SDIO_SDHCI_PCI is not set +# CONFIG_RT_SDIO_DW_MMC is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +CONFIG_RT_SDIO_SDHCI_BRCMSTB=y +CONFIG_RT_SDIO_SDHCI_IPROC=y CONFIG_RT_USING_SPI=y CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SPI_BITOPS is not set @@ -376,19 +404,86 @@ CONFIG_RT_USING_SPI_ISR=y # CONFIG_RT_USING_SFUD is not set # CONFIG_RT_USING_ENC28J60 is not set # CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_BCM2835=y +CONFIG_RT_SPI_BCM2835AUX=y CONFIG_RT_USING_WDT=y -# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_WDT_DW is not set +# CONFIG_RT_WDT_I6300ESB is not set +CONFIG_RT_WDT_BCM2835=y +CONFIG_RT_USING_AUDIO=y +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_SIZE=4096 +CONFIG_RT_AUDIO_REPLAY_MP_BLOCK_COUNT=2 +CONFIG_RT_AUDIO_RECORD_PIPE_SIZE=2048 +# CONFIG_RT_AUDIO_INTEL_HDA is not set +CONFIG_RT_AUDIO_BCM2835_I2S=y # CONFIG_RT_USING_SENSOR is not set CONFIG_RT_USING_TOUCH=y # CONFIG_RT_TOUCH_PIN_IRQ is not set -# CONFIG_RT_USING_GRAPHIC is not set -# CONFIG_RT_USING_HWCRYPTO is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +CONFIG_RT_GRAPHIC_BACKLIGHT=y +# CONFIG_RT_GRAPHIC_BACKLIGHT_GPIO is not set +# CONFIG_RT_GRAPHIC_BACKLIGHT_PWM is not set +CONFIG_RT_GRAPHIC_BACKLIGHT_RPI=y +CONFIG_RT_GRAPHIC_FB=y +CONFIG_RT_GRAPHIC_FB_ILI9486=y +CONFIG_RT_GRAPHIC_FB_SIMPLE=y +CONFIG_RT_GRAPHIC_FB_BCM2708=y +CONFIG_RT_GRAPHIC_FB_RPISENSE=y +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 is not set +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224=y +CONFIG_RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH="../dm/graphic/logo/logo-raspi-clut224.ppm" +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +# CONFIG_RT_HWCRYPTO_USING_AES is not set +# CONFIG_RT_HWCRYPTO_USING_DES is not set +# CONFIG_RT_HWCRYPTO_USING_3DES is not set +# CONFIG_RT_HWCRYPTO_USING_RC4 is not set +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set +CONFIG_RT_HWCRYPTO_RNG_BCM2835=y +CONFIG_RT_HWCRYPTO_RNG_IPROC_RNG200=y # CONFIG_RT_USING_WIFI is not set -# CONFIG_RT_USING_LED is not set -# CONFIG_RT_USING_INPUT is not set -# CONFIG_RT_USING_MBOX is not set +CONFIG_RT_USING_PTP=y +CONFIG_RT_USING_LED=y +CONFIG_RT_LED_GPIO=y +# CONFIG_RT_LED_PWM is not set +# CONFIG_RT_LED_SYSCON is not set +CONFIG_RT_USING_INPUT=y +CONFIG_RT_INPUT_POWER=y +# CONFIG_RT_INPUT_UAPI is not set +CONFIG_RT_INPUT_JOYSTICK=y +# CONFIG_RT_INPUT_JOYSTICK_ADC is not set +CONFIG_RT_INPUT_JOYSTICK_RPISENSE=y +CONFIG_RT_INPUT_KEYBOARD=y +# CONFIG_RT_INPUT_KEYBOARD_ADC is not set +CONFIG_RT_INPUT_KEYBOARD_GPIO=y +# CONFIG_RT_INPUT_MISC is not set +CONFIG_RT_INPUT_TOUCHSCREEN=y +CONFIG_RT_INPUT_TOUCHSCREEN_ADS7846=y +# CONFIG_RT_INPUT_TOUCHSCREEN_GOODIX is not set +CONFIG_RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW=y +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_PIC is not set +CONFIG_RT_MBOX_BCM2835=y # CONFIG_RT_USING_HWSPINLOCK is not set -# CONFIG_RT_USING_PHYE is not set +# CONFIG_RT_USING_RPMSG is not set +CONFIG_RT_USING_PHYE=y +CONFIG_RT_PHYE_GENERIC_USB=y +# CONFIG_RT_USING_ATA is not set +CONFIG_RT_USING_NVME=y +CONFIG_RT_USING_NVME_IO_QUEUE=1 +CONFIG_RT_NVME_PCI=y CONFIG_RT_USING_BLK=y # @@ -399,43 +494,125 @@ CONFIG_RT_BLK_PARTITION_EFI=y # end of Partition Types # CONFIG_RT_USING_SCSI is not set -# CONFIG_RT_USING_FIRMWARE is not set +CONFIG_RT_USING_FIRMWARE=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set +# CONFIG_RT_FIRMWARE_ARM_SCMI is not set +CONFIG_RT_FIRMWARE_RASPBERRYPI=y +# CONFIG_RT_USING_TEE is not set # CONFIG_RT_USING_HWCACHE is not set -# CONFIG_RT_USING_REGULATOR is not set -# CONFIG_RT_USING_RESET is not set +CONFIG_RT_USING_DVFS=y +CONFIG_RT_USING_DVFS_EVENT=y +CONFIG_RT_USING_DVFS_OPP_RETRY_MAX=10 + +# +# DVFS Event Drivers +# + +# +# DVFS CPUfreq Drivers +# +CONFIG_RT_DVFS_RASPBERRY_CPUFREQ=y + +# +# DVFS Devfreq Drivers +# +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_FAN53555 is not set +CONFIG_RT_REGULATOR_FIXED=y +CONFIG_RT_REGULATOR_GPIO=y +# CONFIG_RT_REGULATOR_PWM is not set +CONFIG_RT_USING_RESET=y +CONFIG_RT_RESET_SIMPLE=y +CONFIG_RT_RESET_BRCMSTB_RESCAL=y +CONFIG_RT_RESET_BRCMSTB=y +CONFIG_RT_RESET_RASPBERRYPI=y # # Power Management (PM) Domains device drivers # +CONFIG_RT_PMDOMAIN_BCM2835=y +CONFIG_RT_PMDOMAIN_RASPBERRYPI=y # end of Power Management (PM) Domains device drivers # CONFIG_RT_USING_POWER_RESET is not set # CONFIG_RT_USING_POWER_SUPPLY is not set -# CONFIG_RT_USING_THERMAL is not set +CONFIG_RT_USING_THERMAL=y + +# +# Thermal Sensors Drivers +# +CONFIG_RT_THERMAL_BCM2835=y +CONFIG_RT_THERMAL_BCM2711=y + +# +# Thermal Cool Drivers +# +CONFIG_RT_THERMAL_COOL_DVFS=y +# CONFIG_RT_THERMAL_COOL_GPIO_FAN is not set +CONFIG_RT_THERMAL_COOL_PWM_FAN=y # CONFIG_RT_USING_VIRTIO is not set # CONFIG_RT_USING_NVMEM is not set -# CONFIG_RT_USING_DMA is not set -# CONFIG_RT_USING_MFD is not set +CONFIG_RT_USING_DMA=y +# CONFIG_RT_DMA_PL330 is not set +CONFIG_RT_DMA_DW_AXI_DMAC=y +CONFIG_RT_DMA_BCM2835=y +CONFIG_RT_USING_MFD=y +# CONFIG_RT_MFD_EDU is not set +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_BCM2835_PM=y +CONFIG_RT_MFD_RP1=y +CONFIG_RT_MFD_RPI_SENSE=y +# CONFIG_RT_USING_IVSHMEM is not set CONFIG_RT_USING_OFW=y # CONFIG_RT_USING_BUILTIN_FDT is not set CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 -# CONFIG_RT_USING_PCI is not set +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +# CONFIG_RT_PCI_ENDPOINT is not set +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set + +# +# PCI Device Drivers +# +# CONFIG_RT_PCI_ECAM is not set +# CONFIG_RT_PCI_DW is not set +CONFIG_RT_PCIE_BRCMSTB=y CONFIG_RT_USING_PIC=y # CONFIG_RT_USING_PIC_STATISTICS is not set -CONFIG_MAX_HANDLERS=256 +CONFIG_MAX_HANDLERS=1024 CONFIG_RT_PIC_ARM_GIC=y +# CONFIG_RT_PIC_ARM_GIC_V2M is not set # CONFIG_RT_PIC_ARM_GIC_V3 is not set CONFIG_RT_PIC_ARM_GIC_MAX_NR=1 +CONFIG_RT_PIC_BCM2712_MIP=y +CONFIG_RT_PIC_BCM2835_INTC=y +CONFIG_RT_PIC_BCM2836_L1_INTC=y +CONFIG_RT_PIC_BRCMSTB_L2_IRQ=y CONFIG_RT_USING_PIN=y # CONFIG_RT_PIN_PL061 is not set -# CONFIG_RT_USING_PINCTRL is not set +CONFIG_RT_PIN_BCM_VIRT=y +CONFIG_RT_PIN_BRCMSTB=y +CONFIG_RT_PIN_RASPBERRYPI_EXP=y +CONFIG_RT_USING_PINCTRL=y +# CONFIG_RT_PINCTRL_SINGLE is not set +CONFIG_RT_PINCTRL_BCM2712=y +CONFIG_RT_PINCTRL_BCM2835=y +CONFIG_RT_PINCTRL_RP1=y CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_BCM2711_DVP=y +CONFIG_RT_CLK_BCM2835=y +CONFIG_RT_CLK_RASPBERRYPI=y +CONFIG_RT_CLK_RP1=y # CONFIG_RT_USING_CHERRYUSB is not set # # SoC (System on Chip) Drivers # +CONFIG_RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR=y +# end of SoC (System on Chip) Drivers # end of Device Drivers # @@ -464,12 +641,12 @@ CONFIG_RT_USING_POSIX_FS=y CONFIG_RT_USING_POSIX_DEVIO=y CONFIG_RT_USING_POSIX_STDIO=y CONFIG_RT_USING_POSIX_POLL=y -# CONFIG_RT_USING_POSIX_SELECT is not set -# CONFIG_RT_USING_POSIX_EVENTFD is not set +CONFIG_RT_USING_POSIX_SELECT=y +CONFIG_RT_USING_POSIX_EVENTFD=y CONFIG_RT_USING_POSIX_EPOLL=y CONFIG_RT_USING_POSIX_SIGNALFD=y CONFIG_RT_SIGNALFD_MAX_NUM=10 -# CONFIG_RT_USING_POSIX_TIMERFD is not set +CONFIG_RT_USING_POSIX_TIMERFD=y # CONFIG_RT_USING_POSIX_SOCKET is not set CONFIG_RT_USING_POSIX_TERMIOS=y # CONFIG_RT_USING_POSIX_AIO is not set @@ -483,7 +660,8 @@ CONFIG_RT_USING_POSIX_TIMER=y # # Interprocess Communication (IPC) # -# CONFIG_RT_USING_POSIX_PIPE is not set +CONFIG_RT_USING_POSIX_PIPE=y +CONFIG_RT_USING_POSIX_PIPE_SIZE=512 # CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set # CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set @@ -524,12 +702,12 @@ CONFIG_NETDEV_IPV6=0 CONFIG_RT_USING_LWIP=y # CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set # CONFIG_RT_USING_LWIP141 is not set -# CONFIG_RT_USING_LWIP203 is not set -CONFIG_RT_USING_LWIP212=y +CONFIG_RT_USING_LWIP203=y +# CONFIG_RT_USING_LWIP212 is not set # CONFIG_RT_USING_LWIP_LATEST is not set -CONFIG_RT_USING_LWIP_VER_NUM=0x20102 +CONFIG_RT_USING_LWIP_VER_NUM=0x20003 # CONFIG_RT_USING_LWIP_IPV6 is not set -CONFIG_RT_LWIP_MEM_ALIGNMENT=4 +CONFIG_RT_LWIP_MEM_ALIGNMENT=8 CONFIG_RT_LWIP_IGMP=y CONFIG_RT_LWIP_ICMP=y # CONFIG_RT_LWIP_SNMP is not set @@ -541,8 +719,8 @@ CONFIG_IP_SOF_BROADCAST_RECV=1 # # Static IPv4 Address # -CONFIG_RT_LWIP_IPADDR="192.168.137.100" -CONFIG_RT_LWIP_GWADDR="192.168.137.1" +CONFIG_RT_LWIP_IPADDR="192.168.1.30" +CONFIG_RT_LWIP_GWADDR="192.168.1.1" CONFIG_RT_LWIP_MSKADDR="255.255.255.0" # end of Static IPv4 Address @@ -550,23 +728,23 @@ CONFIG_RT_LWIP_UDP=y CONFIG_RT_LWIP_TCP=y CONFIG_RT_LWIP_RAW=y # CONFIG_RT_LWIP_PPP is not set -CONFIG_RT_MEMP_NUM_NETCONN=16 +CONFIG_RT_MEMP_NUM_NETCONN=8 CONFIG_RT_LWIP_PBUF_NUM=16 CONFIG_RT_LWIP_RAW_PCB_NUM=4 -CONFIG_RT_LWIP_UDP_PCB_NUM=8 -CONFIG_RT_LWIP_TCP_PCB_NUM=8 +CONFIG_RT_LWIP_UDP_PCB_NUM=4 +CONFIG_RT_LWIP_TCP_PCB_NUM=4 CONFIG_RT_LWIP_TCP_SEG_NUM=40 -CONFIG_RT_LWIP_TCP_SND_BUF=8192 -CONFIG_RT_LWIP_TCP_WND=8192 +CONFIG_RT_LWIP_TCP_SND_BUF=8196 +CONFIG_RT_LWIP_TCP_WND=8196 CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10 CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8 -CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=32768 +CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=8192 # CONFIG_LWIP_NO_RX_THREAD is not set -CONFIG_LWIP_NO_TX_THREAD=y +# CONFIG_LWIP_NO_TX_THREAD is not set CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12 -CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=32768 +CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192 CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8 -CONFIG_RT_LWIP_REASSEMBLY_FRAG=y +# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set CONFIG_LWIP_NETIF_STATUS_CALLBACK=1 CONFIG_LWIP_NETIF_LINK_CALLBACK=1 CONFIG_RT_LWIP_NETIF_NAMESIZE=6 @@ -575,8 +753,8 @@ CONFIG_LWIP_SO_RCVTIMEO=1 CONFIG_LWIP_SO_SNDTIMEO=1 CONFIG_LWIP_SO_RCVBUF=1 CONFIG_LWIP_SO_LINGER=0 -CONFIG_RT_LWIP_NETIF_LOOPBACK=y -CONFIG_LWIP_NETIF_LOOPBACK=1 +# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=0 # CONFIG_RT_LWIP_STATS is not set # CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set CONFIG_RT_LWIP_USING_PING=y @@ -598,11 +776,7 @@ CONFIG_RT_LWIP_USING_PING=y # # CONFIG_RT_USING_RYM is not set # CONFIG_RT_USING_ULOG is not set -CONFIG_RT_USING_UTEST=y -CONFIG_UTEST_THR_STACK_SIZE=8192 -CONFIG_UTEST_THR_PRIORITY=20 -# CONFIG_RT_UTEST_USING_AUTO_RUN is not set -CONFIG_RT_UTEST_MAX_OPTIONS=64 +# CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_RESOURCE_ID=y CONFIG_RT_USING_ADT=y @@ -655,114 +829,14 @@ CONFIG_RT_USING_VDSO=y # end of Using USB legacy version # CONFIG_RT_USING_FDT is not set +# CONFIG_RT_USING_LEGACY_VIRTIO is not set # CONFIG_RT_USING_RUST is not set # end of RT-Thread Components # # RT-Thread Utestcases # -CONFIG_RT_USING_UTESTCASES=y - -# -# Kernel Core -# -# CONFIG_RT_UTEST_OBJECT is not set -# CONFIG_RT_UTEST_SLAB is not set -# CONFIG_RT_UTEST_IRQ is not set -# CONFIG_RT_UTEST_SEMAPHORE is not set -# CONFIG_RT_UTEST_EVENT is not set -# CONFIG_RT_UTEST_TIMER is not set -# CONFIG_RT_UTEST_MESSAGEQUEUE is not set -# CONFIG_RT_UTEST_SIGNAL is not set -# CONFIG_RT_UTEST_MUTEX is not set -# CONFIG_RT_UTEST_MAILBOX is not set -# CONFIG_RT_UTEST_THREAD is not set -# CONFIG_RT_UTEST_ATOMIC is not set -# CONFIG_RT_UTEST_HOOKLIST is not set -# CONFIG_RT_UTEST_MTSAFE_KPRINT is not set -CONFIG_RT_UTEST_SCHEDULER=y -# CONFIG_RT_UTEST_SYS_PERF is not set -# CONFIG_RT_UTEST_TC_USING_KLIBC is not set - -# -# SMP Test -# -# CONFIG_RT_UTEST_SMP_AFFFINITY is not set -# CONFIG_RT_UTEST_SMP_ASSIGNED_IDLE_CORE is not set -# CONFIG_RT_UTEST_SMP_INTERRUPT_PRI is not set -# CONFIG_RT_UTEST_SMP_SPINLOCK is not set -# CONFIG_RT_UTEST_SMP_THREAD_PREEMPTION is not set -# end of SMP Test -# end of Kernel Core - -# -# Kernel Components -# - -# -# Drivers -# -# CONFIG_RT_UTEST_DRIVERS_CORE is not set - -# -# IPC Test -# -# CONFIG_RT_UTEST_COMPLETION is not set -# CONFIG_RT_UTEST_WORKQUEUE is not set -# end of IPC Test - -# -# Serial Test -# -# CONFIG_RT_UTEST_SERIAL_BYPASS is not set -# end of Serial Test - -# -# SMP-Call Test -# -# CONFIG_RT_UTEST_SMP_CALL_FUNC is not set -# end of SMP-Call Test -# end of Drivers - -# -# File System -# -# CONFIG_RT_UTEST_TC_USING_DFS_API is not set -# end of File System - -# -# CPP11 -# -# CONFIG_RT_UTEST_CPP11_THREAD is not set -# end of CPP11 - -# -# Network -# -# CONFIG_RT_UTEST_TC_USING_SAL is not set -# CONFIG_RT_UTEST_TC_USING_NETDEV is not set -# CONFIG_RT_UTEST_TC_USING_LWIP is not set -# end of Network - -# -# Utest Framework -# -# CONFIG_RT_UTEST_SELF_PASS is not set -# end of Utest Framework -# end of Kernel Components - -# -# Memory Management Subsytem Testcase -# -# CONFIG_RT_UTEST_MM_API is not set -# CONFIG_RT_UTEST_MM_LWP is not set -# end of Memory Management Subsytem Testcase - -# -# Tmpfs Testcase -# -# CONFIG_RT_UTEST_TMPFS_CP is not set -# end of Tmpfs Testcase +# CONFIG_RT_USING_UTESTCASES is not set # end of RT-Thread Utestcases # @@ -958,7 +1032,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_U8G2 is not set # end of u8g2: a monochrome graphic library -# CONFIG_PKG_USING_NES_SIMULATOR is not set # CONFIG_PKG_USING_OPENMV is not set # CONFIG_PKG_USING_MUPDF is not set # CONFIG_PKG_USING_STEMWIN is not set @@ -983,9 +1056,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # # tools packages # -# CONFIG_PKG_USING_VECTOR is not set -# CONFIG_PKG_USING_SORCH is not set -# CONFIG_PKG_USING_DICT is not set # CONFIG_PKG_USING_CMBACKTRACE is not set # CONFIG_PKG_USING_MCOREDUMP is not set # CONFIG_PKG_USING_EASYFLASH is not set @@ -1034,9 +1104,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_RVBACKTRACE is not set # CONFIG_PKG_USING_HPATCHLITE is not set # CONFIG_PKG_USING_THREAD_METRIC is not set -# CONFIG_PKG_USING_UORB is not set -# CONFIG_PKG_USING_RT_TUNNEL is not set -# CONFIG_PKG_USING_VIRTUAL_TERMINAL is not set # end of tools packages # @@ -1131,9 +1198,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_R_RHEALSTONE is not set # CONFIG_PKG_USING_HEARTBEAT is not set # CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set -# CONFIG_PKG_USING_CHERRYECAT is not set -# CONFIG_PKG_USING_EVENT_LOOP is not set -# CONFIG_PKG_USING_THREAD_MANAGER is not set # end of system packages # @@ -1279,7 +1343,9 @@ CONFIG_RT_UTEST_SCHEDULER=y # # NUVOTON Drivers # +# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set # CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set # end of NUVOTON Drivers # @@ -1287,24 +1353,7 @@ CONFIG_RT_UTEST_SCHEDULER=y # # CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set # CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32_RISCV_SERIES_DRIVER is not set -# CONFIG_PKG_USING_GD32VW55X_WIFI is not set # end of GD32 Drivers - -# -# HPMicro SDK -# -# CONFIG_PKG_USING_HPM_SDK is not set -# end of HPMicro SDK - -# -# FT32 HAL & SDK Drivers -# -# CONFIG_PKG_USING_FT32F0_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F0_CMSIS_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_STD_DRIVER is not set -# CONFIG_PKG_USING_FT32F4_CMSIS_DRIVER is not set -# end of FT32 HAL & SDK Drivers # end of HAL & SDK Drivers # @@ -1350,11 +1399,9 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_RT3020 is not set # CONFIG_PKG_USING_MLX90632 is not set # CONFIG_PKG_USING_MLX90382 is not set -# CONFIG_PKG_USING_MLX90384 is not set # CONFIG_PKG_USING_MLX90393 is not set # CONFIG_PKG_USING_MLX90392 is not set # CONFIG_PKG_USING_MLX90394 is not set -# CONFIG_PKG_USING_MLX90396 is not set # CONFIG_PKG_USING_MLX90397 is not set # CONFIG_PKG_USING_MS5611 is not set # CONFIG_PKG_USING_MAX31865 is not set @@ -1383,7 +1430,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_P3T1755 is not set # CONFIG_PKG_USING_QMI8658 is not set # CONFIG_PKG_USING_ICM20948 is not set -# CONFIG_PKG_USING_SCD4X is not set # end of sensors drivers # @@ -1401,7 +1447,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_CST812T is not set # end of touch drivers -# CONFIG_PKG_USING_LCD_SPI_DRIVER is not set # CONFIG_PKG_USING_REALTEK_AMEBA is not set # CONFIG_PKG_USING_BUTTON is not set # CONFIG_PKG_USING_PCF8574 is not set @@ -1481,13 +1526,6 @@ CONFIG_RT_UTEST_SCHEDULER=y # CONFIG_PKG_USING_IC74HC165 is not set # CONFIG_PKG_USING_IST8310 is not set # CONFIG_PKG_USING_ST7789_SPI is not set -# CONFIG_PKG_USING_CAN_UDS is not set -# CONFIG_PKG_USING_ISOTP_C is not set -# CONFIG_PKG_USING_IKUNLED is not set -# CONFIG_PKG_USING_INS5T8025 is not set -# CONFIG_PKG_USING_IRUART is not set -# CONFIG_PKG_USING_ST7305 is not set -# CONFIG_PKG_USING_TM1668 is not set # CONFIG_PKG_USING_SPI_TOOLS is not set # end of peripheral libraries and drivers @@ -1827,11 +1865,4 @@ CONFIG_RT_UTEST_SCHEDULER=y # end of Arduino libraries # end of RT-Thread online packages -CONFIG_BCM2711_SOC=y - -# -# Hardware Drivers Config -# -CONFIG_BSP_USING_PL011=y -CONFIG_BSP_USING_SDHCI=y -# end of Hardware Drivers Config +CONFIG_SOC_BCM2712=y diff --git a/bsp/raspberry-pi/raspi-dm2.0/Kconfig b/bsp/raspberry-pi/raspi5/Kconfig old mode 100644 new mode 100755 similarity index 74% rename from bsp/raspberry-pi/raspi-dm2.0/Kconfig rename to bsp/raspberry-pi/raspi5/Kconfig index f62b1758e9..424bd6f235 --- a/bsp/raspberry-pi/raspi-dm2.0/Kconfig +++ b/bsp/raspberry-pi/raspi5/Kconfig @@ -6,17 +6,18 @@ RTT_DIR := ../../.. PKGS_DIR := packages +SOC_DM_DIR := $BSP_DIR/../dm/ + +source "$(SOC_DM_DIR)/Kconfig" source "$(RTT_DIR)/Kconfig" osource "$PKGS_DIR/Kconfig" -config BCM2711_SOC +config SOC_BCM2712 bool select ARCH_ARMV8 - select ARCH_ARM_MMU - select RT_USING_CACHE select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN select ARCH_CPU_64BIT + select RT_USING_CACHE + select RT_USING_STDC_ATOMIC default y - -rsource "drivers/Kconfig" diff --git a/bsp/raspberry-pi/raspi5/README.md b/bsp/raspberry-pi/raspi5/README.md new file mode 100644 index 0000000000..6a40a90509 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/README.md @@ -0,0 +1,217 @@ +# Raspberry Pi 5 BSP 使用说明 + +[English](README_en.md) + +## 1. 简介 + +本 BSP 为 Raspberry Pi 5 提供 RT-Thread 64 位板级支持,目标 SoC 为 Broadcom BCM2712(4 核 Cortex-A76),并使用 RT-Thread Device Model 管理板载设备及 RP1 南桥外设。 + +当前启动流程为:Raspberry Pi 固件加载 U-Boot,U-Boot 再加载 `rtthread.bin`,并将固件提供的设备树传递给 RT-Thread。BSP 默认启用 SMP,控制台设备为设备树中的 `uart10`。 + +## 2. 准备工作 + +### 2.1 硬件 + +- Raspberry Pi 5; +- microSD 卡及读卡器; +- 3.3 V TTL 串口工具; +- 可选:用于 TFTP 启动的有线网络。 + +> 串口电平必须为 3.3 V,请勿直接连接 RS-232 或 5 V 串口。默认波特率为 `115200 8N1`,关闭硬件和软件流控。 + +### 2.2 软件 + +- Python 3; +- SCons 及 RT-Thread Env 工具; +- AArch64 bare-metal GCC 工具链; +- 适用于 Raspberry Pi 5 的 U-Boot; +- 可选:TFTP 服务器。 + +默认工具链前缀为 `aarch64-none-elf-`,`rtconfig.py` 中的默认搜索路径为: + +```text +/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-elf/bin/ +``` + +推荐通过环境变量指定本机工具链,避免修改仓库文件: + +```bash +export RTT_EXEC_PATH=/path/to/aarch64-toolchain/bin +export RTT_CC_PREFIX=aarch64-none-elf- +``` + +编译脚本优先使用 `-mtune=cortex-a76`;旧工具链不支持时,会依次回退到 `cortex-a73` 或 `generic`。 + +## 3. 配置与编译 + +进入 BSP 目录: + +```bash +cd bsp/raspberry-pi/raspi5 +``` + +如需调整功能,可先打开配置菜单: + +```bash +scons --menuconfig +``` + +编译 BSP: + +```bash +scons -j$(nproc) +``` + +Windows 环境可直接使用 `scons`,或将 `$(nproc)` 替换为合适的并行任务数。 + +成功后会生成: + +| 文件 | 说明 | +| --- | --- | +| `rtthread.elf` | 带符号信息的 ELF 文件,用于调试和反汇编 | +| `rtthread.bin` | U-Boot 实际加载的裸二进制镜像 | +| `rtthread.map` | 链接映射文件 | +| `rtt.asm` | 反汇编结果 | + +`rtthread.bin` 的加载地址为 `0x210000`,与默认配置中的 `ARCH_TEXT_OFFSET` 一致,请勿随意修改启动命令中的地址。 + +## 4. 准备启动介质 + +### 4.1 准备 U-Boot + +先准备一张能够由 Raspberry Pi 5 固件正常识别的 microSD 卡。将适用于 Raspberry Pi 5 的 U-Boot 镜像放到 FAT 启动分区根目录,并命名为: + +```text +u-boot.bin +``` + +本目录的 [`tools/config.txt`](tools/config.txt) 包含 BSP 所需的最小固件配置: + +```ini +kernel=u-boot.bin +dtparam=pciex1 +``` + +如果启动分区已经存在 `config.txt`,请合并上述配置,不要直接覆盖其中仍需保留的显示、串口或其他板级设置。 + +### 4.2 放置 RT-Thread 镜像 + +使用 SD 卡启动时,将编译生成的 `rtthread.bin` 复制到第一个 FAT 分区的根目录: + +```text +/rtthread.bin +``` + +默认命令使用 U-Boot 的 `mmc 0:1`。如果实际 SD 卡控制器或分区编号不同,请先用以下命令确认: + +```text +mmc list +mmc dev 0 +part list mmc 0 +fatls mmc 0:1 +``` + +## 5. U-Boot 启动 + +### 5.1 设置公共启动参数 + +在 U-Boot 控制台设置 RT-Thread 使用的启动参数: + +```text +setenv bootargs_rtt 'earlycon cma=8M coherent_pool=2M' +saveenv +``` + +启动命令会复制固件提供的活动设备树,并更新 `/chosen/bootargs`。不要使用与当前开发板不匹配的静态 DTB 替代该设备树,否则 RP1、PCIe 和板载外设信息可能不完整。 + +### 5.2 从 SD 卡加载 + +```text +setenv bootrtt 'mmc dev 0; fatload mmc 0:1 0x210000 rtthread.bin; fdt addr ${fdtcontroladdr}; fdt move ${fdt_addr_r} 0x20000; fdt addr ${fdt_addr_r}; fdt resize 8192; setenv bootargs ${bootargs_rtt}; fdt set /chosen bootargs ${bootargs}; booti 0x210000 - ${fdt_addr_r}' +saveenv +run bootrtt +``` + +如需每次上电自动启动,可在确认手动启动正常后设置: + +```text +setenv bootcmd 'run bootrtt' +saveenv +``` + +### 5.3 从 TFTP 加载 + +先将 `rtthread.bin` 放到 TFTP 服务器根目录。下面地址仅为示例,请根据实际网络修改: + +```text +setenv bootrtt_tftp 'setenv ethprime eth0; setenv ipaddr 192.168.10.2; setenv serverip 192.168.10.1; setenv netmask 255.255.255.0; ping 192.168.10.1; tftp 0x210000 rtthread.bin; fdt addr ${fdtcontroladdr}; fdt move ${fdt_addr_r} 0x20000; fdt addr ${fdt_addr_r}; fdt resize 8192; setenv bootargs ${bootargs_rtt}; fdt set /chosen bootargs ${bootargs}; booti 0x210000 - ${fdt_addr_r}' +saveenv +run bootrtt_tftp +``` + +如果 U-Boot 中的有线网卡名称不是 `eth0`,可通过 `printenv ethact ethprime` 或 `bdinfo` 检查后调整 `ethprime`。 + +## 6. 启动结果 + +启动成功后,串口应出现 RT-Thread 标志、SMP 初始化信息,随后进入 MSH: + +```text + \ | / +- RT - Thread Operating System + / | \ + 2006 - 2026 Copyright by RT-Thread team +Hi, this is RT-Thread!! +msh /> +``` + +实际版本号、构建时间和设备初始化日志会随配置变化。 + +## 7. 默认配置 + +默认 `rtconfig.h` 启用了以下主要功能。是否能探测到具体设备,仍取决于 Raspberry Pi 固件版本、活动设备树、扩展板和外设连接情况。 + +| 类别 | 默认配置中的主要支持 | +| --- | --- | +| CPU | AArch64、4 核 SMP、MMU、Cache、ASID | +| 控制台 | PL011/8250 串口,默认 `uart10` | +| 存储 | SDHCI/MMC、FatFs、NVMe over PCIe | +| 网络 | RP1 以太网、PHY、lwIP、DHCP | +| 总线 | PCIe、I2C、SPI、SDIO、Device Tree/OFW | +| RP1 外设 | ADC、PWM、GPIO/Pinctrl、时钟、MFD | +| 系统服务 | RTC、Watchdog、DMA、Thermal、DVFS、Mailbox | +| 多媒体与输入 | I2S Audio、Framebuffer、Touchscreen、Joystick、Keyboard | +| 用户态 | RT-Smart、DFS、POSIX、LWP、动态链接支持 | + +## 8. 常见问题 + +### 8.1 U-Boot 找不到 `rtthread.bin` + +先执行: + +```text +fatls mmc 0:1 +``` + +确认文件名、设备号和分区号。Linux 文件名区分大小写。 + +### 8.2 `Bad Linux ARM64 Image magic!` 或跳转后无输出 + +- 确认加载的是 `rtthread.bin`,而不是 `rtthread.elf`; +- 确认加载及启动地址均为 `0x210000`; +- 确认使用 `booti 0x210000 - ${fdt_addr_r}`; +- 检查串口参数以及设备树中的 `stdout-path`。 + +### 8.3 设备树或 RP1 外设初始化失败 + +- 确认 Raspberry Pi 固件和 U-Boot 支持 Raspberry Pi 5; +- 确认 `config.txt` 中包含 `dtparam=pciex1`; +- 保留并传递固件提供的活动设备树; +- 不要在 U-Boot 中覆盖成其他 Raspberry Pi 型号的 DTB。 + +### 8.4 TFTP 下载失败 + +检查 `ipaddr`、`serverip`、`netmask`、TFTP 根目录、防火墙和网线连接,并先在 U-Boot 中执行 `ping ${serverip}`。 + +## 9. 重新配置后的注意事项 + +运行 `scons --menuconfig` 后,配置可能与本文记录的默认 `rtconfig.h` 不同。提交 BSP 配置变更前,应同时检查生成的 `rtconfig.h`,并确认新增驱动在 Raspberry Pi 5 实机上完成验证。 diff --git a/bsp/raspberry-pi/raspi5/README_en.md b/bsp/raspberry-pi/raspi5/README_en.md new file mode 100644 index 0000000000..83d124fc18 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/README_en.md @@ -0,0 +1,217 @@ +# Raspberry Pi 5 BSP User Guide + +[中文](README.md) + +## 1. Introduction + +This BSP provides 64-bit RT-Thread support for Raspberry Pi 5. It targets the Broadcom BCM2712 SoC, which contains four Cortex-A76 cores, and uses the RT-Thread Device Model to manage on-board devices and RP1 southbridge peripherals. + +The current boot flow is: Raspberry Pi firmware loads U-Boot, U-Boot loads `rtthread.bin`, and the firmware-provided device tree is passed to RT-Thread. SMP is enabled by default, and the default console device is `uart10` from the device tree. + +## 2. Prerequisites + +### 2.1 Hardware + +- Raspberry Pi 5; +- A microSD card and card reader; +- A 3.3 V TTL serial adapter; +- Optional: a wired network for TFTP boot. + +> The serial interface must use 3.3 V levels. Do not connect an RS-232 or 5 V serial adapter directly. The default serial settings are `115200 8N1`, with hardware and software flow control disabled. + +### 2.2 Software + +- Python 3; +- SCons and the RT-Thread Env tools; +- An AArch64 bare-metal GCC toolchain; +- A Raspberry Pi 5-compatible U-Boot image; +- Optional: a TFTP server. + +The default toolchain prefix is `aarch64-none-elf-`. The default search path in `rtconfig.py` is: + +```text +/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-elf/bin/ +``` + +Using environment variables is recommended so that repository files do not need to be modified: + +```bash +export RTT_EXEC_PATH=/path/to/aarch64-toolchain/bin +export RTT_CC_PREFIX=aarch64-none-elf- +``` + +The build script prefers `-mtune=cortex-a76`. If an older compiler does not support it, the script falls back to `cortex-a73` and then `generic`. + +## 3. Configuration and Build + +Enter the BSP directory: + +```bash +cd bsp/raspberry-pi/raspi5 +``` + +To change the default configuration, open menuconfig first: + +```bash +scons --menuconfig +``` + +Build the BSP: + +```bash +scons -j$(nproc) +``` + +On Windows, run `scons` directly or replace `$(nproc)` with a suitable number of parallel jobs. + +A successful build produces: + +| File | Description | +| --- | --- | +| `rtthread.elf` | ELF image with symbols for debugging and disassembly | +| `rtthread.bin` | Raw binary image loaded by U-Boot | +| `rtthread.map` | Linker map | +| `rtt.asm` | Disassembly output | + +The load address of `rtthread.bin` is `0x210000`, matching `ARCH_TEXT_OFFSET` in the default configuration. Do not change this address in the boot commands without updating the BSP configuration accordingly. + +## 4. Preparing the Boot Media + +### 4.1 Preparing U-Boot + +Prepare a microSD card that can be recognized by the Raspberry Pi 5 firmware. Place a Raspberry Pi 5-compatible U-Boot image in the root of the FAT boot partition and name it: + +```text +u-boot.bin +``` + +The [`tools/config.txt`](tools/config.txt) file contains the minimum firmware configuration required by this BSP: + +```ini +kernel=u-boot.bin +dtparam=pciex1 +``` + +If the boot partition already contains a `config.txt`, merge these settings into it. Do not overwrite display, serial, or other board-specific settings that are still required. + +### 4.2 Copying the RT-Thread Image + +For SD card boot, copy the generated `rtthread.bin` to the root of the first FAT partition: + +```text +/rtthread.bin +``` + +The default commands use U-Boot device and partition `mmc 0:1`. If your SD controller or partition number differs, inspect it first: + +```text +mmc list +mmc dev 0 +part list mmc 0 +fatls mmc 0:1 +``` + +## 5. Booting from U-Boot + +### 5.1 Common Boot Arguments + +Set the RT-Thread boot arguments at the U-Boot console: + +```text +setenv bootargs_rtt 'earlycon cma=8M coherent_pool=2M' +saveenv +``` + +The boot commands copy the live device tree provided by the firmware and update `/chosen/bootargs`. Do not replace it with a static DTB for another board revision or Raspberry Pi model, because RP1, PCIe, and on-board peripheral information may be incomplete. + +### 5.2 Booting from the SD Card + +```text +setenv bootrtt 'mmc dev 0; fatload mmc 0:1 0x210000 rtthread.bin; fdt addr ${fdtcontroladdr}; fdt move ${fdt_addr_r} 0x20000; fdt addr ${fdt_addr_r}; fdt resize 8192; setenv bootargs ${bootargs_rtt}; fdt set /chosen bootargs ${bootargs}; booti 0x210000 - ${fdt_addr_r}' +saveenv +run bootrtt +``` + +After manual boot has been verified, enable automatic boot if desired: + +```text +setenv bootcmd 'run bootrtt' +saveenv +``` + +### 5.3 Booting over TFTP + +Place `rtthread.bin` in the TFTP server root. The addresses below are examples and must be adjusted for your network: + +```text +setenv bootrtt_tftp 'setenv ethprime eth0; setenv ipaddr 192.168.10.2; setenv serverip 192.168.10.1; setenv netmask 255.255.255.0; ping 192.168.10.1; tftp 0x210000 rtthread.bin; fdt addr ${fdtcontroladdr}; fdt move ${fdt_addr_r} 0x20000; fdt addr ${fdt_addr_r}; fdt resize 8192; setenv bootargs ${bootargs_rtt}; fdt set /chosen bootargs ${bootargs}; booti 0x210000 - ${fdt_addr_r}' +saveenv +run bootrtt_tftp +``` + +If the U-Boot Ethernet device is not named `eth0`, inspect `printenv ethact ethprime` or `bdinfo` and adjust `ethprime`. + +## 6. Expected Output + +After a successful boot, the serial console should display the RT-Thread banner and SMP initialization messages before entering MSH: + +```text + \ | / +- RT - Thread Operating System + / | \ + 2006 - 2026 Copyright by RT-Thread team +Hi, this is RT-Thread!! +msh /> +``` + +The exact version, build time, and device initialization messages depend on the active configuration. + +## 7. Default Configuration + +The default `rtconfig.h` enables the major features listed below. Whether a particular device is detected still depends on the Raspberry Pi firmware version, live device tree, expansion boards, and connected peripherals. + +| Category | Major features enabled by default | +| --- | --- | +| CPU | AArch64, four-core SMP, MMU, cache, and ASID | +| Console | PL011/8250 serial drivers; `uart10` is the default console | +| Storage | SDHCI/MMC, FatFs, and NVMe over PCIe | +| Networking | RP1 Ethernet, PHY support, lwIP, and DHCP | +| Buses | PCIe, I2C, SPI, SDIO, and Device Tree/OFW | +| RP1 peripherals | ADC, PWM, GPIO/pinctrl, clocks, and MFD | +| System services | RTC, watchdog, DMA, thermal control, DVFS, and mailbox | +| Multimedia and input | I2S audio, framebuffer, touchscreen, joystick, and keyboard | +| User space | RT-Smart, DFS, POSIX, LWP, and dynamic linking | + +## 8. Troubleshooting + +### 8.1 U-Boot Cannot Find `rtthread.bin` + +Run: + +```text +fatls mmc 0:1 +``` + +Check the filename, device number, and partition number. Linux filenames are case-sensitive. + +### 8.2 `Bad Linux ARM64 Image magic!` or No Output After Jumping + +- Make sure `rtthread.bin`, not `rtthread.elf`, was loaded; +- Make sure both the load and boot addresses are `0x210000`; +- Make sure the command is `booti 0x210000 - ${fdt_addr_r}`; +- Check the serial settings and `stdout-path` in the device tree. + +### 8.3 Device Tree or RP1 Peripheral Initialization Fails + +- Make sure the Raspberry Pi firmware and U-Boot support Raspberry Pi 5; +- Make sure `config.txt` contains `dtparam=pciex1`; +- Preserve and pass the live device tree provided by the firmware; +- Do not replace it in U-Boot with a DTB for another Raspberry Pi model. + +### 8.4 TFTP Download Fails + +Check `ipaddr`, `serverip`, `netmask`, the TFTP root, the host firewall, and the Ethernet connection. Run `ping ${serverip}` in U-Boot before downloading the image. + +## 9. Notes After Reconfiguration + +After running `scons --menuconfig`, the active configuration may differ from the default `rtconfig.h` documented here. Before submitting BSP configuration changes, inspect the generated `rtconfig.h` and verify newly enabled drivers on Raspberry Pi 5 hardware. diff --git a/bsp/raspberry-pi/raspi5/SConscript b/bsp/raspberry-pi/raspi5/SConscript new file mode 100755 index 0000000000..3b4078130e --- /dev/null +++ b/bsp/raspberry-pi/raspi5/SConscript @@ -0,0 +1,17 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +objs = objs + SConscript(cwd + '/../dm/SConscript', variant_dir = 'dm', duplicate = 0) + +Return('objs') + \ No newline at end of file diff --git a/bsp/raspberry-pi/raspi-dm2.0/SConstruct b/bsp/raspberry-pi/raspi5/SConstruct old mode 100644 new mode 100755 similarity index 58% rename from bsp/raspberry-pi/raspi-dm2.0/SConstruct rename to bsp/raspberry-pi/raspi5/SConstruct index 55cab35463..ec6fe0187f --- a/bsp/raspberry-pi/raspi-dm2.0/SConstruct +++ b/bsp/raspberry-pi/raspi5/SConstruct @@ -11,20 +11,19 @@ TARGET = 'rtthread.' + rtconfig.TARGET_EXT DefaultEnvironment(tools=[]) env = Environment(tools = ['mingw'], - AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, - CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, - CPP = rtconfig.CPP, CXXFLAGS = rtconfig.CXXFLAGS, - AR = rtconfig.AR, ARFLAGS = '-rc', + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) env.PrependENVPath('PATH', rtconfig.EXEC_PATH) env['ASCOM'] = env['ASPPCOM'] -env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS -Wl,--start-group $_LIBFLAGS -Wl,--end-group' Export('RTT_ROOT') Export('rtconfig') # prepare building environment -objs = PrepareBuilding(env, RTT_ROOT) +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) # make a building DoBuilding(TARGET, objs) diff --git a/bsp/raspberry-pi/raspi5/applications/SConscript b/bsp/raspberry-pi/raspi5/applications/SConscript new file mode 100755 index 0000000000..c583d3016e --- /dev/null +++ b/bsp/raspberry-pi/raspi5/applications/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/raspi5/applications/main.c b/bsp/raspberry-pi/raspi5/applications/main.c new file mode 100644 index 0000000000..b54235ce9b --- /dev/null +++ b/bsp/raspberry-pi/raspi5/applications/main.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017-05-30 bernard the first version + */ + +#include + +int main(int argc, char **argv) +{ + rt_kprintf("Hi, this is RT-Thread!!\n"); + + return 0; +} diff --git a/bsp/raspberry-pi/raspi5/drivers/SConscript b/bsp/raspberry-pi/raspi5/drivers/SConscript new file mode 100755 index 0000000000..f7e8f47ce8 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/drivers/SConscript @@ -0,0 +1,12 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] +objs = [] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/raspberry-pi/raspi5/drivers/board.c b/bsp/raspberry-pi/raspi5/drivers/board.c new file mode 100755 index 0000000000..5283c37f53 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/drivers/board.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include +#include +#include + +void rt_hw_board_init(void) +{ + rt_hw_common_setup(); +} + +/* + * Several root-level nodes reference RP1 GPIO in the live DT. + * Resolving that phandle from an early driver probe calls rt_platform_ofw_request() + * on the RP1 subtree before PCIe has enumerated the RP1 device. + * + * Mark those nodes unavailable at INIT_CORE (before platform_ofw / early probes), + * then restore them later once platform init has passed the RP1 bring-up window. + */ +static struct rt_ofw_prop *cam0_status_prop = RT_NULL; +static struct rt_ofw_prop *cam1_status_prop = RT_NULL; +static struct rt_ofw_prop *leds_status_prop = RT_NULL; + +static void ofw_status_mark(const char *path, struct rt_ofw_prop **status_prop, + const char *status) +{ + struct rt_ofw_node *np; + rt_size_t len = rt_strlen(status) + 1; + + if (!(np = rt_ofw_find_node_by_path(path))) + { + return; + } + + if (!(*status_prop = rt_ofw_get_prop(np, "status", RT_NULL))) + { + if (rt_ofw_append_prop(np, "status", len, (void *)status)) + { + rt_kprintf("append prop status failed on %s\n", path); + RT_ASSERT(0); + } + + *status_prop = rt_ofw_get_prop(np, "status", RT_NULL); + } + + if (*status_prop) + { + (*status_prop)->value = (char *)status; + (*status_prop)->length = len; + } + + rt_ofw_node_put(np); +} + +static int early_rp1_consumer_disable(void) +{ + ofw_status_mark("/cam0_reg", &cam0_status_prop, "disabled"); + ofw_status_mark("/cam1_reg", &cam1_status_prop, "disabled"); + ofw_status_mark("/leds", &leds_status_prop, "disabled"); + + return RT_EOK; +} +INIT_CORE_EXPORT(early_rp1_consumer_disable); + +static struct rt_ofw_prop *fb_status_prop = RT_NULL; + +#ifdef RT_GRAPHIC_FB_BCM2708 +static int legacy_framebuffer_enable(void) +{ + ofw_status_mark("/soc/fb", &fb_status_prop, "okay"); + + return RT_EOK; +} +INIT_CORE_EXPORT(legacy_framebuffer_enable); +#endif /* RT_GRAPHIC_FB_BCM2708 */ + +static int cam_regulator_enable(void) +{ + ofw_status_mark("/cam0_reg", &cam0_status_prop, "okay"); + ofw_status_mark("/cam1_reg", &cam1_status_prop, "okay"); + + return RT_EOK; +} +INIT_PREV_EXPORT(cam_regulator_enable); + +/* + * /leds is kept out of the INIT_PLATFORM scan above. After INIT_DEVICE, only + * register it once mfd.rp1 has published the RP1 PIC on the OFW node; otherwise + * gpio-leds would pull the RP1 subtree in via GPIO phandle (Path B). + */ +static int leds_init(void) +{ + struct rt_ofw_node *np; + + ofw_status_mark("/leds", &leds_status_prop, "okay"); + + if (!(np = rt_ofw_find_node_by_path("/leds"))) + { + return RT_EOK; + } + + rt_platform_ofw_request(np); + rt_ofw_node_put(np); + + return RT_EOK; +} +INIT_EXPORT(leds_init, "3.1"); diff --git a/bsp/raspberry-pi/raspi5/drivers/board.h b/bsp/raspberry-pi/raspi5/drivers/board.h new file mode 100755 index 0000000000..87ec007d29 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/drivers/board.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +void rt_hw_board_init(void); + +#endif /* __BOARD_H__ */ diff --git a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h b/bsp/raspberry-pi/raspi5/rtconfig.h old mode 100644 new mode 100755 similarity index 70% rename from bsp/raspberry-pi/raspi-dm2.0/rtconfig.h rename to bsp/raspberry-pi/raspi5/rtconfig.h index 634c26b675..0ee061d2f1 --- a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h +++ b/bsp/raspberry-pi/raspi5/rtconfig.h @@ -8,16 +8,6 @@ /* rt_vsnprintf options */ #define RT_KLIBC_USING_VSNPRINTF_LONGLONG -#define RT_KLIBC_USING_VSNPRINTF_STANDARD -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6 -#define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 -#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4 /* end of rt_vsnprintf options */ /* rt_vsscanf options */ @@ -72,24 +62,24 @@ /* end of rt_strnlen options */ /* end of klibc options */ -#define RT_NAME_MAX 12 +#define RT_NAME_MAX 24 #define RT_USING_SMART #define RT_USING_SMP #define RT_CPUS_NR 4 -#define RT_ALIGN_SIZE 4 +#define RT_ALIGN_SIZE 8 #define RT_THREAD_PRIORITY_32 #define RT_THREAD_PRIORITY_MAX 32 -#define RT_TICK_PER_SECOND 1000 +#define RT_TICK_PER_SECOND 100 #define RT_USING_OVERFLOW_CHECK #define RT_USING_HOOK #define RT_HOOK_USING_FUNC_PTR #define RT_USING_IDLE_HOOK #define RT_IDLE_HOOK_LIST_SIZE 4 -#define IDLE_THREAD_STACK_SIZE 16384 -#define SYSTEM_THREAD_STACK_SIZE 16384 +#define IDLE_THREAD_STACK_SIZE 8192 +#define SYSTEM_THREAD_STACK_SIZE 8192 #define RT_USING_TIMER_SOFT #define RT_TIMER_THREAD_PRIO 4 -#define RT_TIMER_THREAD_STACK_SIZE 16384 +#define RT_TIMER_THREAD_STACK_SIZE 8192 #define RT_USING_CPU_USAGE_TRACER #define RT_CPU_USAGE_CALC_INTERVAL_MS 200 @@ -97,8 +87,10 @@ /* end of kservice options */ #define RT_USING_DEBUG +#define RT_DEBUGING_ASSERT #define RT_DEBUGING_COLOR #define RT_DEBUGING_CONTEXT +#define RT_DEBUGING_CRITICAL /* Inter-Thread communication */ @@ -111,16 +103,21 @@ /* Memory Management */ +#define RT_USING_MEMPOOL #define RT_USING_SLAB +#define RT_USING_MEMHEAP +#define RT_MEMHEAP_FAST_MODE #define RT_USING_SLAB_AS_HEAP +#define RT_USING_HEAP_ISR #define RT_USING_HEAP /* end of Memory Management */ #define RT_USING_DEVICE #define RT_USING_DEVICE_OPS #define RT_USING_INTERRUPT_INFO +#define RT_USING_THREADSAFE_PRINTF #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 256 -#define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_CONSOLE_DEVICE_NAME "uart10" #define RT_USING_CONSOLE_OUTPUT_CTL #define RT_VER_NUM 0x50300 #define RT_USING_STDC_ATOMIC @@ -129,10 +126,11 @@ /* AArch64 Architecture Configuration */ -#define ARCH_TEXT_OFFSET 0x200000 -#define ARCH_RAM_OFFSET 0x0 -#define ARCH_SECONDARY_CPU_STACK_SIZE 65536 +#define ARCH_TEXT_OFFSET 0x210000 +#define ARCH_RAM_OFFSET 0x200000 +#define ARCH_SECONDARY_CPU_STACK_SIZE 4096 #define ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS +#define ARCH_USING_GENERIC_CPUID #define ARCH_HEAP_SIZE 0x4000000 #define ARCH_INIT_PAGE_SIZE 0x200000 /* end of AArch64 Architecture Configuration */ @@ -145,6 +143,7 @@ #define KERNEL_VADDR_START 0xffff000000000000 #define ARCH_ARMV8 #define ARCH_USING_ASID +#define ARCH_USING_HW_THREAD_SELF #define ARCH_USING_IRQ_CTX_LIST /* RT-Thread Components */ @@ -160,9 +159,9 @@ #define FINSH_THREAD_PRIORITY 20 #define FINSH_THREAD_STACK_SIZE 8192 #define FINSH_USING_HISTORY -#define FINSH_HISTORY_LINES 5 +#define FINSH_HISTORY_LINES 10 #define FINSH_USING_SYMTAB -#define FINSH_CMD_SIZE 80 +#define FINSH_CMD_SIZE 256 #define MSH_USING_BUILT_IN_COMMANDS #define FINSH_USING_DESCRIPTION #define FINSH_ARG_MAX 10 @@ -173,7 +172,7 @@ #define RT_USING_DFS #define DFS_USING_POSIX #define DFS_USING_WORKDIR -#define DFS_FD_MAX 64 +#define DFS_FD_MAX 32 #define RT_USING_DFS_V2 #define RT_USING_DFS_ELMFAT @@ -192,9 +191,8 @@ #define RT_DFS_ELM_MUTEX_TIMEOUT 3000 /* end of elm-chan's FatFs, Generic FAT Filesystem Module */ #define RT_USING_DFS_DEVFS +#define RT_USING_DFS_ROMFS #define RT_USING_DFS_PTYFS -#define RT_USING_DFS_PROCFS -#define RT_USING_DFS_TMPFS #define RT_USING_PAGECACHE /* page cache config */ @@ -215,32 +213,107 @@ #define RT_USING_DEVICE_IPC #define RT_UNAMED_PIPE_NUMBER 64 #define RT_USING_SYSTEM_WORKQUEUE -#define RT_SYSTEM_WORKQUEUE_STACKSIZE 16384 +#define RT_SYSTEM_WORKQUEUE_STACKSIZE 8192 #define RT_SYSTEM_WORKQUEUE_PRIORITY 23 #define RT_USING_SERIAL #define RT_USING_SERIAL_V1 #define RT_SERIAL_USING_DMA -#define RT_SERIAL_RB_BUFSZ 64 +#define RT_SERIAL_RB_BUFSZ 256 #define RT_USING_SERIAL_BYPASS +#define RT_SERIAL_PL011 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_BCM2835AUX +#define RT_SERIAL_8250_BCM7271 +#define RT_USING_ADC +#define RT_USING_ADC_V1 +#define RT_ADC_RP1 #define RT_USING_CLOCK_TIME +#define RT_CLOCK_TIME_ARM_ARCH +#define RT_CLOCK_TIME_BCM2835 +#define RT_USING_ETHERNET +#define RT_ETHERNET_CADENCE +#define RT_ETHERNET_CADENCE_PTP #define RT_USING_I2C #define RT_USING_I2C_BITOPS +#define RT_I2C_BCM2835 +#define RT_I2C_BRCMSTB +#define RT_USING_PHY_V2 +#define RT_PHY_BCM54213 #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM +#define RT_USING_PWM +#define RT_PWM_BCM2835 +#define RT_PWM_BRCMSTB +#define RT_PWM_RP1 #define RT_USING_RTC -#define RT_USING_SOFT_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 8192 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_DS1302 +#define RT_RTC_DS1307 +#define RT_RTC_PCF8523 +#define RT_RTC_RPI #define RT_USING_SDIO -#define RT_SDIO_STACK_SIZE 16384 +#define RT_SDIO_STACK_SIZE 8192 #define RT_SDIO_THREAD_PRIORITY 15 #define RT_MMCSD_STACK_SIZE 8192 #define RT_MMCSD_THREAD_PRIORITY 22 #define RT_MMCSD_MAX_PARTITION 16 #define RT_USING_SDHCI +#define RT_SDIO_SDHCI_BRCMSTB +#define RT_SDIO_SDHCI_IPROC #define RT_USING_SPI #define RT_USING_SPI_ISR +#define RT_SPI_BCM2835 +#define RT_SPI_BCM2835AUX #define RT_USING_WDT +#define RT_WDT_BCM2835 +#define RT_USING_AUDIO +#define RT_AUDIO_REPLAY_MP_BLOCK_SIZE 4096 +#define RT_AUDIO_REPLAY_MP_BLOCK_COUNT 2 +#define RT_AUDIO_RECORD_PIPE_SIZE 2048 +#define RT_AUDIO_BCM2835_I2S #define RT_USING_TOUCH +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_BACKLIGHT +#define RT_GRAPHIC_BACKLIGHT_RPI +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_FB_ILI9486 +#define RT_GRAPHIC_FB_SIMPLE +#define RT_GRAPHIC_FB_BCM2708 +#define RT_GRAPHIC_FB_RPISENSE +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RASPI_CLUT224 +#define RT_GRAPHIC_LOGO_RASPI_CLUT224_PATH "../dm/graphic/logo/logo-raspi-clut224.ppm" +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_RNG +#define RT_HWCRYPTO_RNG_BCM2835 +#define RT_HWCRYPTO_RNG_IPROC_RNG200 +#define RT_USING_PTP +#define RT_USING_LED +#define RT_LED_GPIO +#define RT_USING_INPUT +#define RT_INPUT_POWER +#define RT_INPUT_JOYSTICK +#define RT_INPUT_JOYSTICK_RPISENSE +#define RT_INPUT_KEYBOARD +#define RT_INPUT_KEYBOARD_GPIO +#define RT_INPUT_TOUCHSCREEN +#define RT_INPUT_TOUCHSCREEN_ADS7846 +#define RT_INPUT_TOUCHSCREEN_RASPBERRYPI_FW +#define RT_USING_MBOX +#define RT_MBOX_BCM2835 +#define RT_USING_PHYE +#define RT_PHYE_GENERIC_USB +#define RT_USING_NVME +#define RT_USING_NVME_IO_QUEUE 1 +#define RT_NVME_PCI #define RT_USING_BLK /* Partition Types */ @@ -248,22 +321,90 @@ #define RT_BLK_PARTITION_DFS #define RT_BLK_PARTITION_EFI /* end of Partition Types */ +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_RASPBERRYPI +#define RT_USING_DVFS +#define RT_USING_DVFS_EVENT +#define RT_USING_DVFS_OPP_RETRY_MAX 10 + +/* DVFS Event Drivers */ + +/* DVFS CPUfreq Drivers */ + +#define RT_DVFS_RASPBERRY_CPUFREQ + +/* DVFS Devfreq Drivers */ + +#define RT_USING_REGULATOR +#define RT_REGULATOR_FIXED +#define RT_REGULATOR_GPIO +#define RT_USING_RESET +#define RT_RESET_SIMPLE +#define RT_RESET_BRCMSTB_RESCAL +#define RT_RESET_BRCMSTB +#define RT_RESET_RASPBERRYPI /* Power Management (PM) Domains device drivers */ +#define RT_PMDOMAIN_BCM2835 +#define RT_PMDOMAIN_RASPBERRYPI /* end of Power Management (PM) Domains device drivers */ +#define RT_USING_THERMAL + +/* Thermal Sensors Drivers */ + +#define RT_THERMAL_BCM2835 +#define RT_THERMAL_BCM2711 + +/* Thermal Cool Drivers */ + +#define RT_THERMAL_COOL_DVFS +#define RT_THERMAL_COOL_PWM_FAN +#define RT_USING_DMA +#define RT_DMA_DW_AXI_DMAC +#define RT_DMA_BCM2835 +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_BCM2835_PM +#define RT_MFD_RP1 +#define RT_MFD_RPI_SENSE #define RT_USING_OFW #define RT_FDT_EARLYCON_MSG_SIZE 128 #define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 + +/* PCI Device Drivers */ + +#define RT_PCIE_BRCMSTB #define RT_USING_PIC -#define MAX_HANDLERS 256 +#define MAX_HANDLERS 1024 #define RT_PIC_ARM_GIC #define RT_PIC_ARM_GIC_MAX_NR 1 +#define RT_PIC_BCM2712_MIP +#define RT_PIC_BCM2835_INTC +#define RT_PIC_BCM2836_L1_INTC +#define RT_PIC_BRCMSTB_L2_IRQ #define RT_USING_PIN +#define RT_PIN_BCM_VIRT +#define RT_PIN_BRCMSTB +#define RT_PIN_RASPBERRYPI_EXP +#define RT_USING_PINCTRL +#define RT_PINCTRL_BCM2712 +#define RT_PINCTRL_BCM2835 +#define RT_PINCTRL_RP1 #define RT_USING_CLK +#define RT_CLK_BCM2711_DVP +#define RT_CLK_BCM2835 +#define RT_CLK_RASPBERRYPI +#define RT_CLK_RP1 /* SoC (System on Chip) Drivers */ +#define RT_SOC_BROADCOM_RASPBERRYPI_VOLTAGE_MONITOR +/* end of SoC (System on Chip) Drivers */ /* end of Device Drivers */ /* C/C++ and POSIX layer */ @@ -285,9 +426,12 @@ #define RT_USING_POSIX_DEVIO #define RT_USING_POSIX_STDIO #define RT_USING_POSIX_POLL +#define RT_USING_POSIX_SELECT +#define RT_USING_POSIX_EVENTFD #define RT_USING_POSIX_EPOLL #define RT_USING_POSIX_SIGNALFD #define RT_SIGNALFD_MAX_NUM 10 +#define RT_USING_POSIX_TIMERFD #define RT_USING_POSIX_TERMIOS #define RT_USING_POSIX_DELAY #define RT_USING_POSIX_CLOCK @@ -295,6 +439,8 @@ /* Interprocess Communication (IPC) */ +#define RT_USING_POSIX_PIPE +#define RT_USING_POSIX_PIPE_SIZE 512 /* Socket is in the 'Network' category */ @@ -321,9 +467,9 @@ #define NETDEV_IPV4 1 #define NETDEV_IPV6 0 #define RT_USING_LWIP -#define RT_USING_LWIP212 -#define RT_USING_LWIP_VER_NUM 0x20102 -#define RT_LWIP_MEM_ALIGNMENT 4 +#define RT_USING_LWIP203 +#define RT_USING_LWIP_VER_NUM 0x20003 +#define RT_LWIP_MEM_ALIGNMENT 8 #define RT_LWIP_IGMP #define RT_LWIP_ICMP #define RT_LWIP_DNS @@ -333,29 +479,27 @@ /* Static IPv4 Address */ -#define RT_LWIP_IPADDR "192.168.137.100" -#define RT_LWIP_GWADDR "192.168.137.1" +#define RT_LWIP_IPADDR "192.168.1.30" +#define RT_LWIP_GWADDR "192.168.1.1" #define RT_LWIP_MSKADDR "255.255.255.0" /* end of Static IPv4 Address */ #define RT_LWIP_UDP #define RT_LWIP_TCP #define RT_LWIP_RAW -#define RT_MEMP_NUM_NETCONN 16 +#define RT_MEMP_NUM_NETCONN 8 #define RT_LWIP_PBUF_NUM 16 #define RT_LWIP_RAW_PCB_NUM 4 -#define RT_LWIP_UDP_PCB_NUM 8 -#define RT_LWIP_TCP_PCB_NUM 8 +#define RT_LWIP_UDP_PCB_NUM 4 +#define RT_LWIP_TCP_PCB_NUM 4 #define RT_LWIP_TCP_SEG_NUM 40 -#define RT_LWIP_TCP_SND_BUF 8192 -#define RT_LWIP_TCP_WND 8192 +#define RT_LWIP_TCP_SND_BUF 8196 +#define RT_LWIP_TCP_WND 8196 #define RT_LWIP_TCPTHREAD_PRIORITY 10 #define RT_LWIP_TCPTHREAD_MBOX_SIZE 8 -#define RT_LWIP_TCPTHREAD_STACKSIZE 32768 -#define LWIP_NO_TX_THREAD +#define RT_LWIP_TCPTHREAD_STACKSIZE 8192 #define RT_LWIP_ETHTHREAD_PRIORITY 12 -#define RT_LWIP_ETHTHREAD_STACKSIZE 32768 +#define RT_LWIP_ETHTHREAD_STACKSIZE 8192 #define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 -#define RT_LWIP_REASSEMBLY_FRAG #define LWIP_NETIF_STATUS_CALLBACK 1 #define LWIP_NETIF_LINK_CALLBACK 1 #define RT_LWIP_NETIF_NAMESIZE 6 @@ -364,8 +508,7 @@ #define LWIP_SO_SNDTIMEO 1 #define LWIP_SO_RCVBUF 1 #define LWIP_SO_LINGER 0 -#define RT_LWIP_NETIF_LOOPBACK -#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_NETIF_LOOPBACK 0 #define RT_LWIP_USING_PING /* end of Network */ @@ -375,10 +518,6 @@ /* Utilities */ -#define RT_USING_UTEST -#define UTEST_THR_STACK_SIZE 8192 -#define UTEST_THR_PRIORITY 20 -#define RT_UTEST_MAX_OPTIONS 64 #define RT_USING_RESOURCE_ID #define RT_USING_ADT #define RT_USING_ADT_AVL @@ -418,59 +557,6 @@ /* RT-Thread Utestcases */ -#define RT_USING_UTESTCASES - -/* Kernel Core */ - -#define RT_UTEST_SCHEDULER - -/* SMP Test */ - -/* end of SMP Test */ -/* end of Kernel Core */ - -/* Kernel Components */ - -/* Drivers */ - - -/* IPC Test */ - -/* end of IPC Test */ - -/* Serial Test */ - -/* end of Serial Test */ - -/* SMP-Call Test */ - -/* end of SMP-Call Test */ -/* end of Drivers */ - -/* File System */ - -/* end of File System */ - -/* CPP11 */ - -/* end of CPP11 */ - -/* Network */ - -/* end of Network */ - -/* Utest Framework */ - -/* end of Utest Framework */ -/* end of Kernel Components */ - -/* Memory Management Subsytem Testcase */ - -/* end of Memory Management Subsytem Testcase */ - -/* Tmpfs Testcase */ - -/* end of Tmpfs Testcase */ /* end of RT-Thread Utestcases */ /* RT-Thread online packages */ @@ -594,14 +680,6 @@ /* GD32 Drivers */ /* end of GD32 Drivers */ - -/* HPMicro SDK */ - -/* end of HPMicro SDK */ - -/* FT32 HAL & SDK Drivers */ - -/* end of FT32 HAL & SDK Drivers */ /* end of HAL & SDK Drivers */ /* sensors drivers */ @@ -681,12 +759,6 @@ /* end of Arduino libraries */ /* end of RT-Thread online packages */ -#define BCM2711_SOC - -/* Hardware Drivers Config */ - -#define BSP_USING_PL011 -#define BSP_USING_SDHCI -/* end of Hardware Drivers Config */ +#define SOC_BCM2712 #endif diff --git a/bsp/raspberry-pi/raspi5/rtconfig.py b/bsp/raspberry-pi/raspi5/rtconfig.py new file mode 100755 index 0000000000..0d2b07daff --- /dev/null +++ b/bsp/raspberry-pi/raspi5/rtconfig.py @@ -0,0 +1,88 @@ +import os +import subprocess + +# toolchains options +ARCH ='aarch64' +CPU ='cortex-a' +CROSS_TOOL ='gcc' + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = r'../../..' + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') + +PLATFORM = 'gcc' +EXEC_PATH = r'/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-elf/bin/' + +if os.getenv('RTT_EXEC_PATH'): + EXEC_PATH = os.getenv('RTT_EXEC_PATH') + +PREFERRED_MTUNE = 'cortex-a76' +MTUNE_FALLBACKS = ('cortex-a73', 'generic') + +def _gcc_supports_mtune(cc, exec_path, march, tune): + env = os.environ.copy() + if exec_path: + env['PATH'] = exec_path + os.pathsep + env.get('PATH', '') + + try: + ret = subprocess.run( + [cc, '-march=' + march, '-mtune=' + tune, '-c', '-x', 'c', '-', '-o', os.devnull], + input=b'', + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + env=env, + check=False, + ) + return ret.returncode == 0 + except (OSError, subprocess.SubprocessError): + return False + +def resolve_mtune(cc, exec_path, preferred=PREFERRED_MTUNE, march='armv8-a', + fallbacks=MTUNE_FALLBACKS): + for tune in (preferred,) + fallbacks: + if _gcc_supports_mtune(cc, exec_path, march, tune): + if tune != preferred: + print('Note: %s does not support -mtune=%s, using -mtune=%s' % ( + cc, preferred, tune)) + return tune + return fallbacks[-1] + +BUILD = 'debug' + +if PLATFORM == 'gcc': + # toolchains + PREFIX = os.getenv('RTT_CC_PREFIX') or 'aarch64-none-elf-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + CPP = PREFIX + 'cpp' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + + MTUNE = resolve_mtune(CC, EXEC_PATH) + DEVICE = ' -march=armv8-a -mtune=%s -fdiagnostics-color=always' % MTUNE + CPPFLAGS = ' -nostdinc -undef -E -P -x assembler-with-cpp' + CFLAGS = DEVICE + ' -Wall -Wno-cpp -D_POSIX_SOURCE' + AFLAGS = ' -c' + ' -x assembler-with-cpp -D__ASSEMBLY__' + LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds' + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -O0 -ggdb' + AFLAGS += ' -ggdb' + else: + CFLAGS += ' -O2' + + CXXFLAGS = CFLAGS + +DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n' +POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' diff --git a/bsp/raspberry-pi/raspi5/tools/config.txt b/bsp/raspberry-pi/raspi5/tools/config.txt new file mode 100644 index 0000000000..6b8cc37169 --- /dev/null +++ b/bsp/raspberry-pi/raspi5/tools/config.txt @@ -0,0 +1,2 @@ +kernel=u-boot.bin +dtparam=pciex1 diff --git a/bsp/raspberry-pi/tools/sdk_dist.py b/bsp/raspberry-pi/tools/sdk_dist.py new file mode 100644 index 0000000000..1eb07fc906 --- /dev/null +++ b/bsp/raspberry-pi/tools/sdk_dist.py @@ -0,0 +1,30 @@ +import os + + +def update_dm_paths(dm_dir, dist_dir): + components_dir = os.path.join(dist_dir, 'rt-thread', 'components') + + for root, dirs, files in os.walk(dm_dir): + if 'SConscript' not in files: + continue + + sconscript_path = os.path.join(root, 'SConscript') + component_path = os.path.relpath(components_dir, root).replace(os.path.sep, '/') + with open(sconscript_path, 'r') as f: + data = f.read() + + data = data.replace('../../../../components', component_path) + + with open(sconscript_path, 'w') as f: + f.write(data) + + +def dist_do_building(BSP_ROOT, dist_dir): + from mkdist import bsp_copy_files + + dm_dir = os.path.join(os.path.dirname(dist_dir), 'dm') + + print('=> copy raspberry-pi dm') + bsp_copy_files(os.path.join(os.path.dirname(BSP_ROOT), 'dm'), + dm_dir) + update_dm_paths(dm_dir, dist_dir) diff --git a/components/drivers/dma/Kconfig b/components/drivers/dma/Kconfig index 604402ac99..9352cf192f 100644 --- a/components/drivers/dma/Kconfig +++ b/components/drivers/dma/Kconfig @@ -12,6 +12,12 @@ config RT_DMA_PL330 depends on RT_USING_RESET default n +config RT_DMA_DW_AXI_DMAC + bool "Synopsys DesignWare AXI DMA" + depends on RT_USING_DMA + depends on RT_USING_CLK + default n + if RT_USING_DMA osource "$(SOC_DM_DMA_DIR)/Kconfig" endif diff --git a/components/drivers/dma/SConscript b/components/drivers/dma/SConscript index f32d702ecc..9202ecfa6d 100644 --- a/components/drivers/dma/SConscript +++ b/components/drivers/dma/SConscript @@ -13,6 +13,9 @@ src = ['dma.c', 'dma_pool.c'] if GetDepend(['RT_DMA_PL330']): src += ['dma-pl330.c'] +if GetDepend(['RT_DMA_DW_AXI_DMAC']): + src += ['dma-dw-axi-dmac.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/dma/dma-dw-axi-dmac.c b/components/drivers/dma/dma-dw-axi-dmac.c new file mode 100644 index 0000000000..60f136915b --- /dev/null +++ b/components/drivers/dma/dma-dw-axi-dmac.c @@ -0,0 +1,1158 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-11-25 GuEe-GUI first version + */ + +#include +#include +#include +#include + +#define DBG_TAG "dma.axi" +#define DBG_LVL DBG_INFO +#include + +#define DMAC_MAX_CHANNELS 32 +#define DMAC_MAX_MASTERS 2 +#define DMAC_MAX_BLK_SIZE 0x200000 +#define DMAC_MAX_LLIS 64 +#define LLI_ALIGN 64 + +#define COMMON_REG_LEN 0x100 +#define CHAN_REG_LEN 0x100 +#define DMA_REG_MAP_CH_REF 8 + +#define DMAC_CFG 0x010 +#define DMAC_CHEN 0x018 +#define DMAC_INTSTATUS 0x030 +#define DMAC_RESET 0x058 + +#define CH_SAR 0x000 +#define CH_DAR 0x008 +#define CH_BLOCK_TS 0x010 +#define CH_CTL 0x018 +#define CH_CTL_L 0x018 +#define CH_CTL_H 0x01C +#define CH_CFG 0x020 +#define CH_CFG_L 0x020 +#define CH_CFG_H 0x024 +#define CH_LLP 0x028 +#define CH_INTSTATUS_ENA 0x080 +#define CH_INTSTATUS 0x088 +#define CH_INTSIGNAL_ENA 0x090 +#define CH_INTCLEAR 0x098 + +#define DMAC_EN_MASK RT_BIT(0) +#define INT_EN_MASK RT_BIT(1) + +#define DMAC_CHAN_EN_SHIFT 0 +#define DMAC_CHAN_EN_WE_SHIFT 8 +#define DMAC_CHAN_EN2_WE_SHIFT 16 + +#define CH_CTL_H_ARLEN_EN RT_BIT(6) +#define CH_CTL_H_ARLEN_POS 7 +#define CH_CTL_H_AWLEN_EN RT_BIT(15) +#define CH_CTL_H_AWLEN_POS 16 +#define CH_CTL_H_LLI_LAST RT_BIT(30) +#define CH_CTL_H_LLI_VALID RT_BIT(31) + +#define CH_CTL_L_DST_MSIZE_POS 18 +#define CH_CTL_L_SRC_MSIZE_POS 14 +#define CH_CTL_L_DST_WIDTH_POS 11 +#define CH_CTL_L_SRC_WIDTH_POS 8 +#define CH_CTL_L_DST_INC_POS 6 +#define CH_CTL_L_SRC_INC_POS 4 +#define CH_CTL_L_DST_MAST RT_BIT(2) +#define CH_CTL_L_SRC_MAST RT_BIT(0) + +#define CH_CFG_H_PRIORITY_POS 17 +#define CH_CFG_H_DST_PER_POS 12 +#define CH_CFG_H_SRC_PER_POS 7 +#define CH_CFG_H_HS_SEL_DST_POS 4 +#define CH_CFG_H_HS_SEL_SRC_POS 3 +#define CH_CFG_H_TT_FC_POS 0 + +#define CH_CFG2_L_SRC_PER_POS 4 +#define CH_CFG2_L_DST_PER_POS 11 +#define CH_CFG2_H_TT_FC_POS 0 +#define CH_CFG2_H_HS_SEL_SRC_POS 3 +#define CH_CFG2_H_HS_SEL_DST_POS 4 +#define CH_CFG2_H_PRIORITY_POS 20 + +#define CH_CFG_L_DST_MULTBLK_TYPE_POS 2 +#define CH_CFG_L_SRC_MULTBLK_TYPE_POS 0 + +#define DWAXIDMAC_ARWLEN_MIN 0 +#define DWAXIDMAC_ARWLEN_MAX 255 + +#define DWAXIDMAC_BURST_TRANS_LEN_1 0 +#define DWAXIDMAC_BURST_TRANS_LEN_4 1 +#define DWAXIDMAC_BURST_TRANS_LEN_8 2 +#define DWAXIDMAC_BURST_TRANS_LEN_16 3 + +#define DWAXIDMAC_CH_CTL_L_INC 0 +#define DWAXIDMAC_CH_CTL_L_NOINC 1 + +#define DWAXIDMAC_HS_SEL_HW 0 +#define DWAXIDMAC_HS_SEL_SW 1 + +#define DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC 0 +#define DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC 1 +#define DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC 2 +#define DWAXIDMAC_TT_FC_MEM_TO_PER_DST 5 +#define DWAXIDMAC_TT_FC_PER_TO_MEM_SRC 4 + +#define DWAXIDMAC_MBLK_TYPE_LL 3 + +#define DWAXIDMAC_IRQ_DMA_TRF RT_BIT(1) +#define DWAXIDMAC_IRQ_ALL_ERR (RT_GENMASK(21, 16) | RT_GENMASK(14, 5)) +#define DWAXIDMAC_IRQ_ALL RT_GENMASK(31, 0) +#define DWAXIDMAC_IRQ_NONE 0 + +#define DWAXIDMAC_TRANS_WIDTH_MAX 7 + +rt_packed(struct axi_dma_lli { + rt_uint64_t sar; + rt_uint64_t dar; + rt_uint32_t block_ts_lo; + rt_uint32_t block_ts_hi; + rt_uint64_t llp; + rt_uint32_t ctl_lo; + rt_uint32_t ctl_hi; + rt_uint32_t sstat; + rt_uint32_t dstat; + rt_uint32_t status_lo; + rt_uint32_t status_hi; + rt_uint32_t reserved_lo; + rt_uint32_t reserved_hi; +}); + +struct dw_axi_dma_hcfg +{ + rt_uint32_t nr_channels; + rt_uint32_t nr_masters; + rt_uint32_t m_data_width; + rt_uint32_t block_size[DMAC_MAX_CHANNELS]; + rt_uint32_t priority[DMAC_MAX_CHANNELS]; + rt_uint32_t axi_rw_burst_len[DMAC_MAX_CHANNELS]; + rt_bool_t reg_map_8_channels; + rt_bool_t restrict_axi_burst_len; + rt_bool_t use_cfg2; +}; + +struct axi_dma_chan; + +struct axi_dma_chip +{ + struct rt_dma_controller parent; + struct dw_axi_dma_hcfg hdata; + + struct rt_clk *core_clk; + struct rt_clk *cfgr_clk; + + void *regs; + int irq; + + struct axi_dma_chan *chans; +}; + +struct axi_dma_chan +{ + struct rt_dma_chan parent; + + struct axi_dma_chip *chip; + void *chan_regs; + rt_uint8_t id; + rt_uint8_t hw_handshake; + rt_bool_t enabled; + rt_bool_t cyclic; + + enum rt_dma_transfer_direction direction; + rt_size_t transfer_size; + rt_size_t period_len; + rt_uint32_t cyclic_pos; + + struct axi_dma_lli *lli; + void *lli_raw; + rt_ubase_t lli_dma; + rt_ubase_t lli_bus; + rt_uint32_t nr_llis; + rt_size_t lli_bytes; +}; + +#define raw_to_axi_dma_chip(raw) rt_container_of(raw, struct axi_dma_chip, parent) +#define raw_to_axi_dma_chan(raw) rt_container_of(raw, struct axi_dma_chan, parent) + +rt_inline void axi_dma_writel(struct axi_dma_chip *chip, rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32(chip->regs + reg) = val; +} + +rt_inline rt_uint32_t axi_dma_readl(struct axi_dma_chip *chip, rt_uint32_t reg) +{ + return HWREG32(chip->regs + reg); +} + +rt_inline void axi_chan_writel(struct axi_dma_chan *chan, rt_uint32_t reg, rt_uint32_t val) +{ + HWREG32(chan->chan_regs + reg) = val; +} + +rt_inline rt_uint32_t axi_chan_readl(struct axi_dma_chan *chan, rt_uint32_t reg) +{ + return HWREG32(chan->chan_regs + reg); +} + +rt_inline void axi_chan_writeq(struct axi_dma_chan *chan, rt_uint32_t reg, rt_uint64_t val) +{ + axi_chan_writel(chan, reg, rt_lower_32_bits(val)); + axi_chan_writel(chan, reg + 4, rt_upper_32_bits(val)); +} + +rt_inline void axi_dma_disable(struct axi_dma_chip *chip) +{ + rt_uint32_t val = axi_dma_readl(chip, DMAC_CFG); + + val &= ~DMAC_EN_MASK; + axi_dma_writel(chip, DMAC_CFG, val); +} + +rt_inline void axi_dma_enable(struct axi_dma_chip *chip) +{ + rt_uint32_t val = axi_dma_readl(chip, DMAC_CFG); + + val |= DMAC_EN_MASK; + axi_dma_writel(chip, DMAC_CFG, val); +} + +rt_inline void axi_dma_irq_disable(struct axi_dma_chip *chip) +{ + rt_uint32_t val = axi_dma_readl(chip, DMAC_CFG); + + val &= ~INT_EN_MASK; + axi_dma_writel(chip, DMAC_CFG, val); +} + +rt_inline void axi_dma_irq_enable(struct axi_dma_chip *chip) +{ + rt_uint32_t val = axi_dma_readl(chip, DMAC_CFG); + + val |= INT_EN_MASK; + axi_dma_writel(chip, DMAC_CFG, val); +} + +rt_inline void axi_chan_irq_disable(struct axi_dma_chan *chan) +{ + axi_chan_writel(chan, CH_INTSTATUS_ENA, DWAXIDMAC_IRQ_NONE); +} + +rt_inline void axi_chan_irq_set(struct axi_dma_chan *chan, rt_uint32_t irq_mask) +{ + axi_chan_writel(chan, CH_INTSTATUS_ENA, irq_mask); +} + +rt_inline void axi_chan_irq_sig_set(struct axi_dma_chan *chan, rt_uint32_t irq_mask) +{ + axi_chan_writel(chan, CH_INTSIGNAL_ENA, irq_mask); +} + +rt_inline void axi_chan_irq_clear(struct axi_dma_chan *chan, rt_uint32_t irq_mask) +{ + axi_chan_writel(chan, CH_INTCLEAR, irq_mask); +} + +rt_inline rt_uint32_t axi_chan_irq_read(struct axi_dma_chan *chan) +{ + return axi_chan_readl(chan, CH_INTSTATUS); +} + +rt_inline void axi_chan_disable(struct axi_dma_chan *chan) +{ + rt_uint32_t val = axi_dma_readl(chan->chip, DMAC_CHEN); + + val &= ~(RT_BIT(chan->id) << DMAC_CHAN_EN_SHIFT); + if (chan->chip->hdata.reg_map_8_channels) + { + val |= RT_BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + } + else + { + val |= RT_BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT; + } + axi_dma_writel(chan->chip, DMAC_CHEN, val); +} + +rt_inline void axi_chan_enable(struct axi_dma_chan *chan) +{ + rt_uint32_t val = axi_dma_readl(chan->chip, DMAC_CHEN); + + if (chan->chip->hdata.reg_map_8_channels) + { + val |= RT_BIT(chan->id) << DMAC_CHAN_EN_SHIFT | + RT_BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + } + else + { + val |= RT_BIT(chan->id) << DMAC_CHAN_EN_SHIFT | + RT_BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT; + } + axi_dma_writel(chan->chip, DMAC_CHEN, val); +} + +rt_inline rt_bool_t axi_chan_is_hw_enable(struct axi_dma_chan *chan) +{ + rt_uint32_t val = axi_dma_readl(chan->chip, DMAC_CHEN); + + return !!(val & (RT_BIT(chan->id) << DMAC_CHAN_EN_SHIFT)); +} + +static rt_uint32_t axi_dma_encode_msize(rt_uint32_t max_burst) +{ + if (max_burst <= 1) + { + return DWAXIDMAC_BURST_TRANS_LEN_1; + } + if (max_burst > 1024) + { + return 10; + } + + return __rt_fls(max_burst) - 2; +} + +static rt_uint32_t axi_chan_get_xfer_width(struct axi_dma_chan *chan, + rt_ubase_t src, rt_ubase_t dst, rt_size_t len) +{ + rt_uint32_t max_width = chan->chip->hdata.m_data_width; + + return __rt_ffs(src | dst | len | RT_BIT(max_width)) - 1; +} + +static void axi_dma_hw_init(struct axi_dma_chip *chip) +{ + rt_uint32_t retries = 1000; + + axi_dma_writel(chip, DMAC_RESET, 1); + while (axi_dma_readl(chip, DMAC_RESET)) + { + if (!--retries) + { + LOG_E("DMAC reset timeout"); + return; + } + rt_hw_cpu_relax(); + } + + for (rt_uint32_t i = 0; i < chip->hdata.nr_channels; ++i) + { + axi_chan_irq_disable(&chip->chans[i]); + axi_chan_disable(&chip->chans[i]); + } + + /* DMAC reset clears the global DMA and interrupt enable bits. */ + axi_dma_enable(chip); + axi_dma_irq_enable(chip); +} + +static rt_err_t axi_dma_resume(struct axi_dma_chip *chip) +{ + rt_err_t err; + + if ((err = rt_clk_prepare_enable(chip->cfgr_clk))) + { + return err; + } + + if ((err = rt_clk_prepare_enable(chip->core_clk))) + { + rt_clk_disable_unprepare(chip->cfgr_clk); + return err; + } + + axi_dma_enable(chip); + axi_dma_irq_enable(chip); + + return RT_EOK; +} + +static void axi_dma_suspend(struct axi_dma_chip *chip) +{ + axi_dma_irq_disable(chip); + axi_dma_disable(chip); + rt_clk_disable_unprepare(chip->core_clk); + rt_clk_disable_unprepare(chip->cfgr_clk); +} + +static void axi_dma_free_llis(struct axi_dma_chan *chan) +{ + struct rt_device *dev = chan->chip->parent.dev; + + if (chan->lli_raw) + { + rt_dma_free_coherent(dev, chan->lli_bytes, chan->lli_raw, chan->lli_bus); + chan->lli_raw = RT_NULL; + chan->lli = RT_NULL; + chan->lli_dma = 0; + chan->lli_bus = 0; + chan->nr_llis = 0; + chan->lli_bytes = 0; + } +} + +static struct axi_dma_lli *axi_dma_alloc_llis(struct axi_dma_chan *chan, rt_uint32_t count) +{ + struct rt_device *dev = chan->chip->parent.dev; + rt_size_t size = RT_ALIGN(count * sizeof(struct axi_dma_lli), LLI_ALIGN); + rt_ubase_t dma; + void *cpu; + rt_ubase_t aligned_dma; + struct axi_dma_lli *lli; + + axi_dma_free_llis(chan); + + cpu = rt_dma_alloc_coherent(dev, size + LLI_ALIGN, &dma); + if (!cpu) + { + return RT_NULL; + } + + aligned_dma = RT_ALIGN(dma, LLI_ALIGN); + lli = (struct axi_dma_lli *)((rt_uint8_t *)cpu + (aligned_dma - dma)); + + chan->lli_raw = cpu; + chan->lli = lli; + chan->lli_bus = dma; + chan->lli_dma = aligned_dma; + chan->nr_llis = count; + chan->lli_bytes = size + LLI_ALIGN; + + rt_memset(lli, 0, count * sizeof(*lli)); + + return lli; +} + +static void axi_chan_config_write(struct axi_dma_chan *chan, rt_uint8_t tt_fc, + rt_uint8_t src_per, rt_uint8_t dst_per) +{ + rt_uint32_t cfg_lo, cfg_hi; + struct dw_axi_dma_hcfg *hdata = &chan->chip->hdata; + + cfg_lo = (DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_DST_MULTBLK_TYPE_POS | + DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_SRC_MULTBLK_TYPE_POS); + + if (hdata->reg_map_8_channels && !hdata->use_cfg2) + { + cfg_hi = tt_fc << CH_CFG_H_TT_FC_POS | + DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS | + DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS | + src_per << CH_CFG_H_SRC_PER_POS | + dst_per << CH_CFG_H_DST_PER_POS | + hdata->priority[chan->id] << CH_CFG_H_PRIORITY_POS; + } + else + { + cfg_lo |= src_per << CH_CFG2_L_SRC_PER_POS | + dst_per << CH_CFG2_L_DST_PER_POS; + cfg_hi = tt_fc << CH_CFG2_H_TT_FC_POS | + DWAXIDMAC_HS_SEL_HW << CH_CFG2_H_HS_SEL_SRC_POS | + DWAXIDMAC_HS_SEL_HW << CH_CFG2_H_HS_SEL_DST_POS | + hdata->priority[chan->id] << CH_CFG2_H_PRIORITY_POS; + } + + axi_chan_writel(chan, CH_CFG_L, cfg_lo); + axi_chan_writel(chan, CH_CFG_H, cfg_hi); +} + +static void axi_dma_fill_lli_ctl(struct axi_dma_chan *chan, struct axi_dma_lli *lli, + rt_uint32_t ctl_lo, rt_uint32_t block_ts, rt_bool_t last) +{ + rt_uint32_t ctl_hi = CH_CTL_H_LLI_VALID; + + if (chan->chip->hdata.restrict_axi_burst_len) + { + rt_uint32_t burst_len = chan->chip->hdata.axi_rw_burst_len[chan->id]; + + ctl_hi |= CH_CTL_H_ARLEN_EN | CH_CTL_H_AWLEN_EN | + burst_len << CH_CTL_H_ARLEN_POS | + burst_len << CH_CTL_H_AWLEN_POS; + } + + if (last) + { + ctl_hi |= CH_CTL_H_LLI_LAST; + } + + lli->block_ts_lo = rt_cpu_to_le32(block_ts - 1); + lli->ctl_lo = rt_cpu_to_le32(ctl_lo); + lli->ctl_hi = rt_cpu_to_le32(ctl_hi); +} + +static rt_uint32_t axi_dma_calc_memcpy_llis(struct axi_dma_chan *chan, + rt_ubase_t src, rt_ubase_t dst, rt_size_t len) +{ + rt_size_t max_block_ts = chan->chip->hdata.block_size[chan->id]; + rt_uint32_t nr_llis = 0; + rt_size_t remain = len; + + while (remain) + { + rt_uint32_t width = axi_chan_get_xfer_width(chan, src, dst, remain); + rt_size_t xfer_len = remain; + rt_uint32_t block_ts = xfer_len >> width; + + if (block_ts > max_block_ts) + { + block_ts = max_block_ts; + xfer_len = max_block_ts << width; + } + + nr_llis++; + if (nr_llis > DMAC_MAX_LLIS) + { + return 0; + } + + src += xfer_len; + dst += xfer_len; + remain -= xfer_len; + } + + return nr_llis; +} + +static rt_err_t axi_dma_build_memcpy_llis(struct axi_dma_chan *chan, + rt_ubase_t src, rt_ubase_t dst, rt_size_t len) +{ + rt_size_t max_block_ts = chan->chip->hdata.block_size[chan->id]; + rt_uint32_t nr_llis; + rt_size_t remain = len; + struct axi_dma_lli *lli; + + nr_llis = axi_dma_calc_memcpy_llis(chan, src, dst, len); + if (!nr_llis) + { + return -RT_EINVAL; + } + + lli = axi_dma_alloc_llis(chan, nr_llis); + if (!lli) + { + return -RT_ENOMEM; + } + + remain = len; + for (rt_uint32_t i = 0; i < nr_llis; ++i) + { + rt_uint32_t width = axi_chan_get_xfer_width(chan, src, dst, remain); + rt_size_t xfer_len = remain; + rt_uint32_t block_ts = xfer_len >> width; + + if (block_ts > max_block_ts) + { + block_ts = max_block_ts; + xfer_len = max_block_ts << width; + } + + lli[i].sar = rt_cpu_to_le64(src); + lli[i].dar = rt_cpu_to_le64(dst); + + axi_dma_fill_lli_ctl(chan, &lli[i], + (DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | + DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS | + width << CH_CTL_L_DST_WIDTH_POS | + width << CH_CTL_L_SRC_WIDTH_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS), + block_ts, i == nr_llis - 1); + + if (i < nr_llis - 1) + { + rt_ubase_t next = chan->lli_dma + (i + 1) * sizeof(struct axi_dma_lli); + + lli[i].llp = rt_cpu_to_le64(next); + } + + src += xfer_len; + dst += xfer_len; + remain -= xfer_len; + } + + chan->direction = RT_DMA_MEM_TO_MEM; + chan->transfer_size = len; + chan->cyclic = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t axi_dma_build_slave_llis(struct axi_dma_chan *chan, + rt_ubase_t mem_addr, rt_size_t len, enum rt_dma_transfer_direction dir, + rt_bool_t cyclic, rt_size_t period_len) +{ + rt_uint32_t data_width = RT_BIT(chan->chip->hdata.m_data_width); + rt_uint32_t mem_width, reg_width, block_ts; + rt_size_t axi_block_ts = chan->chip->hdata.block_size[chan->id]; + rt_uint32_t ctl_lo; + rt_ubase_t dev_addr; + struct axi_dma_lli *lli; + + if (dir == RT_DMA_MEM_TO_DEV) + { + reg_width = __rt_ffs(chan->parent.conf.dst_addr_width) - 1; + mem_width = __rt_ffs(data_width | mem_addr | len) - 1; + dev_addr = chan->parent.conf.dst_addr; + ctl_lo = reg_width << CH_CTL_L_DST_WIDTH_POS | + mem_width << CH_CTL_L_SRC_WIDTH_POS | + axi_dma_encode_msize(chan->parent.conf.dst_maxburst) << CH_CTL_L_DST_MSIZE_POS | + axi_dma_encode_msize(16) << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> mem_width; + } + else if (dir == RT_DMA_DEV_TO_MEM) + { + reg_width = __rt_ffs(chan->parent.conf.src_addr_width) - 1; + mem_width = __rt_ffs(data_width | mem_addr | len) - 1; + if (chan->parent.conf.dst_addr_width && + chan->parent.conf.dst_addr_width < (1U << mem_width)) + { + mem_width = __rt_ffs(chan->parent.conf.dst_addr_width) - 1; + } + dev_addr = chan->parent.conf.src_addr; + ctl_lo = reg_width << CH_CTL_L_SRC_WIDTH_POS | + mem_width << CH_CTL_L_DST_WIDTH_POS | + axi_dma_encode_msize(16) << CH_CTL_L_DST_MSIZE_POS | + axi_dma_encode_msize(chan->parent.conf.src_maxburst) << CH_CTL_L_SRC_MSIZE_POS | + DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS | + DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS; + block_ts = len >> reg_width; + } + else + { + return -RT_EINVAL; + } + + if (len % (1U << reg_width)) + { + return -RT_EINVAL; + } + + if (block_ts > axi_block_ts) + { + return -RT_EINVAL; + } + + lli = axi_dma_alloc_llis(chan, 1); + if (!lli) + { + return -RT_ENOMEM; + } + + if (dir == RT_DMA_MEM_TO_DEV) + { + lli->sar = rt_cpu_to_le64(mem_addr); + lli->dar = rt_cpu_to_le64(dev_addr); + } + else + { + lli->sar = rt_cpu_to_le64(dev_addr); + lli->dar = rt_cpu_to_le64(mem_addr); + } + + axi_dma_fill_lli_ctl(chan, lli, ctl_lo, block_ts, RT_TRUE); + + if (cyclic) + { + lli->llp = rt_cpu_to_le64(chan->lli_dma); + } + + chan->direction = dir; + chan->transfer_size = len; + chan->period_len = period_len; + chan->cyclic = cyclic; + chan->cyclic_pos = 0; + + return RT_EOK; +} + +static rt_err_t axi_dma_chan_start_locked(struct axi_dma_chan *chan) +{ + rt_uint8_t tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC; + rt_uint8_t src_per = 0, dst_per = 0; + rt_uint32_t irq_mask; + + if (axi_chan_is_hw_enable(chan)) + { + return -RT_EBUSY; + } + + switch (chan->direction) + { + case RT_DMA_MEM_TO_DEV: + tt_fc = DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC; + dst_per = chan->hw_handshake; + break; + case RT_DMA_DEV_TO_MEM: + tt_fc = DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC; + src_per = chan->hw_handshake; + break; + default: + break; + } + + axi_chan_config_write(chan, tt_fc, src_per, dst_per); + axi_chan_writeq(chan, CH_LLP, chan->lli_dma); + + irq_mask = DWAXIDMAC_IRQ_DMA_TRF | DWAXIDMAC_IRQ_ALL_ERR; + axi_chan_irq_sig_set(chan, irq_mask); + axi_chan_irq_set(chan, irq_mask | RT_BIT(29)); + + axi_chan_enable(chan); + + return RT_EOK; +} + +static struct rt_dma_chan *axi_dma_request_chan(struct rt_dma_controller *ctrl, + struct rt_device *slave, void *fw_data) +{ + struct axi_dma_chip *chip = raw_to_axi_dma_chip(ctrl); + struct rt_ofw_cell_args *args = fw_data; + struct axi_dma_chan *chan = RT_NULL; + + for (rt_uint32_t i = 0; i < chip->hdata.nr_channels; ++i) + { + if (!chip->chans[i].enabled) + { + chan = &chip->chans[i]; + break; + } + } + + if (!chan) + { + return rt_err_ptr(-RT_EBUSY); + } + + chan->hw_handshake = args ? (rt_uint8_t)args->args[0] : 0; + chan->enabled = RT_TRUE; + chan->parent.slave = slave; + chan->cyclic = RT_FALSE; + chan->cyclic_pos = 0; + + return &chan->parent; +} + +static rt_err_t axi_dma_stop(struct rt_dma_chan *chan) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + rt_uint32_t timeout = 1000; + rt_uint32_t active = RT_BIT(axi_chan->id) << DMAC_CHAN_EN_SHIFT; + + axi_chan_disable(axi_chan); + + while ((axi_dma_readl(axi_chan->chip, DMAC_CHEN) & active) && --timeout) + { + rt_hw_cpu_relax(); + } + + axi_chan_irq_clear(axi_chan, DWAXIDMAC_IRQ_ALL); + axi_chan->cyclic = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t axi_dma_release_chan(struct rt_dma_chan *chan) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + + axi_dma_stop(chan); + axi_dma_free_llis(axi_chan); + axi_chan->enabled = RT_FALSE; + + return RT_EOK; +} + +static rt_err_t axi_dma_start(struct rt_dma_chan *chan) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + + if (!axi_chan->lli) + { + return -RT_EINVAL; + } + + return axi_dma_chan_start_locked(axi_chan); +} + +static rt_err_t axi_dma_config(struct rt_dma_chan *chan, struct rt_dma_slave_config *conf) +{ + rt_memcpy(&chan->conf, conf, sizeof(*conf)); + + return RT_EOK; +} + +static rt_err_t axi_dma_prep_memcpy(struct rt_dma_chan *chan, + rt_ubase_t dma_addr_src, rt_ubase_t dma_addr_dst, rt_size_t len) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + + return axi_dma_build_memcpy_llis(axi_chan, dma_addr_src, dma_addr_dst, len); +} + +static rt_err_t axi_dma_prep_cyclic(struct rt_dma_chan *chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, rt_size_t period_len, + enum rt_dma_transfer_direction dir) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + + if (!period_len || buf_len % period_len) + { + return -RT_EINVAL; + } + + return axi_dma_build_slave_llis(axi_chan, dma_buf_addr, period_len, dir, RT_TRUE, period_len); +} + +static rt_err_t axi_dma_prep_single(struct rt_dma_chan *chan, + rt_ubase_t dma_buf_addr, rt_size_t buf_len, + enum rt_dma_transfer_direction dir) +{ + struct axi_dma_chan *axi_chan = raw_to_axi_dma_chan(chan); + + return axi_dma_build_slave_llis(axi_chan, dma_buf_addr, buf_len, dir, RT_FALSE, 0); +} + +static const struct rt_dma_controller_ops axi_dma_ops = { + .request_chan = axi_dma_request_chan, + .release_chan = axi_dma_release_chan, + .start = axi_dma_start, + .stop = axi_dma_stop, + .config = axi_dma_config, + .prep_memcpy = axi_dma_prep_memcpy, + .prep_cyclic = axi_dma_prep_cyclic, + .prep_single = axi_dma_prep_single, +}; + +static void axi_dma_handle_complete(struct axi_dma_chan *chan) +{ + if (chan->cyclic) + { + chan->cyclic_pos += chan->period_len; + if (chan->cyclic_pos >= chan->transfer_size) + { + chan->cyclic_pos = 0; + } + + axi_chan_irq_clear(chan, DWAXIDMAC_IRQ_DMA_TRF); + if (chan->lli) + { + chan->lli->ctl_hi = rt_cpu_to_le32(rt_le32_to_cpu(chan->lli->ctl_hi) | CH_CTL_H_LLI_VALID); + } + axi_chan_enable(chan); + rt_dma_chan_done(&chan->parent, chan->period_len); + } + else + { + axi_chan_disable(chan); + rt_dma_chan_done(&chan->parent, chan->transfer_size); + } +} + +static void axi_dma_isr(int irq, void *param) +{ + struct axi_dma_chip *chip = param; + rt_uint32_t status; + + axi_dma_irq_disable(chip); + + for (rt_uint32_t i = 0; i < chip->hdata.nr_channels; ++i) + { + struct axi_dma_chan *chan = &chip->chans[i]; + + if (!chan->enabled) + { + continue; + } + + status = axi_chan_irq_read(chan); + if (!status) + { + continue; + } + + axi_chan_irq_clear(chan, status); + + if (status & DWAXIDMAC_IRQ_ALL_ERR) + { + LOG_E("chan%u error irq 0x%08x", chan->id, status); + axi_dma_stop(&chan->parent); + rt_dma_chan_done(&chan->parent, 0); + } + else if (status & DWAXIDMAC_IRQ_DMA_TRF) + { + axi_dma_handle_complete(chan); + } + } + + axi_dma_irq_enable(chip); +} + +static rt_err_t axi_dma_parse_props(struct rt_device *dev, struct dw_axi_dma_hcfg *hdata) +{ + int count; + rt_uint32_t tmp, carr[DMAC_MAX_CHANNELS]; + rt_err_t err; + + if ((err = rt_dm_dev_prop_read_u32(dev, "dma-channels", &tmp))) + { + return err; + } + if (!tmp || tmp > DMAC_MAX_CHANNELS) + { + return -RT_EINVAL; + } + + hdata->nr_channels = tmp; + if (tmp <= DMA_REG_MAP_CH_REF) + { + hdata->reg_map_8_channels = RT_TRUE; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "snps,dma-masters", &tmp))) + { + return err; + } + if (!tmp || tmp > DMAC_MAX_MASTERS) + { + return -RT_EINVAL; + } + hdata->nr_masters = tmp; + + if (rt_dm_dev_prop_read_u32(dev, "snps,dma-targets", &tmp) == RT_EOK && tmp > 16) + { + hdata->use_cfg2 = RT_TRUE; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "snps,data-width", &tmp))) + { + return err; + } + if (tmp > DWAXIDMAC_TRANS_WIDTH_MAX) + { + return -RT_EINVAL; + } + hdata->m_data_width = tmp; + + if (rt_dm_dev_prop_read_u32_array_index(dev, "snps,block-size", 0, + hdata->nr_channels, carr) != hdata->nr_channels) + { + return -RT_EINVAL; + } + for (tmp = 0; tmp < hdata->nr_channels; ++tmp) + { + if (!carr[tmp] || carr[tmp] > DMAC_MAX_BLK_SIZE) + { + return -RT_EINVAL; + } + hdata->block_size[tmp] = carr[tmp]; + } + + if (rt_dm_dev_prop_read_u32_array_index(dev, "snps,priority", 0, + hdata->nr_channels, carr) != hdata->nr_channels) + { + return -RT_EINVAL; + } + for (tmp = 0; tmp < hdata->nr_channels; ++tmp) + { + if (carr[tmp] >= hdata->nr_channels) + { + return -RT_EINVAL; + } + hdata->priority[tmp] = carr[tmp]; + } + + count = rt_dm_dev_prop_count_of_u32(dev, "snps,axi-max-burst-len"); + if (count > 0 && count <= hdata->nr_channels && + rt_dm_dev_prop_read_u32_array_index(dev, "snps,axi-max-burst-len", 0, + count, carr) == count) + { + hdata->restrict_axi_burst_len = RT_TRUE; + for (tmp = 0; tmp < hdata->nr_channels; ++tmp) + { + rt_uint32_t burst_len = carr[rt_min(tmp, (rt_uint32_t)count - 1)]; + + if (burst_len < DWAXIDMAC_ARWLEN_MIN + 1 || + burst_len > DWAXIDMAC_ARWLEN_MAX + 1) + { + return -RT_EINVAL; + } + hdata->axi_rw_burst_len[tmp] = burst_len; + } + } + + return RT_EOK; +} + +static rt_err_t axi_dma_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_bool_t resumed = RT_FALSE; + struct rt_device *dev = &pdev->parent; + struct axi_dma_chip *chip = rt_calloc(1, sizeof(*chip)); + + if (!chip) + { + return -RT_ENOMEM; + } + + chip->regs = rt_dm_dev_iomap(dev, 0); + if (!chip->regs) + { + err = -RT_EIO; + goto _fail; + } + + chip->irq = rt_dm_dev_get_irq(dev, 0); + if (chip->irq < 0) + { + err = chip->irq; + goto _fail; + } + + chip->core_clk = rt_clk_get_by_name(dev, "core-clk"); + if (rt_is_err(chip->core_clk)) + { + err = rt_ptr_err(chip->core_clk); + goto _fail; + } + + chip->cfgr_clk = rt_clk_get_by_name(dev, "cfgr-clk"); + if (rt_is_err(chip->cfgr_clk)) + { + err = rt_ptr_err(chip->cfgr_clk); + goto _fail; + } + + if ((err = axi_dma_parse_props(dev, &chip->hdata))) + { + goto _fail; + } + + chip->chans = rt_calloc(chip->hdata.nr_channels, sizeof(chip->chans[0])); + if (!chip->chans) + { + err = -RT_ENOMEM; + goto _fail; + } + + for (rt_uint32_t i = 0; i < chip->hdata.nr_channels; ++i) + { + struct axi_dma_chan *chan = &chip->chans[i]; + + chan->chip = chip; + chan->id = i; + chan->chan_regs = chip->regs + COMMON_REG_LEN + i * CHAN_REG_LEN; + } + + if ((err = axi_dma_resume(chip))) + { + goto _fail; + } + resumed = RT_TRUE; + + axi_dma_hw_init(chip); + + chip->parent.dev = dev; + chip->parent.ops = &axi_dma_ops; + rt_dma_controller_add_direction(&chip->parent, RT_DMA_MEM_TO_MEM); + rt_dma_controller_add_direction(&chip->parent, RT_DMA_MEM_TO_DEV); + rt_dma_controller_add_direction(&chip->parent, RT_DMA_DEV_TO_MEM); + rt_dma_controller_set_addr_mask(&chip->parent, RT_DMA_ADDR_MASK(64)); + + if ((err = rt_dma_controller_register(&chip->parent))) + { + goto _fail; + } + + rt_hw_interrupt_install(chip->irq, axi_dma_isr, chip, "axi-dma"); + rt_hw_interrupt_umask(chip->irq); + + dev->user_data = chip; + + LOG_I("DesignWare AXI DMA, %u channels", chip->hdata.nr_channels); + + return RT_EOK; + +_fail: + if (chip->chans) + { + rt_free(chip->chans); + } + if (resumed) + { + axi_dma_suspend(chip); + } + if (chip->regs) + { + rt_iounmap(chip->regs); + } + if (!rt_is_err_or_null(chip->core_clk)) + { + rt_clk_put(chip->core_clk); + } + if (!rt_is_err_or_null(chip->cfgr_clk)) + { + rt_clk_put(chip->cfgr_clk); + } + rt_free(chip); + + return err; +} + +static rt_err_t axi_dma_remove(struct rt_platform_device *pdev) +{ + struct axi_dma_chip *chip = pdev->parent.user_data; + + rt_hw_interrupt_mask(chip->irq); + rt_pic_detach_irq(chip->irq, chip); + + rt_dma_controller_unregister(&chip->parent); + + for (rt_uint32_t i = 0; i < chip->hdata.nr_channels; ++i) + { + axi_dma_free_llis(&chip->chans[i]); + } + + axi_dma_suspend(chip); + rt_iounmap(chip->regs); + rt_clk_put(chip->core_clk); + rt_clk_put(chip->cfgr_clk); + rt_free(chip->chans); + rt_free(chip); + + return RT_EOK; +} + +static const struct rt_ofw_node_id axi_dma_ofw_ids[] = { + { .compatible = "snps,axi-dma-1.01a" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver axi_dma_driver = { + .name = "dma-dw-axi", + .ids = axi_dma_ofw_ids, + .probe = axi_dma_probe, + .remove = axi_dma_remove, +}; + +static int axi_dma_drv_register(void) +{ + rt_platform_driver_register(&axi_dma_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(axi_dma_drv_register); diff --git a/libcpu/aarch64/common/trap.c b/libcpu/aarch64/common/trap.c index 0ac2dca8ba..fad0b120d9 100644 --- a/libcpu/aarch64/common/trap.c +++ b/libcpu/aarch64/common/trap.c @@ -172,69 +172,6 @@ void rt_hw_show_register(struct rt_hw_exp_stack *regs) #ifndef RT_USING_PIC static void _rt_hw_trap_irq(rt_interrupt_context_t irq_context) { -#ifdef SOC_BCM283x - extern rt_uint8_t core_timer_flag; - void *param; - uint32_t irq; - rt_isr_handler_t isr_func; - extern struct rt_irq_desc isr_table[]; - uint32_t value = 0; - value = IRQ_PEND_BASIC & 0x3ff; - - if(core_timer_flag != 0) - { - uint32_t cpu_id = rt_hw_cpu_id(); - uint32_t int_source = CORE_IRQSOURCE(cpu_id); - if (int_source & 0x0f) - { - if (int_source & 0x08) - { - isr_func = isr_table[IRQ_ARM_TIMER].handler; -#ifdef RT_USING_INTERRUPT_INFO - isr_table[IRQ_ARM_TIMER].counter++; -#endif - if (isr_func) - { - param = isr_table[IRQ_ARM_TIMER].param; - isr_func(IRQ_ARM_TIMER, param); - } - } - } - } - - /* local interrupt*/ - if (value) - { - if (value & (1 << 8)) - { - value = IRQ_PEND1; - irq = __rt_ffs(value) - 1; - } - else if (value & (1 << 9)) - { - value = IRQ_PEND2; - irq = __rt_ffs(value) + 31; - } - else - { - value &= 0x0f; - irq = __rt_ffs(value) + 63; - } - - /* get interrupt service routine */ - isr_func = isr_table[irq].handler; -#ifdef RT_USING_INTERRUPT_INFO - isr_table[irq].counter++; -#endif - if (isr_func) - { - /* Interrupt for myself. */ - param = isr_table[irq].param; - /* turn to interrupt service routine */ - isr_func(irq, param); - } - } -#else void *param; int ir, ir_self; rt_isr_handler_t isr_func; @@ -269,7 +206,6 @@ static void _rt_hw_trap_irq(rt_interrupt_context_t irq_context) /* end of interrupt */ rt_hw_interrupt_ack(ir); -#endif } #else static void _rt_hw_trap_irq(struct rt_interrupt_context *this_ctx)