diff --git a/bsp/hpmicro/hpm6750evk/board/eth_phy_port.c b/bsp/hpmicro/hpm6750evk/board/eth_phy_port.c index 6a096ddef572..290caa63faac 100644 --- a/bsp/hpmicro/hpm6750evk/board/eth_phy_port.c +++ b/bsp/hpmicro/hpm6750evk/board/eth_phy_port.c @@ -96,7 +96,7 @@ eth_phy_monitor_handle_t phy_monitor_handle = static struct rt_phy_ops phy_ops; -static rt_phy_status phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +static rt_phy_status phy_init(rt_phy_t *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) { return PHY_STATUS_OK; } diff --git a/bsp/hpmicro/hpm6750evkmini/board/eth_phy_port.c b/bsp/hpmicro/hpm6750evkmini/board/eth_phy_port.c index d025d1b3eb5c..95a360814228 100644 --- a/bsp/hpmicro/hpm6750evkmini/board/eth_phy_port.c +++ b/bsp/hpmicro/hpm6750evkmini/board/eth_phy_port.c @@ -96,7 +96,7 @@ eth_phy_monitor_handle_t phy_monitor_handle = static struct rt_phy_ops phy_ops; -static rt_phy_status phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +static rt_phy_status phy_init(rt_phy_t *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) { return PHY_STATUS_OK; } diff --git a/bsp/imxrt/libraries/drivers/drv_ksz8081.c b/bsp/imxrt/libraries/drivers/drv_ksz8081.c index 5ed5fa3b84be..741e9ba9b25b 100644 --- a/bsp/imxrt/libraries/drivers/drv_ksz8081.c +++ b/bsp/imxrt/libraries/drivers/drv_ksz8081.c @@ -108,7 +108,7 @@ static inline rt_bool_t write_reg(rt_mdio_t *bus, rt_uint32_t addr, rt_uint32_t return RT_TRUE; } -static rt_phy_status rt_phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +static rt_phy_status rt_phy_init(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) { rt_bool_t ret; rt_phy_status result; @@ -208,7 +208,7 @@ static rt_phy_status rt_phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t } -static rt_phy_status rt_phy_read(rt_uint32_t reg, rt_uint32_t *data) +static rt_phy_status rt_phy_read(struct rt_phy_device *phy, rt_uint32_t reg, rt_uint32_t *data) { rt_mdio_t *mdio_bus = phy_ksz8081.bus; rt_uint32_t device_id = phy_ksz8081.addr; @@ -220,7 +220,7 @@ static rt_phy_status rt_phy_read(rt_uint32_t reg, rt_uint32_t *data) return PHY_STATUS_FAIL; } -static rt_phy_status rt_phy_write(rt_uint32_t reg, rt_uint32_t data) +static rt_phy_status rt_phy_write(struct rt_phy_device *phy, rt_uint32_t reg, rt_uint32_t data) { rt_mdio_t *mdio_bus = phy_ksz8081.bus; rt_uint32_t device_id = phy_ksz8081.addr; @@ -232,7 +232,7 @@ static rt_phy_status rt_phy_write(rt_uint32_t reg, rt_uint32_t data) return PHY_STATUS_FAIL; } -static rt_phy_status rt_phy_loopback(rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable) +static rt_phy_status rt_phy_loopback(struct rt_phy_device *phy, rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable) { rt_uint32_t data = 0; rt_phy_status result; @@ -288,7 +288,7 @@ static rt_phy_status rt_phy_loopback(rt_uint32_t mode, rt_uint32_t speed, rt_boo return result; } -static rt_phy_status get_link_status(rt_bool_t *status) +static rt_phy_status get_link_status(struct rt_phy_device *phy, rt_bool_t *status) { rt_phy_status result; rt_uint32_t data; @@ -310,7 +310,7 @@ static rt_phy_status get_link_status(rt_bool_t *status) } return result; } -static rt_phy_status get_link_speed_duplex(rt_uint32_t *speed, rt_uint32_t *duplex) +static rt_phy_status get_link_speed_duplex(struct rt_phy_device *phy, rt_uint32_t *speed, rt_uint32_t *duplex) { rt_phy_status result = PHY_STATUS_OK; rt_uint32_t data, ctl_reg; diff --git a/bsp/imxrt/libraries/drivers/drv_rtl8211f.c b/bsp/imxrt/libraries/drivers/drv_rtl8211f.c index 43e50c7eb950..8a8a8fdcdfbf 100644 --- a/bsp/imxrt/libraries/drivers/drv_rtl8211f.c +++ b/bsp/imxrt/libraries/drivers/drv_rtl8211f.c @@ -185,7 +185,7 @@ static status_t PHY_RTL8211F_MMD_Write(uint8_t device, uint16_t addr, uint32_t d return result; } -static rt_phy_status rt_phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +static rt_phy_status rt_phy_init(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) { rt_bool_t ret; rt_phy_status result; @@ -309,7 +309,7 @@ static rt_phy_status rt_phy_init(void *object, rt_uint32_t phy_addr, rt_uint32_t return result; } -static rt_phy_status rt_phy_read(rt_uint32_t reg, rt_uint32_t *data) +static rt_phy_status rt_phy_read(struct rt_phy_device *phy, rt_uint32_t reg, rt_uint32_t *data) { rt_mdio_t *mdio_bus = phy_rtl8211f.bus; rt_uint32_t device_id = phy_rtl8211f.addr; @@ -321,7 +321,7 @@ static rt_phy_status rt_phy_read(rt_uint32_t reg, rt_uint32_t *data) return PHY_STATUS_FAIL; } -static rt_phy_status rt_phy_write(rt_uint32_t reg, rt_uint32_t data) +static rt_phy_status rt_phy_write(struct rt_phy_device *phy, rt_uint32_t reg, rt_uint32_t data) { rt_mdio_t *mdio_bus = phy_rtl8211f.bus; rt_uint32_t device_id = phy_rtl8211f.addr; @@ -333,7 +333,7 @@ static rt_phy_status rt_phy_write(rt_uint32_t reg, rt_uint32_t data) return PHY_STATUS_FAIL; } -static rt_phy_status rt_phy_loopback(rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable) +static rt_phy_status rt_phy_loopback(struct rt_phy_device *phy, rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable) { /* This PHY only supports local loopback. */ // rt_assert(mode == PHY_LOCAL_LOOP); @@ -371,7 +371,7 @@ static rt_phy_status rt_phy_loopback(rt_uint32_t mode, rt_uint32_t speed, rt_boo return result; } -static rt_phy_status get_link_status(rt_bool_t *status) +static rt_phy_status get_link_status(struct rt_phy_device *phy, rt_bool_t *status) { // assert(status); @@ -396,7 +396,7 @@ static rt_phy_status get_link_status(rt_bool_t *status) return result; } -static rt_phy_status get_link_speed_duplex(rt_uint32_t *speed, rt_uint32_t *duplex) +static rt_phy_status get_link_speed_duplex(struct rt_phy_device *phy, rt_uint32_t *speed, rt_uint32_t *duplex) { // assert(!((speed == NULL) && (duplex == NULL))); diff --git a/bsp/qemu-virt64-aarch64/.config b/bsp/qemu-virt64-aarch64/.config index 1c600283e27c..2c2f1cee967e 100644 --- a/bsp/qemu-virt64-aarch64/.config +++ b/bsp/qemu-virt64-aarch64/.config @@ -64,7 +64,7 @@ CONFIG_RT_USING_MESSAGEQUEUE=y # Memory Management # CONFIG_RT_PAGE_MAX_ORDER=11 -# 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=y @@ -174,6 +174,7 @@ CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 CONFIG_RT_DFS_ELM_REENTRANT=y CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 CONFIG_RT_USING_DFS_DEVFS=y +CONFIG_RT_USING_DFS_DIRECTFS=y CONFIG_RT_USING_DFS_ROMFS=y # CONFIG_RT_USING_DFS_CROMFS is not set # CONFIG_RT_USING_DFS_RAMFS is not set @@ -192,30 +193,37 @@ CONFIG_RT_LWP_SHM_MAX_NR=64 # # Device Drivers # -CONFIG_RT_USING_DEVICE_IPC=y -CONFIG_RT_UNAMED_PIPE_NUMBER=64 -CONFIG_RT_USING_SYSTEM_WORKQUEUE=y -CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 -CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 CONFIG_RT_USING_TTY=y # CONFIG_RT_TTY_DEBUG is not set -# CONFIG_RT_USING_CAN is not set # CONFIG_RT_USING_CPUTIME is not set -# CONFIG_RT_USING_I2C is not set -# CONFIG_RT_USING_PHY is not set -# CONFIG_RT_USING_ADC is not set # 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_SDIO is not set -# CONFIG_RT_USING_SPI is not set -# CONFIG_RT_USING_WDT is not set -# CONFIG_RT_USING_AUDIO is not set -# CONFIG_RT_USING_SENSOR is not set # CONFIG_RT_USING_TOUCH is not set # CONFIG_RT_USING_LCD is not set +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +CONFIG_RT_USING_DEV_BUS=y +# CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_UNAMED_PIPE_NUMBER=64 +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 +# CONFIG_RT_USING_ADC is not set +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=y +# CONFIG_RT_AUDIO_ROCKCHIP is not set +# CONFIG_RT_USING_CAN is not set +CONFIG_RT_USING_CLK=y +# CONFIG_RT_CLK_ROCKCHIP is not set +CONFIG_RT_USING_FIRMWARE=y +CONFIG_RT_FIRMWARE_PSCI=y +CONFIG_RT_FIRMWARE_QEMU_FW_CFG=y CONFIG_RT_USING_HWCRYPTO=y CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 @@ -231,16 +239,14 @@ CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 CONFIG_RT_HWCRYPTO_USING_RNG=y # CONFIG_RT_HWCRYPTO_USING_CRC is not set # CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set -# CONFIG_RT_USING_PULSE_ENCODER is not set -# CONFIG_RT_USING_INPUT_CAPTURE is not set -CONFIG_RT_USING_DEV_BUS=y -# CONFIG_RT_USING_WIFI is not set -CONFIG_RT_USING_CLK=y -CONFIG_RT_USING_FIRMWARE=y -CONFIG_RT_FIRMWARE_PSCI=y +# CONFIG_RT_HWCRYPTO_RNG_ROCKCHIP is not set +# CONFIG_RT_USING_HWSPINLOCK is not set CONFIG_RT_USING_HWTIMER=y CONFIG_RT_HWTIMER_ARM_ARCH=y -# CONFIG_RT_HWTIMER_RISCV_CLINT is not set +# CONFIG_RT_HWTIMER_BCM2835 is not set +# CONFIG_RT_HWTIMER_ROCKCHIP is not set +# CONFIG_RT_USING_I2C is not set +# CONFIG_RT_USING_MBOX is not set # CONFIG_RT_USING_MFD is not set # CONFIG_RT_USING_MTD_NAND is not set CONFIG_RT_USING_MTD_NOR=y @@ -248,48 +254,76 @@ CONFIG_RT_USING_MTD_NOR_CFI=y CONFIG_RT_USING_OFW=y # CONFIG_RT_USING_BUILTIN_FDT is not set CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 +CONFIG_RT_USING_OFW_DIRECTFS=y CONFIG_RT_USING_PCI=y CONFIG_RT_PCI_MSI=y +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set CONFIG_RT_PCI_ECAM=y +CONFIG_RT_PCI_HOST_COMMON=y +CONFIG_RT_PCI_HOST_GENERIC=y +# CONFIG_RT_PCI_DW_HOST is not set +# CONFIG_RT_USING_PHY is not set CONFIG_RT_USING_PIC=y CONFIG_MAX_HANDLERS=512 # CONFIG_RT_PIC_BCM2835_INTC is not set # CONFIG_RT_PIC_BCM2836_L1_INTC is not set CONFIG_RT_PIC_ARM_GIC=y -# CONFIG_RT_PIC_ARM_GIC_V2M is not set +CONFIG_RT_PIC_ARM_GIC_V2M=y CONFIG_RT_PIC_ARM_GIC_V3=y # CONFIG_RT_PIC_ARM_GIC_V3_ITS is not set CONFIG_RT_PIC_ARM_GIC_MAX_NR=1 -# CONFIG_RT_PIC_RISCV_INTC is not set -# CONFIG_RT_PIC_SIFIVE_PLIC is not set +CONFIG_RT_USING_PINCTRL=y +# CONFIG_RT_PINCTRL_ROCKCHIP is not set CONFIG_RT_USING_PIN=y CONFIG_RT_PIN_PL061=y +# CONFIG_RT_PIN_ROCKCHIP is not set CONFIG_RT_USING_PM=y CONFIG_PM_TICKLESS_THRESHOLD_TIME=2 # CONFIG_PM_USING_CUSTOM_CONFIG is not set # CONFIG_PM_ENABLE_DEBUG is not set # CONFIG_PM_ENABLE_SUSPEND_SLEEP_MODE is not set # CONFIG_PM_ENABLE_THRESHOLD_SLEEP_MODE is not set -# CONFIG_RT_PM_RESET_SYSCON is not set -# CONFIG_RT_PM_RESET_SYSCON_POWEROFF is not set +# CONFIG_RT_PM_BCM2835 is not set +# CONFIG_RT_PM_SYSCON_POWEROFF is not set +# CONFIG_RT_PM_SYSCON_REBOOT is not set +# CONFIG_RT_USING_PWM is not set +# CONFIG_RT_USING_REGULATOR is not set +# CONFIG_RT_USING_RESET is not set CONFIG_RT_USING_RTC=y CONFIG_RT_USING_ALARM=y # CONFIG_RT_USING_SOFT_RTC is not set -CONFIG_RT_RTC_PL031=y # CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +CONFIG_RT_RTC_PL031=y +# CONFIG_RT_RTC_RK_TIMER is not set +# CONFIG_RT_USING_SDIO is not set +# CONFIG_RT_USING_SENSOR is not set 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=256 CONFIG_RT_SERIAL_PL011=y +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_BCM2835AUX is not set +# CONFIG_RT_SERIAL_8250_DW is not set +# CONFIG_RT_SERIAL_8250_OFW is not set +CONFIG_RT_SERIAL_8250_PCI=y +CONFIG_RT_USING_SOC=y +# CONFIG_RT_SOC_ROCKCHIP is not set +# CONFIG_RT_USING_SPI is not set CONFIG_RT_USING_VIRTIO=y +CONFIG_RT_VIRTIO_TRANSPORT_MMIO=y +CONFIG_RT_VIRTIO_TRANSPORT_PCI=y CONFIG_RT_VIRTIO_NET=y CONFIG_RT_VIRTIO_BLK=y CONFIG_RT_VIRTIO_CONSOLE=y CONFIG_RT_VIRTIO_RNG=y CONFIG_RT_VIRTIO_GPU=y CONFIG_RT_VIRTIO_INPUT=y +# CONFIG_RT_USING_WDT is not set # # Using USB diff --git a/bsp/qemu-virt64-aarch64/applications/main.c b/bsp/qemu-virt64-aarch64/applications/main.c index 51c7e70cb5f0..a6ef3bc9f0ba 100644 --- a/bsp/qemu-virt64-aarch64/applications/main.c +++ b/bsp/qemu-virt64-aarch64/applications/main.c @@ -13,9 +13,17 @@ int main(int argc, char** argv) { + const char *oem; + +#ifdef RT_USING_SMART + oem = "Smart"; +#else + oem = "Thread"; +#endif + rt_ubase_t level = rt_hw_interrupt_disable(); - rt_kprintf("Hi, this is RT-Thread!!\n"); + rt_kprintf("Hi, this is RT-%s!!\n", oem); rt_hw_interrupt_enable(level); diff --git a/bsp/qemu-virt64-aarch64/applications/pin.c b/bsp/qemu-virt64-aarch64/applications/pin.c index 339ab0c4a02b..15f0b90b32db 100644 --- a/bsp/qemu-virt64-aarch64/applications/pin.c +++ b/bsp/qemu-virt64-aarch64/applications/pin.c @@ -21,8 +21,9 @@ #define LINUX_KEY_POWER 116 /* SC System Power Down */ -void linux_key_poweroff(void *args) +static void linux_key_poweroff(void *args) { + rt_kputs("\n"); LOG_I("Power off the machine by [%s]", args); rt_hw_cpu_shutdown(); @@ -39,9 +40,9 @@ static int pin_init() rt_ofw_foreach_child_node(gpio_keys_np, key) { - struct rt_ofw_cell_args args; + rt_base_t pin = rt_ofw_get_named_pin(key, "gpios", 0, RT_NULL, RT_NULL); - if (!rt_ofw_parse_phandle_cells(key, "gpios", "#gpio-cells", 0, &args)) + if (pin >= 0) { rt_uint32_t linux_code; void *key_args = RT_NULL; @@ -61,11 +62,9 @@ static int pin_init() if (fn_ptr) { - rt_pin_attach_irq(args.args[0], args.args[1], fn_ptr, key_args); - rt_pin_irq_enable(args.args[0], RT_TRUE); + rt_pin_attach_irq(pin, PIN_IRQ_PIN_NONE, fn_ptr, key_args); + rt_pin_irq_enable(pin, RT_TRUE); } - - rt_ofw_node_put(args.data); } } diff --git a/bsp/qemu-virt64-aarch64/qemu.py b/bsp/qemu-virt64-aarch64/qemu.py index dbe766820936..e172b2b71135 100755 --- a/bsp/qemu-virt64-aarch64/qemu.py +++ b/bsp/qemu-virt64-aarch64/qemu.py @@ -5,7 +5,7 @@ opt=sys.argv graphic_cfg=""" \ - -serial stdio \ + -serial stdio -device ramfb \ -device virtio-gpu-device,xres=800,yres=600 \ -device virtio-keyboard-device \ -device virtio-mouse-device \ @@ -14,51 +14,73 @@ q_gic=2 q_dumpdtb="" +q_el=1 q_smp=4 q_mem=128 q_graphic="-nographic" q_debug="" -q_bootargs="console=ttyAMA0 earlycon root=block0 rootfstype=elm" +q_bootargs="console=ttyAMA0 earlycon root=block0 rootfstype=elm rootwait rw" +q_initrd="" q_sd="sd.bin" +q_net="user,id=net0" q_flash="flash.bin" +q_nvme="nvme.bin" +q_emmc="emmc.bin" def is_opt(key, inkey): if str("-"+key) == inkey: return True return False -if sys.platform.startswith('win'): - if not os.path.exists(q_sd): - os.system("qemu-img create -f raw {} 64M".format(q_sd)) - if not os.path.exists(q_flash): - os.system("qemu-img create -f raw {} 64M".format(q_flash)) -else: - if not os.path.exists(q_sd): - os.system("dd if=/dev/zero of={} bs=1024 count=65536".format(q_sd)) - if not os.path.exists(q_flash): - os.system("dd if=/dev/zero of={} bs=1024 count=65536".format(q_flash)) - for i in range(len(opt)): if i == 0: continue inkey=opt[i] - if is_opt("gic", inkey): q_gic = int(opt[i+1]) - if is_opt("dumpdtb", inkey): q_dumpdtb = str(",dumpdtb=" + opt[i+1]) - if is_opt("smp", inkey): q_smp = int(opt[i+1]) - if is_opt("mem", inkey): q_mem = int(opt[i+1]) - if is_opt("debug", inkey): q_debug = "-S -s" - if is_opt("bootargs", inkey): q_debug = opt[i+1] - if is_opt("graphic", inkey): q_graphic = graphic_cfg - if is_opt("sd", inkey): q_sd = opt[i+1] - if is_opt("flash", inkey): q_flash = opt[i+1] + if is_opt("gic", inkey): q_gic=int(opt[i+1]) + if is_opt("dumpdtb", inkey): q_dumpdtb=str(",dumpdtb=" + opt[i+1]) + if is_opt("el", inkey): q_el=int(opt[i+1]) + if is_opt("smp", inkey): q_smp=int(opt[i+1]) + if is_opt("mem", inkey): q_mem=int(opt[i+1]) + if is_opt("debug", inkey): q_debug="-S -s" + if is_opt("bootargs", inkey): q_bootargs=opt[i+1] + if is_opt("initrd", inkey): q_initrd=str("-initrd " + opt[i+1]) + if is_opt("graphic", inkey): q_graphic=graphic_cfg + if is_opt("sd", inkey): q_sd=opt[i+1] + if is_opt("tap", inkey): q_net="tap,id=net0,ifname=tap0" + if is_opt("flash", inkey): q_flash=opt[i+1] + if is_opt("nvme", inkey): q_nvme=opt[i+1] + if is_opt("emmc", inkey): q_emmc=opt[i+1] if q_smp > 8: - q_gic = 3 + q_gic=3 + +if q_el == 1: + q_el="" +elif q_el == 2: + q_el=",virtualization=on" + if q_gic == 3: + q_gic="max" +elif q_el == 3: + q_el=",secure=on" +else: + print("Invalid -el {}".format(q_el)); + exit(0) + +bin_list = [q_sd, q_flash, q_nvme, q_emmc] + +if sys.platform.startswith('win'): + for bin in bin_list: + if not os.path.exists(bin): + os.system("qemu-img create -f raw {} 64M".format(bin)) +else: + for bin in bin_list: + if not os.path.exists(bin): + os.system("dd if=/dev/zero of={} bs=1024 count=65536".format(bin)) os.system(""" qemu-system-aarch64 \ - -M virt,gic-version={}{} \ + -M virt,acpi=on,iommu=smmuv3,its=on,gic-version={}{}{} \ -cpu max \ -smp {} \ -m {} \ @@ -66,19 +88,26 @@ def is_opt(key, inkey): -append "{}" \ {} \ {} \ + {} \ -drive if=none,file={},format=raw,id=blk0 \ -device virtio-blk-device,drive=blk0 \ - -netdev user,id=net0 \ + -netdev {} \ -device virtio-net-device,netdev=net0 \ -device virtio-rng-device \ -device intel-hda \ -device hda-duplex \ -drive file={},format=raw,if=pflash,index=1 \ + -drive file={},format=raw,if=none,id=nvme0 \ + -device nvme,serial=deadbeef,drive=nvme0 \ + -drive file={},format=raw,if=none,id=emmc0 \ + -device sdhci-pci -device sd-card,drive=emmc0 \ -device virtio-serial-device \ -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 \ - -device virtserialport,chardev=console0 -""".format(q_gic, q_dumpdtb, q_smp, q_mem, q_bootargs, q_graphic, q_debug, q_sd, q_flash)) + -device virtserialport,chardev=console0 \ + -device pci-serial,chardev=console1 \ + -chardev socket,host=127.0.0.1,port=4322,server=on,wait=off,telnet=on,id=console1 +""".format(q_gic, q_dumpdtb, q_el, q_smp, q_mem, q_bootargs, q_initrd, q_graphic, q_debug, q_sd, q_net, q_flash, q_nvme, q_emmc)) if len(q_dumpdtb) != 0: dtb=q_dumpdtb.split('=')[-1] - os.system("dtc -I dtb -O dts {} -o {}".format(dtb, dtb.replace(".dtb", ".dts"))) + os.system("dtc -I dtb -O dts -@ -A {} -o {}".format(dtb, dtb.replace(".dtb", ".dts"))) diff --git a/bsp/qemu-virt64-aarch64/rtconfig.h b/bsp/qemu-virt64-aarch64/rtconfig.h index 65d5b7599f59..a4a671a51823 100644 --- a/bsp/qemu-virt64-aarch64/rtconfig.h +++ b/bsp/qemu-virt64-aarch64/rtconfig.h @@ -43,6 +43,7 @@ /* Memory Management */ #define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMPOOL #define RT_USING_SLAB #define RT_USING_MEMHEAP #define RT_MEMHEAP_FAST_MODE @@ -124,6 +125,7 @@ #define RT_DFS_ELM_REENTRANT #define RT_DFS_ELM_MUTEX_TIMEOUT 3000 #define RT_USING_DFS_DEVFS +#define RT_USING_DFS_DIRECTFS #define RT_USING_DFS_ROMFS #define RT_USING_LWP #define RT_LWP_MAX_NR 30 @@ -135,38 +137,51 @@ /* Device Drivers */ +#define RT_USING_TTY +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM +#define RT_USING_DEV_BUS #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_TTY -#define RT_USING_NULL -#define RT_USING_ZERO -#define RT_USING_RANDOM +#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_INTEL_HDA +#define RT_USING_CLK +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_PSCI +#define RT_FIRMWARE_QEMU_FW_CFG #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_USING_DEV_BUS -#define RT_USING_CLK -#define RT_USING_FIRMWARE -#define RT_FIRMWARE_PSCI #define RT_USING_HWTIMER #define RT_HWTIMER_ARM_ARCH #define RT_USING_MTD_NOR #define RT_USING_MTD_NOR_CFI #define RT_USING_OFW #define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_OFW_DIRECTFS #define RT_USING_PCI #define RT_PCI_MSI +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 #define RT_PCI_ECAM +#define RT_PCI_HOST_COMMON +#define RT_PCI_HOST_GENERIC #define RT_USING_PIC #define MAX_HANDLERS 512 #define RT_PIC_ARM_GIC +#define RT_PIC_ARM_GIC_V2M #define RT_PIC_ARM_GIC_V3 #define RT_PIC_ARM_GIC_MAX_NR 1 +#define RT_USING_PINCTRL #define RT_USING_PIN #define RT_PIN_PL061 #define RT_USING_PM @@ -179,7 +194,12 @@ #define RT_SERIAL_USING_DMA #define RT_SERIAL_RB_BUFSZ 256 #define RT_SERIAL_PL011 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_PCI +#define RT_USING_SOC #define RT_USING_VIRTIO +#define RT_VIRTIO_TRANSPORT_MMIO +#define RT_VIRTIO_TRANSPORT_PCI #define RT_VIRTIO_NET #define RT_VIRTIO_BLK #define RT_VIRTIO_CONSOLE diff --git a/bsp/rockchip/rk3308/.config b/bsp/rockchip/rk3308/.config new file mode 100644 index 000000000000..deb6695510aa --- /dev/null +++ b/bsp/rockchip/rk3308/.config @@ -0,0 +1,1170 @@ +# +# Automatically generated file; DO NOT EDIT. +# RT-Thread Project Configuration +# + +# +# RT-Thread Kernel +# +CONFIG_RT_NAME_MAX=16 +# CONFIG_RT_USING_ARCH_DATA_TYPE is not set +CONFIG_RT_USING_SMART=y +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 +# CONFIG_RT_THREAD_PRIORITY_256 is not set +CONFIG_RT_THREAD_PRIORITY_MAX=32 +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_IDLE_HOOK=y +CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 +CONFIG_IDLE_THREAD_STACK_SIZE=4096 +CONFIG_SYSTEM_THREAD_STACK_SIZE=4096 +CONFIG_RT_USING_TIMER_SOFT=y +CONFIG_RT_TIMER_THREAD_PRIO=4 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=4096 + +# +# kservice optimization +# +# CONFIG_RT_KSERVICE_USING_STDLIB is not set +# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set +# CONFIG_RT_USING_TINY_FFS is not set +CONFIG_RT_KPRINTF_USING_LONGLONG=y +CONFIG_RT_DEBUG=y +CONFIG_RT_DEBUG_COLOR=y +# CONFIG_RT_DEBUG_INIT_CONFIG is not set +# CONFIG_RT_DEBUG_THREAD_CONFIG is not set +# CONFIG_RT_DEBUG_SCHEDULER_CONFIG is not set +# CONFIG_RT_DEBUG_IPC_CONFIG is not set +# CONFIG_RT_DEBUG_TIMER_CONFIG is not set +# CONFIG_RT_DEBUG_IRQ_CONFIG is not set +# CONFIG_RT_DEBUG_MEM_CONFIG is not set +# CONFIG_RT_DEBUG_SLAB_CONFIG is not set +# CONFIG_RT_DEBUG_MEMHEAP_CONFIG is not set +# CONFIG_RT_DEBUG_PAGE_LEAK is not set +# CONFIG_RT_DEBUG_MODULE_CONFIG is not set + +# +# Inter-Thread communication +# +CONFIG_RT_USING_SEMAPHORE=y +CONFIG_RT_USING_MUTEX=y +CONFIG_RT_USING_EVENT=y +CONFIG_RT_USING_MAILBOX=y +CONFIG_RT_USING_MESSAGEQUEUE=y +# CONFIG_RT_USING_SIGNALS is not set + +# +# Memory Management +# +CONFIG_RT_PAGE_MAX_ORDER=11 +CONFIG_RT_USING_MEMPOOL=y +CONFIG_RT_USING_SMALL_MEM=y +# CONFIG_RT_USING_SLAB 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=y +# CONFIG_RT_USING_MEMHEAP_AS_HEAP is not set +# CONFIG_RT_USING_SLAB_AS_HEAP is not set +# CONFIG_RT_USING_USERHEAP is not set +# CONFIG_RT_USING_NOHEAP is not set +CONFIG_RT_USING_MEMTRACE=y +# CONFIG_RT_USING_HEAP_ISR is not set +CONFIG_RT_USING_HEAP=y + +# +# Kernel Device Object +# +CONFIG_RT_USING_DEVICE=y +CONFIG_RT_USING_DEVICE_OPS=y +CONFIG_RT_USING_DM=y +CONFIG_RT_USING_DM_FDT=y +CONFIG_RT_USING_INTERRUPT_INFO=y +CONFIG_RT_USING_CONSOLE=y +CONFIG_RT_CONSOLEBUF_SIZE=256 +CONFIG_RT_CONSOLE_DEVICE_NAME="uart2" +CONFIG_RT_VER_NUM=0x50001 +# CONFIG_RT_USING_STDC_ATOMIC is not set + +# +# RT-Thread Architecture +# +CONFIG_ARCH_CPU_64BIT=y +CONFIG_RT_USING_CACHE=y +CONFIG_RT_USING_HW_ATOMIC=y +# CONFIG_ARCH_ARM_BOOTWITH_FLUSH_CACHE is not set +# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set +# CONFIG_RT_USING_CPU_FFS is not set +CONFIG_ARCH_MM_MMU=y +CONFIG_ARCH_ARM=y +CONFIG_ARCH_ARM_MMU=y +CONFIG_KERNEL_VADDR_START=0xffff000000000000 +CONFIG_ARCH_ARMV8=y +CONFIG_ARCH_ARMV8_EXTENSIONS=0 +CONFIG_ARCH_TEXT_OFFSET=0x200000 +CONFIG_ARCH_RAM_OFFSET=0x0 +CONFIG_ARCH_ASPACE_SIZE=0xffffffff +CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 +CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y + +# +# RT-Thread Components +# +CONFIG_RT_USING_COMPONENTS_INIT=y +CONFIG_RT_USING_USER_MAIN=y +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 +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=8192 +CONFIG_FINSH_USING_HISTORY=y +CONFIG_FINSH_HISTORY_LINES=5 +CONFIG_FINSH_USING_SYMTAB=y +CONFIG_FINSH_CMD_SIZE=80 +CONFIG_MSH_USING_BUILT_IN_COMMANDS=y +CONFIG_FINSH_USING_DESCRIPTION=y +# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set +# CONFIG_FINSH_USING_AUTH is not set +CONFIG_FINSH_ARG_MAX=10 + +# +# DFS: device virtual file system +# +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=4 +CONFIG_DFS_FILESYSTEM_TYPES_MAX=4 +CONFIG_RT_USING_DFS_ELMFAT=y + +# +# elm-chan's FatFs, Generic FAT Filesystem Module +# +CONFIG_RT_DFS_ELM_CODE_PAGE=437 +CONFIG_RT_DFS_ELM_WORD_ACCESS=y +# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set +CONFIG_RT_DFS_ELM_USE_LFN_3=y +CONFIG_RT_DFS_ELM_USE_LFN=3 +CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y +# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set +CONFIG_RT_DFS_ELM_LFN_UNICODE=0 +CONFIG_RT_DFS_ELM_MAX_LFN=255 +CONFIG_RT_DFS_ELM_DRIVES=2 +CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 +# CONFIG_RT_DFS_ELM_USE_ERASE is not set +CONFIG_RT_DFS_ELM_REENTRANT=y +CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 +CONFIG_RT_USING_DFS_DEVFS=y +# CONFIG_RT_USING_DFS_DIRECTFS 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_FAL is not set +CONFIG_RT_USING_LWP=y +CONFIG_RT_LWP_MAX_NR=30 +CONFIG_LWP_TASK_STACK_SIZE=16384 +CONFIG_RT_CH_MSG_MAX_NR=1024 +CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 +CONFIG_LWP_TID_MAX_NR=64 +CONFIG_RT_LWP_SHM_MAX_NR=64 +# CONFIG_LWP_UNIX98_PTY is not set + +# +# Device Drivers +# +CONFIG_RT_USING_TTY=y +# CONFIG_RT_TTY_DEBUG is not set +# CONFIG_RT_USING_CPUTIME is not set +# 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_TOUCH is not set +# CONFIG_RT_USING_LCD is not set +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +# CONFIG_RT_USING_DEV_BUS is not set +# CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_UNAMED_PIPE_NUMBER=64 +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 +CONFIG_RT_USING_ADC=y +CONFIG_RT_ADC_ROCKCHIP_SARADC=y +# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_USING_CAN is not set +CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_ROCKCHIP=y +CONFIG_RT_CLK_ROCKCHIP_RK3308=y +# CONFIG_RT_CLK_ROCKCHIP_RK3568 is not set +CONFIG_RT_USING_FIRMWARE=y +CONFIG_RT_FIRMWARE_PSCI=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set +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_ROCKCHIP=y +# CONFIG_RT_USING_HWSPINLOCK is not set +CONFIG_RT_USING_HWTIMER=y +CONFIG_RT_HWTIMER_ARM_ARCH=y +# CONFIG_RT_HWTIMER_BCM2835 is not set +CONFIG_RT_HWTIMER_ROCKCHIP=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_I2C_RK3X=y +# CONFIG_RT_USING_MBOX is not set +CONFIG_RT_USING_MFD=y +CONFIG_RT_MFD_SYSCON=y +# CONFIG_RT_MFD_RK8XX is not set +# CONFIG_RT_MFD_RK8XX_I2C is not set +# CONFIG_RT_MFD_RK8XX_SPI is not set +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_MTD_NOR 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_DIRECTFS is not set +# CONFIG_RT_USING_PCI is not set +CONFIG_RT_USING_PHY=y +# CONFIG_RT_PHY_ROCKCHIP_NANENG_COMBO is not set +# CONFIG_RT_PHY_ROCKCHIP_SNPS_PCIE3 is not set +CONFIG_RT_USING_PIC=y +CONFIG_MAX_HANDLERS=512 +# CONFIG_RT_PIC_BCM2835_INTC is not set +# CONFIG_RT_PIC_BCM2836_L1_INTC is not set +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_V3_ITS is not set +CONFIG_RT_PIC_ARM_GIC_MAX_NR=1 +CONFIG_RT_USING_PINCTRL=y +CONFIG_RT_PINCTRL_ROCKCHIP=y +CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_ROCKCHIP=y +CONFIG_RT_USING_PM=y +CONFIG_PM_TICKLESS_THRESHOLD_TIME=2 +# CONFIG_PM_USING_CUSTOM_CONFIG is not set +# CONFIG_PM_ENABLE_DEBUG is not set +# CONFIG_PM_ENABLE_SUSPEND_SLEEP_MODE is not set +# CONFIG_PM_ENABLE_THRESHOLD_SLEEP_MODE is not set +# CONFIG_RT_PM_BCM2835 is not set +# CONFIG_RT_PM_SYSCON_POWEROFF is not set +# CONFIG_RT_PM_SYSCON_REBOOT is not set +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_ROCKCHIP=y +CONFIG_RT_USING_REGULATOR=y +CONFIG_RT_REGULATOR_GPIO=y +CONFIG_RT_USING_RESET=y +CONFIG_RT_USING_RTC=y +CONFIG_RT_USING_ALARM=y +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_GOLDFISH is not set +# CONFIG_RT_RTC_HYM8563 is not set +# CONFIG_RT_RTC_PL031 is not set +CONFIG_RT_RTC_RK_TIMER=y +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_THREAD_PREORITY=22 +CONFIG_RT_MMCSD_MAX_PARTITION=16 +# CONFIG_RT_SDIO_DEBUG is not set +# CONFIG_RT_SDIO_SDHCI_DWCMSHC is not set +CONFIG_RT_SDIO_DW_MMC=y +# CONFIG_RT_SDIO_DW_MMC_PCI is not set +CONFIG_RT_SDIO_DW_MMC_ROCKCHIP=y +CONFIG_RT_USING_SENSOR=y +CONFIG_RT_USING_SENSOR_CMD=y +CONFIG_RT_ADC_ROCKCHIP_TSADC=y +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_SERIAL_PL011 is not set +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_BCM2835AUX is not set +CONFIG_RT_SERIAL_8250_DW=y +# CONFIG_RT_SERIAL_8250_OFW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +CONFIG_RT_USING_SOC=y +CONFIG_RT_SOC_ROCKCHIP=y +CONFIG_RT_SOC_ROCKCHIP_FIQ_DEBUGGER=y +CONFIG_RT_SOC_ROCKCHIP_IODOMAIN=y +CONFIG_RT_USING_SPI=y +# CONFIG_RT_USING_SPI_BITOPS 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_ENC28J60 is not set +# CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_ROCKCHIP=y +# CONFIG_RT_USING_VIRTIO is not set +CONFIG_RT_USING_WDT=y +# CONFIG_RT_WDT_BCM2835 is not set +CONFIG_RT_WDT_DW=y + +# +# Using USB +# +# CONFIG_RT_USING_USB is not set +# CONFIG_RT_USING_USB_HOST is not set +# CONFIG_RT_USING_USB_DEVICE is not set + +# +# C/C++ and POSIX layer +# +CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 + +# +# POSIX (Portable Operating System Interface) layer +# +CONFIG_RT_USING_POSIX_FS=y +CONFIG_RT_USING_POSIX_DEVIO=y +CONFIG_RT_USING_POSIX_STDIO=y +# CONFIG_RT_USING_POSIX_POLL is not set +# CONFIG_RT_USING_POSIX_SELECT 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 + +# +# Interprocess Communication (IPC) +# +# CONFIG_RT_USING_POSIX_PIPE is not set +# CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set +# CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set + +# +# Socket is in the 'Network' category +# +# CONFIG_RT_USING_CPLUSPLUS is not set + +# +# 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_AT is not set + +# +# Utilities +# +# CONFIG_RT_USING_RYM is not set +# 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_ADT=y +CONFIG_RT_USING_ADT_AVL=y +CONFIG_RT_USING_ADT_BITMAP=y +CONFIG_RT_USING_ADT_HASHMAP=y +CONFIG_RT_USING_ADT_REF=y +# CONFIG_RT_USING_RT_LINK is not set +# CONFIG_RT_USING_VBUS is not set + +# +# RT-Thread Utestcases +# +# CONFIG_RT_USING_UTESTCASES is not set + +# +# RT-Thread online packages +# + +# +# IoT - internet of things +# +# CONFIG_PKG_USING_LWIP is not set +# CONFIG_PKG_USING_LORAWAN_DRIVER is not set +# CONFIG_PKG_USING_PAHOMQTT is not set +# CONFIG_PKG_USING_UMQTT is not set +# CONFIG_PKG_USING_WEBCLIENT is not set +# CONFIG_PKG_USING_WEBNET is not set +# CONFIG_PKG_USING_MONGOOSE is not set +# CONFIG_PKG_USING_MYMQTT is not set +# CONFIG_PKG_USING_KAWAII_MQTT is not set +# CONFIG_PKG_USING_BC28_MQTT is not set +# CONFIG_PKG_USING_WEBTERMINAL is not set +# CONFIG_PKG_USING_LIBMODBUS is not set +# CONFIG_PKG_USING_FREEMODBUS is not set +# CONFIG_PKG_USING_NANOPB is not set + +# +# Wi-Fi +# + +# +# Marvell WiFi +# +# CONFIG_PKG_USING_WLANMARVELL is not set + +# +# Wiced WiFi +# +# CONFIG_PKG_USING_WLAN_WICED is not set +# CONFIG_PKG_USING_RW007 is not set +# CONFIG_PKG_USING_COAP is not set +# CONFIG_PKG_USING_NOPOLL is not set +# CONFIG_PKG_USING_NETUTILS is not set +# CONFIG_PKG_USING_CMUX is not set +# CONFIG_PKG_USING_PPP_DEVICE is not set +# CONFIG_PKG_USING_AT_DEVICE is not set +# CONFIG_PKG_USING_ATSRV_SOCKET is not set +# CONFIG_PKG_USING_WIZNET is not set +# CONFIG_PKG_USING_ZB_COORDINATOR is not set + +# +# IoT Cloud +# +# CONFIG_PKG_USING_ONENET is not set +# CONFIG_PKG_USING_GAGENT_CLOUD is not set +# CONFIG_PKG_USING_ALI_IOTKIT is not set +# CONFIG_PKG_USING_AZURE is not set +# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set +# CONFIG_PKG_USING_JIOT-C-SDK is not set +# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set +# CONFIG_PKG_USING_JOYLINK is not set +# CONFIG_PKG_USING_EZ_IOT_OS is not set +# CONFIG_PKG_USING_IOTSHARP_SDK is not set +# CONFIG_PKG_USING_NIMBLE is not set +# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set +# CONFIG_PKG_USING_OTA_DOWNLOADER is not set +# CONFIG_PKG_USING_IPMSG is not set +# CONFIG_PKG_USING_LSSDP is not set +# CONFIG_PKG_USING_AIRKISS_OPEN is not set +# CONFIG_PKG_USING_LIBRWS is not set +# CONFIG_PKG_USING_TCPSERVER is not set +# CONFIG_PKG_USING_PROTOBUF_C is not set +# CONFIG_PKG_USING_DLT645 is not set +# CONFIG_PKG_USING_QXWZ is not set +# CONFIG_PKG_USING_SMTP_CLIENT is not set +# CONFIG_PKG_USING_ABUP_FOTA is not set +# CONFIG_PKG_USING_LIBCURL2RTT is not set +# CONFIG_PKG_USING_CAPNP is not set +# CONFIG_PKG_USING_AGILE_TELNET is not set +# CONFIG_PKG_USING_NMEALIB is not set +# CONFIG_PKG_USING_PDULIB is not set +# CONFIG_PKG_USING_BTSTACK is not set +# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set +# CONFIG_PKG_USING_WAYZ_IOTKIT is not set +# CONFIG_PKG_USING_MAVLINK is not set +# CONFIG_PKG_USING_BSAL is not set +# CONFIG_PKG_USING_AGILE_MODBUS is not set +# CONFIG_PKG_USING_AGILE_FTP is not set +# CONFIG_PKG_USING_EMBEDDEDPROTO is not set +# CONFIG_PKG_USING_RT_LINK_HW is not set +# CONFIG_PKG_USING_RYANMQTT is not set +# CONFIG_PKG_USING_RYANW5500 is not set +# CONFIG_PKG_USING_LORA_PKT_FWD is not set +# CONFIG_PKG_USING_LORA_GW_DRIVER_LIB is not set +# CONFIG_PKG_USING_LORA_PKT_SNIFFER is not set +# CONFIG_PKG_USING_HM is not set +# CONFIG_PKG_USING_SMALL_MODBUS is not set +# CONFIG_PKG_USING_NET_SERVER is not set +# CONFIG_PKG_USING_ZFTP is not set +# CONFIG_PKG_USING_WOL is not set +# CONFIG_PKG_USING_ZEPHYR_POLLING is not set + +# +# security packages +# +# CONFIG_PKG_USING_MBEDTLS is not set +# CONFIG_PKG_USING_LIBSODIUM is not set +# CONFIG_PKG_USING_LIBHYDROGEN is not set +# CONFIG_PKG_USING_TINYCRYPT is not set +# CONFIG_PKG_USING_TFM is not set +# CONFIG_PKG_USING_YD_CRYPTO is not set + +# +# language packages +# + +# +# JSON: JavaScript Object Notation, a lightweight data-interchange format +# +# CONFIG_PKG_USING_CJSON is not set +# CONFIG_PKG_USING_LJSON is not set +# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set +# CONFIG_PKG_USING_RAPIDJSON is not set +# CONFIG_PKG_USING_JSMN is not set +# CONFIG_PKG_USING_AGILE_JSMN is not set +# CONFIG_PKG_USING_PARSON is not set + +# +# XML: Extensible Markup Language +# +# CONFIG_PKG_USING_SIMPLE_XML is not set +# CONFIG_PKG_USING_EZXML is not set +# CONFIG_PKG_USING_LUATOS_SOC is not set +# CONFIG_PKG_USING_LUA is not set +# CONFIG_PKG_USING_JERRYSCRIPT is not set +# CONFIG_PKG_USING_MICROPYTHON is not set +# CONFIG_PKG_USING_PIKASCRIPT is not set +# CONFIG_PKG_USING_RTT_RUST is not set + +# +# multimedia packages +# + +# +# LVGL: powerful and easy-to-use embedded GUI library +# +# CONFIG_PKG_USING_LVGL is not set +# CONFIG_PKG_USING_LITTLEVGL2RTT is not set +# CONFIG_PKG_USING_LV_MUSIC_DEMO is not set +# CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set + +# +# u8g2: a monochrome graphic library +# +# CONFIG_PKG_USING_U8G2_OFFICIAL is not set +# CONFIG_PKG_USING_U8G2 is not set +# CONFIG_PKG_USING_OPENMV is not set +# CONFIG_PKG_USING_MUPDF is not set +# CONFIG_PKG_USING_STEMWIN is not set +# CONFIG_PKG_USING_WAVPLAYER is not set +# CONFIG_PKG_USING_TJPGD is not set +# CONFIG_PKG_USING_PDFGEN is not set +# CONFIG_PKG_USING_HELIX is not set +# CONFIG_PKG_USING_AZUREGUIX is not set +# CONFIG_PKG_USING_TOUCHGFX2RTT is not set +# CONFIG_PKG_USING_NUEMWIN is not set +# CONFIG_PKG_USING_MP3PLAYER is not set +# CONFIG_PKG_USING_TINYJPEG is not set +# CONFIG_PKG_USING_UGUI is not set +# CONFIG_PKG_USING_MCURSES is not set +# CONFIG_PKG_USING_TERMBOX is not set +# CONFIG_PKG_USING_VT100 is not set +# CONFIG_PKG_USING_QRCODE is not set +# CONFIG_PKG_USING_GUIENGINE is not set +# CONFIG_PKG_USING_3GPP_AMRNB is not set + +# +# tools packages +# +# CONFIG_PKG_USING_CMBACKTRACE is not set +# CONFIG_PKG_USING_EASYFLASH is not set +# CONFIG_PKG_USING_EASYLOGGER is not set +# CONFIG_PKG_USING_SYSTEMVIEW is not set +# CONFIG_PKG_USING_SEGGER_RTT is not set +# CONFIG_PKG_USING_RTT_AUTO_EXE_CMD is not set +# CONFIG_PKG_USING_RDB is not set +# CONFIG_PKG_USING_ULOG_EASYFLASH is not set +# CONFIG_PKG_USING_LOGMGR is not set +# CONFIG_PKG_USING_ADBD is not set +# CONFIG_PKG_USING_COREMARK is not set +# CONFIG_PKG_USING_DHRYSTONE is not set +# CONFIG_PKG_USING_MEMORYPERF is not set +# CONFIG_PKG_USING_NR_MICRO_SHELL is not set +# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set +# CONFIG_PKG_USING_LUNAR_CALENDAR is not set +# CONFIG_PKG_USING_BS8116A is not set +# CONFIG_PKG_USING_GPS_RMC is not set +# CONFIG_PKG_USING_URLENCODE is not set +# CONFIG_PKG_USING_UMCN is not set +# CONFIG_PKG_USING_LWRB2RTT is not set +# CONFIG_PKG_USING_CPU_USAGE is not set +# CONFIG_PKG_USING_GBK2UTF8 is not set +# CONFIG_PKG_USING_VCONSOLE is not set +# CONFIG_PKG_USING_KDB is not set +# CONFIG_PKG_USING_WAMR is not set +# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set +# CONFIG_PKG_USING_LWLOG is not set +# CONFIG_PKG_USING_ANV_TRACE is not set +# CONFIG_PKG_USING_ANV_MEMLEAK is not set +# CONFIG_PKG_USING_ANV_TESTSUIT is not set +# CONFIG_PKG_USING_ANV_BENCH is not set +# CONFIG_PKG_USING_DEVMEM is not set +# CONFIG_PKG_USING_REGEX is not set +# CONFIG_PKG_USING_MEM_SANDBOX is not set +# CONFIG_PKG_USING_SOLAR_TERMS is not set +# CONFIG_PKG_USING_GAN_ZHI is not set +# CONFIG_PKG_USING_FDT is not set +# CONFIG_PKG_USING_CBOX is not set +# CONFIG_PKG_USING_SNOWFLAKE is not set +# CONFIG_PKG_USING_HASH_MATCH is not set +# CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set +# CONFIG_PKG_USING_VOFA_PLUS is not set + +# +# system packages +# + +# +# enhanced kernel services +# +# CONFIG_PKG_USING_RT_MEMCPY_CM is not set +# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set +CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y +CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full" +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set +CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y +CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest" + +# +# acceleration: Assembly language or algorithmic acceleration packages +# +# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set +# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set +# CONFIG_PKG_USING_QFPLIB_M3 is not set + +# +# CMSIS: ARM Cortex-M Microcontroller Software Interface Standard +# +# CONFIG_PKG_USING_CMSIS_5 is not set +# CONFIG_PKG_USING_CMSIS_RTOS1 is not set +# CONFIG_PKG_USING_CMSIS_RTOS2 is not set + +# +# Micrium: Micrium software products porting for RT-Thread +# +# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set +# CONFIG_PKG_USING_UCOSII_WRAPPER is not set +# CONFIG_PKG_USING_UC_CRC is not set +# CONFIG_PKG_USING_UC_CLK is not set +# CONFIG_PKG_USING_UC_COMMON is not set +# CONFIG_PKG_USING_UC_MODBUS is not set +# CONFIG_PKG_USING_FREERTOS_WRAPPER is not set +# CONFIG_PKG_USING_CAIRO is not set +# CONFIG_PKG_USING_PIXMAN is not set +# CONFIG_PKG_USING_PARTITION is not set +# CONFIG_PKG_USING_PERF_COUNTER is not set +# CONFIG_PKG_USING_FLASHDB is not set +# CONFIG_PKG_USING_SQLITE is not set +# CONFIG_PKG_USING_RTI is not set +# CONFIG_PKG_USING_DFS_YAFFS is not set +# CONFIG_PKG_USING_LITTLEFS is not set +# CONFIG_PKG_USING_DFS_JFFS2 is not set +# CONFIG_PKG_USING_DFS_UFFS is not set +# CONFIG_PKG_USING_LWEXT4 is not set +# CONFIG_PKG_USING_THREAD_POOL is not set +# CONFIG_PKG_USING_ROBOTS is not set +# CONFIG_PKG_USING_EV is not set +# CONFIG_PKG_USING_SYSWATCH is not set +# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set +# CONFIG_PKG_USING_PLCCORE is not set +# CONFIG_PKG_USING_RAMDISK is not set +# CONFIG_PKG_USING_MININI is not set +# CONFIG_PKG_USING_QBOOT is not set +# CONFIG_PKG_USING_PPOOL is not set +# CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_LPM is not set +# CONFIG_PKG_USING_TLSF is not set +# CONFIG_PKG_USING_EVENT_RECORDER is not set +# CONFIG_PKG_USING_ARM_2D is not set +# CONFIG_PKG_USING_MCUBOOT is not set +# CONFIG_PKG_USING_TINYUSB is not set +# CONFIG_PKG_USING_CHERRYUSB is not set +# CONFIG_PKG_USING_KMULTI_RTIMER is not set +# CONFIG_PKG_USING_TFDB is not set +# CONFIG_PKG_USING_QPC is not set +# CONFIG_PKG_USING_AGILE_UPGRADE is not set +# CONFIG_PKG_USING_FLASH_BLOB is not set +# CONFIG_PKG_USING_MLIBC is not set + +# +# peripheral libraries and drivers +# + +# +# sensors drivers +# +# CONFIG_PKG_USING_LSM6DSM is not set +# CONFIG_PKG_USING_LSM6DSL is not set +# CONFIG_PKG_USING_LPS22HB is not set +# CONFIG_PKG_USING_HTS221 is not set +# CONFIG_PKG_USING_LSM303AGR is not set +# CONFIG_PKG_USING_BME280 is not set +# CONFIG_PKG_USING_BME680 is not set +# CONFIG_PKG_USING_BMA400 is not set +# CONFIG_PKG_USING_BMI160_BMX160 is not set +# CONFIG_PKG_USING_SPL0601 is not set +# CONFIG_PKG_USING_MS5805 is not set +# CONFIG_PKG_USING_DA270 is not set +# CONFIG_PKG_USING_DF220 is not set +# CONFIG_PKG_USING_HSHCAL001 is not set +# CONFIG_PKG_USING_BH1750 is not set +# CONFIG_PKG_USING_MPU6XXX is not set +# CONFIG_PKG_USING_AHT10 is not set +# CONFIG_PKG_USING_AP3216C is not set +# CONFIG_PKG_USING_TSL4531 is not set +# CONFIG_PKG_USING_DS18B20 is not set +# CONFIG_PKG_USING_DHT11 is not set +# CONFIG_PKG_USING_DHTXX is not set +# CONFIG_PKG_USING_GY271 is not set +# CONFIG_PKG_USING_GP2Y10 is not set +# CONFIG_PKG_USING_SGP30 is not set +# CONFIG_PKG_USING_HDC1000 is not set +# CONFIG_PKG_USING_BMP180 is not set +# CONFIG_PKG_USING_BMP280 is not set +# CONFIG_PKG_USING_SHTC1 is not set +# CONFIG_PKG_USING_BMI088 is not set +# CONFIG_PKG_USING_HMC5883 is not set +# CONFIG_PKG_USING_MAX6675 is not set +# CONFIG_PKG_USING_TMP1075 is not set +# CONFIG_PKG_USING_SR04 is not set +# CONFIG_PKG_USING_CCS811 is not set +# CONFIG_PKG_USING_PMSXX is not set +# CONFIG_PKG_USING_RT3020 is not set +# CONFIG_PKG_USING_MLX90632 is not set +# CONFIG_PKG_USING_MLX90393 is not set +# CONFIG_PKG_USING_MLX90392 is not set +# CONFIG_PKG_USING_MLX90397 is not set +# CONFIG_PKG_USING_MS5611 is not set +# CONFIG_PKG_USING_MAX31865 is not set +# CONFIG_PKG_USING_VL53L0X is not set +# CONFIG_PKG_USING_INA260 is not set +# CONFIG_PKG_USING_MAX30102 is not set +# CONFIG_PKG_USING_INA226 is not set +# CONFIG_PKG_USING_LIS2DH12 is not set +# CONFIG_PKG_USING_HS300X is not set +# CONFIG_PKG_USING_ZMOD4410 is not set +# CONFIG_PKG_USING_ISL29035 is not set +# CONFIG_PKG_USING_MMC3680KJ is not set +# CONFIG_PKG_USING_QMP6989 is not set +# CONFIG_PKG_USING_BALANCE is not set +# CONFIG_PKG_USING_SHT2X is not set +# CONFIG_PKG_USING_SHT3X is not set +# CONFIG_PKG_USING_AD7746 is not set +# CONFIG_PKG_USING_ADT74XX is not set +# CONFIG_PKG_USING_MAX17048 is not set +# CONFIG_PKG_USING_AS7341 is not set +# CONFIG_PKG_USING_CW2015 is not set +# CONFIG_PKG_USING_ICM20608 is not set +# CONFIG_PKG_USING_PAJ7620 is not set +# CONFIG_PKG_USING_STHS34PF80 is not set + +# +# touch drivers +# +# CONFIG_PKG_USING_GT9147 is not set +# CONFIG_PKG_USING_GT1151 is not set +# CONFIG_PKG_USING_GT917S is not set +# CONFIG_PKG_USING_GT911 is not set +# CONFIG_PKG_USING_FT6206 is not set +# CONFIG_PKG_USING_FT5426 is not set +# CONFIG_PKG_USING_FT6236 is not set +# CONFIG_PKG_USING_XPT2046_TOUCH is not set +# CONFIG_PKG_USING_REALTEK_AMEBA is not set +# CONFIG_PKG_USING_STM32_SDIO is not set +# CONFIG_PKG_USING_ESP_IDF is not set +# CONFIG_PKG_USING_BUTTON is not set +# CONFIG_PKG_USING_PCF8574 is not set +# CONFIG_PKG_USING_SX12XX is not set +# CONFIG_PKG_USING_SIGNAL_LED is not set +# CONFIG_PKG_USING_LEDBLINK is not set +# CONFIG_PKG_USING_LITTLED is not set +# CONFIG_PKG_USING_LKDGUI is not set +# CONFIG_PKG_USING_NRF5X_SDK is not set +# CONFIG_PKG_USING_NRFX is not set + +# +# Kendryte SDK +# +# CONFIG_PKG_USING_K210_SDK is not set +# CONFIG_PKG_USING_KENDRYTE_SDK is not set +# CONFIG_PKG_USING_INFRARED is not set +# CONFIG_PKG_USING_MULTI_INFRARED is not set +# CONFIG_PKG_USING_AGILE_BUTTON is not set +# CONFIG_PKG_USING_AGILE_LED is not set +# CONFIG_PKG_USING_AT24CXX is not set +# CONFIG_PKG_USING_MOTIONDRIVER2RTT is not set +# CONFIG_PKG_USING_PCA9685 is not set +# CONFIG_PKG_USING_ILI9341 is not set +# CONFIG_PKG_USING_I2C_TOOLS is not set +# CONFIG_PKG_USING_NRF24L01 is not set +# CONFIG_PKG_USING_RPLIDAR is not set +# CONFIG_PKG_USING_AS608 is not set +# CONFIG_PKG_USING_RC522 is not set +# CONFIG_PKG_USING_WS2812B is not set +# CONFIG_PKG_USING_EMBARC_BSP is not set +# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set +# CONFIG_PKG_USING_MULTI_RTIMER is not set +# CONFIG_PKG_USING_MAX7219 is not set +# CONFIG_PKG_USING_BEEP is not set +# CONFIG_PKG_USING_EASYBLINK is not set +# CONFIG_PKG_USING_PMS_SERIES is not set +# CONFIG_PKG_USING_CAN_YMODEM is not set +# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set +# CONFIG_PKG_USING_QLED is not set +# CONFIG_PKG_USING_AGILE_CONSOLE is not set +# CONFIG_PKG_USING_LD3320 is not set +# CONFIG_PKG_USING_WK2124 is not set +# CONFIG_PKG_USING_LY68L6400 is not set +# CONFIG_PKG_USING_DM9051 is not set +# CONFIG_PKG_USING_SSD1306 is not set +# CONFIG_PKG_USING_QKEY is not set +# CONFIG_PKG_USING_RS485 is not set +# CONFIG_PKG_USING_RS232 is not set +# CONFIG_PKG_USING_NES is not set +# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set +# CONFIG_PKG_USING_VDEVICE is not set +# CONFIG_PKG_USING_SGM706 is not set +# CONFIG_PKG_USING_STM32WB55_SDK is not set +# CONFIG_PKG_USING_RDA58XX is not set +# CONFIG_PKG_USING_LIBNFC is not set +# CONFIG_PKG_USING_MFOC is not set +# CONFIG_PKG_USING_TMC51XX is not set +# CONFIG_PKG_USING_TCA9534 is not set +# CONFIG_PKG_USING_KOBUKI is not set +# CONFIG_PKG_USING_ROSSERIAL is not set +# CONFIG_PKG_USING_MICRO_ROS is not set +# CONFIG_PKG_USING_MCP23008 is not set +# CONFIG_PKG_USING_BLUETRUM_SDK is not set +# CONFIG_PKG_USING_MISAKA_AT24CXX is not set +# CONFIG_PKG_USING_MISAKA_RGB_BLING is not set +# CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set +# CONFIG_PKG_USING_SOFT_SERIAL is not set +# CONFIG_PKG_USING_MB85RS16 is not set +# CONFIG_PKG_USING_RFM300 is not set +# CONFIG_PKG_USING_IO_INPUT_FILTER is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set +# CONFIG_PKG_USING_LRF_NV7LIDAR is not set +# CONFIG_PKG_USING_AIP650 is not set +# CONFIG_PKG_USING_FINGERPRINT is not set +# CONFIG_PKG_USING_SPI_TOOLS is not set + +# +# AI packages +# +# CONFIG_PKG_USING_LIBANN is not set +# CONFIG_PKG_USING_NNOM is not set +# CONFIG_PKG_USING_ONNX_BACKEND is not set +# CONFIG_PKG_USING_ONNX_PARSER is not set +# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set +# CONFIG_PKG_USING_ELAPACK is not set +# CONFIG_PKG_USING_ULAPACK is not set +# CONFIG_PKG_USING_QUEST is not set +# CONFIG_PKG_USING_NAXOS is not set +# CONFIG_PKG_USING_NCNN is not set + +# +# Signal Processing and Control Algorithm Packages +# +# CONFIG_PKG_USING_FIRE_PID_CURVE is not set +# CONFIG_PKG_USING_UKAL is not set + +# +# miscellaneous packages +# + +# +# project laboratory +# + +# +# samples: kernel and components samples +# +# CONFIG_PKG_USING_KERNEL_SAMPLES is not set +# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set +# CONFIG_PKG_USING_NETWORK_SAMPLES is not set +# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set + +# +# entertainment: terminal games and other interesting software packages +# +# CONFIG_PKG_USING_CMATRIX is not set +# CONFIG_PKG_USING_SL is not set +# CONFIG_PKG_USING_CAL is not set +# CONFIG_PKG_USING_ACLOCK is not set +# CONFIG_PKG_USING_THREES is not set +# CONFIG_PKG_USING_2048 is not set +# CONFIG_PKG_USING_SNAKE is not set +# CONFIG_PKG_USING_TETRIS is not set +# CONFIG_PKG_USING_DONUT is not set +# CONFIG_PKG_USING_COWSAY is not set +# CONFIG_PKG_USING_MORSE is not set +# CONFIG_PKG_USING_LIBCSV is not set +# CONFIG_PKG_USING_OPTPARSE is not set +# CONFIG_PKG_USING_FASTLZ is not set +# CONFIG_PKG_USING_MINILZO is not set +# CONFIG_PKG_USING_QUICKLZ is not set +# CONFIG_PKG_USING_LZMA is not set +# CONFIG_PKG_USING_MULTIBUTTON is not set +# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set +# CONFIG_PKG_USING_CANFESTIVAL is not set +# CONFIG_PKG_USING_ZLIB is not set +# CONFIG_PKG_USING_MINIZIP is not set +# CONFIG_PKG_USING_HEATSHRINK is not set +# CONFIG_PKG_USING_DSTR is not set +# CONFIG_PKG_USING_TINYFRAME is not set +# CONFIG_PKG_USING_KENDRYTE_DEMO is not set +# CONFIG_PKG_USING_DIGITALCTRL is not set +# CONFIG_PKG_USING_UPACKER is not set +# CONFIG_PKG_USING_UPARAM is not set +# CONFIG_PKG_USING_HELLO is not set +# CONFIG_PKG_USING_VI is not set +# CONFIG_PKG_USING_KI is not set +# CONFIG_PKG_USING_ARMv7M_DWT is not set +# CONFIG_PKG_USING_CRCLIB is not set +# CONFIG_PKG_USING_LWGPS is not set +# CONFIG_PKG_USING_STATE_MACHINE is not set +# CONFIG_PKG_USING_DESIGN_PATTERN is not set +# CONFIG_PKG_USING_CONTROLLER is not set +# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set +# CONFIG_PKG_USING_MFBD is not set +# CONFIG_PKG_USING_SLCAN2RTT is not set +# CONFIG_PKG_USING_SOEM is not set +# CONFIG_PKG_USING_QPARAM is not set +# CONFIG_PKG_USING_CorevMCU_CLI is not set + +# +# Arduino libraries +# +# CONFIG_PKG_USING_RTDUINO is not set + +# +# Projects +# +# CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set +# CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set +# CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set + +# +# Sensors +# +# CONFIG_PKG_USING_ARDUINO_SENSOR_DEVICE_DRIVERS is not set +# CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL375 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L0X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L1X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSOR is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL6180X is not set +# CONFIG_PKG_USING_ADAFRUIT_MAX31855 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31865 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31856 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX6675 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90614 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS1 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AHTX0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS0 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADT7410 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME680 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9808 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4728 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA219 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR390 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DHT is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM6DS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO055 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX1704X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMC56X3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90393 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90395 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ICM20X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DPS310 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTS221 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT4X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL343 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS726X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AMG88XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2320 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2315 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR329_LTR303 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP3XX is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MS8607 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90640 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMA8451 is not set +# CONFIG_PKG_USING_ADAFRUIT_MSA301 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X_RVC is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS2MDL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303DLH_MAG is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LC709203F is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CAP1188 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CCS811 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_NAU7802 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS331 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS2X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS35HW is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303_ACCEL is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3DH is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8591 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL3115A2 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPR121 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPRLS is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPU6050 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCT2075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PM25AQI is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_EMC2101 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXAS21002C is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SCD30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXOS8700 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HMC5883_UNIFIED is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP30 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP006 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TLA202X is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCS34725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI7021 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP40 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHTC3 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU21DF is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS7341 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU31D is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSORLAB is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA260 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP007_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_L3GD20 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP117 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSC2007 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2591_LIBRARY is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VCNL4040 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6075 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML7700 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LIS3DHTR is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DHT is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL335 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_ADXL345 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BME280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP280 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_H3LIS331DL is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MMA7660 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TSL2561 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PAJ7620 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VL53L0X is not set +# CONFIG_PKG_USING_SEEED_ITG3200 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT31 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HP20X is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_DRV2605L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BBM150 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HMC5883L is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM303DLH is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_TCS3414CS is not set +# CONFIG_PKG_USING_SEEED_MP503 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_BMP085 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HIGHTEMP is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_VEML6070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SI1145 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_SHT35 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_AT42QT1070 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LSM6DS3 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HDC1000 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_HM3301 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_MCP9600 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LTC2941 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_LDC1612 is not set + +# +# Display +# +# CONFIG_PKG_USING_ARDUINO_U8G2 is not set +# CONFIG_PKG_USING_ARDUINO_U8GLIB_ARDUINO is not set +# CONFIG_PKG_USING_SEEED_TM1637 is not set + +# +# Timing +# +# CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set + +# +# Data Processing +# +# CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set +# CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set + +# +# Data Storage +# + +# +# Communication +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set + +# +# Device Control +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8574 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCA9685 is not set +# CONFIG_PKG_USING_ARDUINO_SEEED_PCF85063TP is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TPA2016 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DRV2605 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS1841 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS3502 is not set + +# +# Other +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set +# CONFIG_PKG_USING_ARDUINO_RTCLIB is not set + +# +# Signal IO +# +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BUSIO is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCA8418 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP23017 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADS1X15 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AW9523 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set +# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set + +# +# Uncategorized +# +CONFIG_SOC_RK3308=y +CONFIG_RT_USING_AMBA_BUS=y diff --git a/bsp/rockchip/rk3308/Kconfig b/bsp/rockchip/rk3308/Kconfig new file mode 100644 index 000000000000..6ffcf062dc8b --- /dev/null +++ b/bsp/rockchip/rk3308/Kconfig @@ -0,0 +1,33 @@ +mainmenu "RT-Thread Project Configuration" + +config BSP_DIR + string + option env="BSP_ROOT" + default "." + +config RTT_DIR + string + option env="RTT_ROOT" + default "../../.." + +config PKGS_DIR + string + option env="PKGS_ROOT" + default "packages" + +source "$RTT_DIR/Kconfig" +source "$PKGS_DIR/Kconfig" + +config SOC_RK3308 + bool + select ARCH_ARMV8 + select ARCH_CPU_64BIT + select ARCH_ARM_MMU + select RT_USING_CACHE + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + default y + +config RT_USING_AMBA_BUS + bool + default y diff --git a/bsp/rockchip/rk3308/SConscript b/bsp/rockchip/rk3308/SConscript new file mode 100644 index 000000000000..744d8d782140 --- /dev/null +++ b/bsp/rockchip/rk3308/SConscript @@ -0,0 +1,14 @@ +# 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')) + +Return('objs') diff --git a/bsp/rockchip/rk3308/SConstruct b/bsp/rockchip/rk3308/SConstruct new file mode 100644 index 000000000000..ec6fe0187f21 --- /dev/null +++ b/bsp/rockchip/rk3308/SConstruct @@ -0,0 +1,29 @@ +import os +import sys +import rtconfig + +from rtconfig import RTT_ROOT + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +from building import * + +TARGET = 'rtthread.' + rtconfig.TARGET_EXT + +DefaultEnvironment(tools=[]) +env = Environment(tools = ['mingw'], + 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'] + +Export('RTT_ROOT') +Export('rtconfig') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False) + +# make a building +DoBuilding(TARGET, objs) diff --git a/bsp/rockchip/rk3308/applications/SConscript b/bsp/rockchip/rk3308/applications/SConscript new file mode 100644 index 000000000000..c583d3016e0f --- /dev/null +++ b/bsp/rockchip/rk3308/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/rockchip/rk3308/applications/led.c b/bsp/rockchip/rk3308/applications/led.c new file mode 100644 index 000000000000..b83185b2d045 --- /dev/null +++ b/bsp/rockchip/rk3308/applications/led.c @@ -0,0 +1,179 @@ +/* + * 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 "app.led" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_PIN + +struct led +{ + struct rt_device parent; + + char name[RT_NAME_MAX]; + + rt_base_t pin; + + rt_uint8_t status; +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 8192 +#define THREAD_TIMESLICE 10 + rt_thread_t flow; +}; + +static rt_ssize_t led_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_uint8_t status = ((char *)buffer)[0]; + struct led *led = rt_container_of(dev, struct led, parent); + static const char * const modes[] = + { + "none", + "default-on", + "heartbeat", + }; + + if (status >= '0' && status <= '2') + { + led->status = status; + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, led, sizeof(*led)); + rt_thread_resume(led->flow); + + LOG_I("Switch %s to status = %c (%s)", led->name, status, modes[status - '0']); + } + else + { + LOG_E("Invalid status = %c, (0:%s 1:%s 2:%s)", status, + modes[0], modes[1], modes[2]); + } + + return size; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops led_ops = +{ + .write = led_write, +}; +#endif + +static void led_flow(void *param) +{ + struct led *led = param; + +_loop: + + switch (led->status) + { + case '0' ... '1': + rt_pin_mode(led->pin, PIN_MODE_OUTPUT); + rt_pin_write(led->pin, led->status - '0'); + rt_thread_suspend(led->flow); + rt_schedule(); + break; + + case '2': + rt_pin_mode(led->pin, PIN_MODE_OUTPUT); + + while (led->status == '2') + { + rt_pin_write(led->pin, PIN_HIGH); + rt_thread_mdelay(500); + + rt_pin_write(led->pin, PIN_LOW); + rt_thread_mdelay(500); + } + break; + } + + goto _loop; +} + +static rt_err_t crate_led_fops(int idx, struct rt_ofw_node *led_np, rt_base_t pin) +{ + char dev_name[RT_NAME_MAX]; + struct led *led = rt_calloc(1, sizeof(*led)); + + if (!led) + { + return -RT_ENOMEM; + } + + led->pin = pin; + + rt_strncpy(led->name, rt_ofw_node_full_name(led_np), sizeof(led->name)); + led->flow = rt_thread_create(led->name, led_flow, led, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + + if (!led->flow) + { + goto _fail; + } + + led->status = '2'; + + rt_thread_startup(led->flow); + + led->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + led->parent.ops = &led_ops; +#else + led->parent.write = led_write; +#endif + + rt_snprintf(dev_name, sizeof(dev_name), "led%d", idx); + rt_device_register(&led->parent, dev_name, RT_DEVICE_FLAG_WRONLY); + + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, led, sizeof(*led)); + + return RT_EOK; + +_fail: + return -RT_ERROR; +} + +static int led_init(void) +{ + int idx = 0; + struct rt_ofw_node *led_np, *leds_np; + + if (!rt_ofw_machine_is_compatible("radxa,rockpis")) + { + return -RT_ENOSYS; + } + + leds_np = rt_ofw_find_node_by_compatible(RT_NULL, "gpio-leds"); + + if (!leds_np) + { + return -RT_ENOSYS; + } + + rt_ofw_foreach_child_node(leds_np, led_np) + { + rt_base_t pin = rt_ofw_get_named_pin(led_np, "gpios", 0, RT_NULL, RT_NULL); + + if (pin >= 0 && !crate_led_fops(idx, led_np, pin)) + { + ++idx; + } + } + + rt_ofw_node_put(leds_np); + + return RT_EOK; +} +INIT_APP_EXPORT(led_init); + +#endif /* RT_USING_PIN */ diff --git a/bsp/rockchip/rk3308/applications/main.c b/bsp/rockchip/rk3308/applications/main.c new file mode 100644 index 000000000000..27b230e675b5 --- /dev/null +++ b/bsp/rockchip/rk3308/applications/main.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017-5-30 Bernard the first version + */ + +#include +#include + +int main(int argc, char** argv) +{ + const char *oem; + +#ifdef RT_USING_SMART + oem = "Smart"; +#else + oem = "Thread"; +#endif + + rt_ubase_t level = rt_hw_interrupt_disable(); + + rt_kprintf("Hi, this is RT-%s!!\n", oem); + + rt_hw_interrupt_enable(level); + + return 0; +} diff --git a/bsp/rockchip/rk3308/driver/SConscript b/bsp/rockchip/rk3308/driver/SConscript new file mode 100644 index 000000000000..17f80c100b7c --- /dev/null +++ b/bsp/rockchip/rk3308/driver/SConscript @@ -0,0 +1,19 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +list = os.listdir(cwd) +CPPPATH = [cwd] +objs = [] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/bsp/rockchip/rk3308/driver/board.c b/bsp/rockchip/rk3308/driver/board.c new file mode 100644 index 000000000000..e3295faa15d7 --- /dev/null +++ b/bsp/rockchip/rk3308/driver/board.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-21 GuEe-GUI the first version + */ + +#include +#include + +void rt_hw_board_init(void) +{ + rt_fdt_commit_memregion_early(&(rt_region_t) + { + .name = "memheap", + .start = (rt_size_t)rt_kmem_v2p(HEAP_BEGIN), + .end = (rt_size_t)rt_kmem_v2p(HEAP_END), + }, RT_TRUE); + + rt_hw_common_setup(); +} diff --git a/bsp/rockchip/rk3308/driver/board.h b/bsp/rockchip/rk3308/driver/board.h new file mode 100644 index 000000000000..53318a1dc39f --- /dev/null +++ b/bsp/rockchip/rk3308/driver/board.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017-5-30 Bernard the first version + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +#include + +extern unsigned char __bss_start; +extern unsigned char __bss_end; + +#define HEAP_BEGIN (void *)&__bss_end +#define HEAP_END ((void *)HEAP_BEGIN + 64 * 1024 * 1024) + +void rt_hw_board_init(void); + +#endif /* __BOARD_H__ */ diff --git a/bsp/rockchip/rk3308/rtconfig.h b/bsp/rockchip/rk3308/rtconfig.h new file mode 100644 index 000000000000..eb500f1dcaa0 --- /dev/null +++ b/bsp/rockchip/rk3308/rtconfig.h @@ -0,0 +1,368 @@ +#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ + +/* Automatically generated file; DO NOT EDIT. */ +/* RT-Thread Project Configuration */ + +/* RT-Thread Kernel */ + +#define RT_NAME_MAX 16 +#define RT_USING_SMART +#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 +#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 4096 +#define SYSTEM_THREAD_STACK_SIZE 4096 +#define RT_USING_TIMER_SOFT +#define RT_TIMER_THREAD_PRIO 4 +#define RT_TIMER_THREAD_STACK_SIZE 4096 + +/* kservice optimization */ + +#define RT_KPRINTF_USING_LONGLONG +#define RT_DEBUG +#define RT_DEBUG_COLOR + +/* Inter-Thread communication */ + +#define RT_USING_SEMAPHORE +#define RT_USING_MUTEX +#define RT_USING_EVENT +#define RT_USING_MAILBOX +#define RT_USING_MESSAGEQUEUE + +/* Memory Management */ + +#define RT_PAGE_MAX_ORDER 11 +#define RT_USING_MEMPOOL +#define RT_USING_SMALL_MEM +#define RT_USING_MEMHEAP +#define RT_MEMHEAP_FAST_MODE +#define RT_USING_SMALL_MEM_AS_HEAP +#define RT_USING_MEMTRACE +#define RT_USING_HEAP + +/* Kernel Device Object */ + +#define RT_USING_DEVICE +#define RT_USING_DEVICE_OPS +#define RT_USING_DM +#define RT_USING_DM_FDT +#define RT_USING_INTERRUPT_INFO +#define RT_USING_CONSOLE +#define RT_CONSOLEBUF_SIZE 256 +#define RT_CONSOLE_DEVICE_NAME "uart2" +#define RT_VER_NUM 0x50001 + +/* RT-Thread Architecture */ + +#define ARCH_CPU_64BIT +#define RT_USING_CACHE +#define RT_USING_HW_ATOMIC +#define ARCH_MM_MMU +#define ARCH_ARM +#define ARCH_ARM_MMU +#define KERNEL_VADDR_START 0xffff000000000000 +#define ARCH_ARMV8 +#define ARCH_ARMV8_EXTENSIONS 0 +#define ARCH_TEXT_OFFSET 0x200000 +#define ARCH_RAM_OFFSET 0x0 +#define ARCH_ASPACE_SIZE 0xffffffff +#define ARCH_SECONDARY_CPU_STACK_SIZE 4096 +#define ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN +#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 8192 +#define FINSH_USING_HISTORY +#define FINSH_HISTORY_LINES 5 +#define FINSH_USING_SYMTAB +#define FINSH_CMD_SIZE 80 +#define MSH_USING_BUILT_IN_COMMANDS +#define FINSH_USING_DESCRIPTION +#define FINSH_ARG_MAX 10 + +/* DFS: device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_POSIX +#define DFS_USING_WORKDIR +#define DFS_FD_MAX 16 +#define RT_USING_DFS_V1 +#define DFS_FILESYSTEMS_MAX 4 +#define DFS_FILESYSTEM_TYPES_MAX 4 +#define RT_USING_DFS_ELMFAT + +/* elm-chan's FatFs, Generic FAT Filesystem Module */ + +#define RT_DFS_ELM_CODE_PAGE 437 +#define RT_DFS_ELM_WORD_ACCESS +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_LFN_UNICODE_0 +#define RT_DFS_ELM_LFN_UNICODE 0 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 2 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 +#define RT_DFS_ELM_REENTRANT +#define RT_DFS_ELM_MUTEX_TIMEOUT 3000 +#define RT_USING_DFS_DEVFS +#define RT_USING_LWP +#define RT_LWP_MAX_NR 30 +#define LWP_TASK_STACK_SIZE 16384 +#define RT_CH_MSG_MAX_NR 1024 +#define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024 +#define LWP_TID_MAX_NR 64 +#define RT_LWP_SHM_MAX_NR 64 + +/* Device Drivers */ + +#define RT_USING_TTY +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM +#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_ADC +#define RT_ADC_ROCKCHIP_SARADC +#define RT_USING_CLK +#define RT_CLK_ROCKCHIP +#define RT_CLK_ROCKCHIP_RK3308 +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_PSCI +#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_ROCKCHIP +#define RT_USING_HWTIMER +#define RT_HWTIMER_ARM_ARCH +#define RT_HWTIMER_ROCKCHIP +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS +#define RT_I2C_RK3X +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_PHY +#define RT_USING_PIC +#define MAX_HANDLERS 512 +#define RT_PIC_ARM_GIC +#define RT_PIC_ARM_GIC_MAX_NR 1 +#define RT_USING_PINCTRL +#define RT_PINCTRL_ROCKCHIP +#define RT_USING_PIN +#define RT_PIN_ROCKCHIP +#define RT_USING_PM +#define PM_TICKLESS_THRESHOLD_TIME 2 +#define RT_USING_PWM +#define RT_PWM_ROCKCHIP +#define RT_USING_REGULATOR +#define RT_REGULATOR_GPIO +#define RT_USING_RESET +#define RT_USING_RTC +#define RT_USING_ALARM +#define RT_RTC_RK_TIMER +#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_THREAD_PREORITY 22 +#define RT_MMCSD_MAX_PARTITION 16 +#define RT_SDIO_DW_MMC +#define RT_SDIO_DW_MMC_ROCKCHIP +#define RT_USING_SENSOR +#define RT_USING_SENSOR_CMD +#define RT_ADC_ROCKCHIP_TSADC +#define RT_USING_SERIAL +#define RT_USING_SERIAL_V1 +#define RT_SERIAL_RB_BUFSZ 64 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_DW +#define RT_USING_SOC +#define RT_SOC_ROCKCHIP +#define RT_SOC_ROCKCHIP_FIQ_DEBUGGER +#define RT_SOC_ROCKCHIP_IODOMAIN +#define RT_USING_SPI +#define RT_SPI_ROCKCHIP +#define RT_USING_WDT +#define RT_WDT_DW + +/* Using USB */ + + +/* C/C++ and POSIX layer */ + +#define RT_LIBC_DEFAULT_TIMEZONE 8 + +/* 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_TERMIOS +#define RT_USING_POSIX_DELAY +#define RT_USING_POSIX_CLOCK +#define RT_USING_POSIX_TIMER + +/* Interprocess Communication (IPC) */ + + +/* Socket is in the 'Network' category */ + + +/* Network */ + + +/* Utilities */ + +#define RT_USING_ADT +#define RT_USING_ADT_AVL +#define RT_USING_ADT_BITMAP +#define RT_USING_ADT_HASHMAP +#define RT_USING_ADT_REF + +/* RT-Thread Utestcases */ + + +/* RT-Thread online packages */ + +/* IoT - internet of things */ + + +/* Wi-Fi */ + +/* Marvell WiFi */ + + +/* Wiced WiFi */ + + +/* IoT Cloud */ + + +/* security packages */ + + +/* language packages */ + +/* JSON: JavaScript Object Notation, a lightweight data-interchange format */ + + +/* XML: Extensible Markup Language */ + + +/* multimedia packages */ + +/* LVGL: powerful and easy-to-use embedded GUI library */ + + +/* u8g2: a monochrome graphic library */ + + +/* tools packages */ + + +/* system packages */ + +/* enhanced kernel services */ + +#define PKG_USING_RT_VSNPRINTF_FULL +#define PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION + +/* acceleration: Assembly language or algorithmic acceleration packages */ + + +/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */ + + +/* Micrium: Micrium software products porting for RT-Thread */ + + +/* peripheral libraries and drivers */ + +/* sensors drivers */ + + +/* touch drivers */ + + +/* Kendryte SDK */ + + +/* AI packages */ + + +/* Signal Processing and Control Algorithm Packages */ + + +/* miscellaneous packages */ + +/* project laboratory */ + +/* samples: kernel and components samples */ + + +/* entertainment: terminal games and other interesting software packages */ + + +/* Arduino libraries */ + + +/* Projects */ + + +/* Sensors */ + + +/* Display */ + + +/* Timing */ + + +/* Data Processing */ + + +/* Data Storage */ + +/* Communication */ + + +/* Device Control */ + + +/* Other */ + + +/* Signal IO */ + + +/* Uncategorized */ + +#define SOC_RK3308 +#define RT_USING_AMBA_BUS + +#endif diff --git a/bsp/rockchip/rk3308/rtconfig.py b/bsp/rockchip/rk3308/rtconfig.py new file mode 100644 index 000000000000..8bd907eced1a --- /dev/null +++ b/bsp/rockchip/rk3308/rtconfig.py @@ -0,0 +1,54 @@ +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 = os.path.join(os.getcwd(), '..', '..', '..') + +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/' + +EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin' + +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' + + DEVICE = ' -g -march=armv8-a -mtune=cortex-a35 -fdiagnostics-color=always' + CPPFLAGS= ' -E -P -x assembler-with-cpp' + 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' + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -O0 -gdwarf-2' + AFLAGS += ' -gdwarf-2' + 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/rockchip/rk3568/.config b/bsp/rockchip/rk3568/.config index 772d3c6469b0..444214f7708f 100644 --- a/bsp/rockchip/rk3568/.config +++ b/bsp/rockchip/rk3568/.config @@ -6,10 +6,11 @@ # # RT-Thread Kernel # -CONFIG_RT_NAME_MAX=8 +CONFIG_RT_NAME_MAX=16 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set -# CONFIG_RT_USING_SMART is not set -# CONFIG_RT_USING_SMP is not set +CONFIG_RT_USING_SMART=y +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 @@ -22,6 +23,7 @@ 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=4096 +CONFIG_SYSTEM_THREAD_STACK_SIZE=4096 CONFIG_RT_USING_TIMER_SOFT=y CONFIG_RT_TIMER_THREAD_PRIO=4 CONFIG_RT_TIMER_THREAD_STACK_SIZE=4096 @@ -44,6 +46,7 @@ CONFIG_RT_DEBUG_COLOR=y # CONFIG_RT_DEBUG_MEM_CONFIG is not set # CONFIG_RT_DEBUG_SLAB_CONFIG is not set # CONFIG_RT_DEBUG_MEMHEAP_CONFIG is not set +# CONFIG_RT_DEBUG_PAGE_LEAK is not set # CONFIG_RT_DEBUG_MODULE_CONFIG is not set # @@ -80,13 +83,18 @@ CONFIG_RT_USING_HEAP=y # CONFIG_RT_USING_DEVICE=y CONFIG_RT_USING_DEVICE_OPS=y -# CONFIG_RT_USING_DM is not set -# CONFIG_RT_USING_INTERRUPT_INFO is not set +CONFIG_RT_USING_DM=y +CONFIG_RT_USING_DM_FDT=y +CONFIG_RT_USING_INTERRUPT_INFO=y CONFIG_RT_USING_CONSOLE=y -CONFIG_RT_CONSOLEBUF_SIZE=128 +CONFIG_RT_CONSOLEBUF_SIZE=256 CONFIG_RT_CONSOLE_DEVICE_NAME="uart2" -CONFIG_RT_VER_NUM=0x50000 +CONFIG_RT_VER_NUM=0x50001 # CONFIG_RT_USING_STDC_ATOMIC is not set + +# +# RT-Thread Architecture +# CONFIG_ARCH_CPU_64BIT=y CONFIG_RT_USING_CACHE=y CONFIG_RT_USING_HW_ATOMIC=y @@ -96,7 +104,14 @@ CONFIG_RT_USING_HW_ATOMIC=y CONFIG_ARCH_MM_MMU=y CONFIG_ARCH_ARM=y CONFIG_ARCH_ARM_MMU=y +CONFIG_KERNEL_VADDR_START=0xffff000000000000 CONFIG_ARCH_ARMV8=y +CONFIG_ARCH_ARMV8_EXTENSIONS=0 +CONFIG_ARCH_TEXT_OFFSET=0x200000 +CONFIG_ARCH_RAM_OFFSET=0x200000 +CONFIG_ARCH_ASPACE_SIZE=0xffffffff +CONFIG_ARCH_SECONDARY_CPU_STACK_SIZE=4096 +CONFIG_ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS=y # # RT-Thread Components @@ -111,7 +126,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_SYMTAB=y @@ -121,50 +136,232 @@ CONFIG_FINSH_USING_DESCRIPTION=y # CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set # CONFIG_FINSH_USING_AUTH is not set CONFIG_FINSH_ARG_MAX=10 -# CONFIG_RT_USING_DFS is not set + +# +# DFS: device virtual file system +# +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=4 +CONFIG_DFS_FILESYSTEM_TYPES_MAX=4 +CONFIG_RT_USING_DFS_ELMFAT=y + +# +# elm-chan's FatFs, Generic FAT Filesystem Module +# +CONFIG_RT_DFS_ELM_CODE_PAGE=437 +CONFIG_RT_DFS_ELM_WORD_ACCESS=y +# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set +CONFIG_RT_DFS_ELM_USE_LFN_3=y +CONFIG_RT_DFS_ELM_USE_LFN=3 +CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y +# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set +# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set +CONFIG_RT_DFS_ELM_LFN_UNICODE=0 +CONFIG_RT_DFS_ELM_MAX_LFN=255 +CONFIG_RT_DFS_ELM_DRIVES=2 +CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 +# CONFIG_RT_DFS_ELM_USE_ERASE is not set +CONFIG_RT_DFS_ELM_REENTRANT=y +CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 +CONFIG_RT_USING_DFS_DEVFS=y +# CONFIG_RT_USING_DFS_DIRECTFS 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_FAL is not set +CONFIG_RT_USING_LWP=y +CONFIG_RT_LWP_MAX_NR=30 +CONFIG_LWP_TASK_STACK_SIZE=16384 +CONFIG_RT_CH_MSG_MAX_NR=1024 +CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 +CONFIG_LWP_TID_MAX_NR=64 +CONFIG_RT_LWP_SHM_MAX_NR=64 +# CONFIG_LWP_UNIX98_PTY is not set # # Device Drivers # -CONFIG_RT_USING_DEVICE_IPC=y -CONFIG_RT_UNAMED_PIPE_NUMBER=64 -# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set -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_CAN is not set -# CONFIG_RT_USING_HWTIMER is not set +CONFIG_RT_USING_TTY=y +# CONFIG_RT_TTY_DEBUG is not set # CONFIG_RT_USING_CPUTIME is not set -# CONFIG_RT_USING_I2C is not set -# CONFIG_RT_USING_PHY is not set -CONFIG_RT_USING_PIN=y -# 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_MTD_NOR is not set -# CONFIG_RT_USING_MTD_NAND is not set -# CONFIG_RT_USING_PM is not set -# CONFIG_RT_USING_FDT is not set -# CONFIG_RT_USING_RTC is not set -# CONFIG_RT_USING_SDIO is not set -# CONFIG_RT_USING_SPI is not set -# CONFIG_RT_USING_WDT is not set -# CONFIG_RT_USING_AUDIO is not set -# CONFIG_RT_USING_SENSOR is not set +CONFIG_RT_USING_NULL=y +CONFIG_RT_USING_ZERO=y +CONFIG_RT_USING_RANDOM=y # CONFIG_RT_USING_TOUCH is not set # CONFIG_RT_USING_LCD is not set -# CONFIG_RT_USING_HWCRYPTO is not set # CONFIG_RT_USING_PULSE_ENCODER is not set # CONFIG_RT_USING_INPUT_CAPTURE is not set # CONFIG_RT_USING_DEV_BUS is not set # CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_UNAMED_PIPE_NUMBER=64 +CONFIG_RT_USING_SYSTEM_WORKQUEUE=y +CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192 +CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23 +CONFIG_RT_USING_ADC=y +CONFIG_RT_ADC_ROCKCHIP_SARADC=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_ROCKCHIP=y +CONFIG_RT_AUDIO_ROCKCHIP_I2S=y +CONFIG_RT_AUDIO_ROCKCHIP_I2S_TDM=y +CONFIG_RT_AUDIO_ROCKCHIP_PDM=y +CONFIG_RT_AUDIO_ROCKCHIP_SPDIF=y +CONFIG_RT_USING_CAN=y +# CONFIG_RT_CAN_USING_HDR is not set +CONFIG_RT_CAN_USING_CANFD=y +CONFIG_RT_CAN_CANFD_ROCKCHIP=y +CONFIG_RT_USING_CLK=y +CONFIG_RT_CLK_ROCKCHIP=y +# CONFIG_RT_CLK_ROCKCHIP_RK3308 is not set +CONFIG_RT_CLK_ROCKCHIP_RK3568=y +CONFIG_RT_USING_FIRMWARE=y +CONFIG_RT_FIRMWARE_PSCI=y +# CONFIG_RT_FIRMWARE_QEMU_FW_CFG is not set +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_ROCKCHIP=y +CONFIG_RT_USING_HWSPINLOCK=y +CONFIG_RT_HWSPINLOCK_ROCKCHIP=y +CONFIG_RT_USING_HWTIMER=y +CONFIG_RT_HWTIMER_ARM_ARCH=y +# CONFIG_RT_HWTIMER_BCM2835 is not set +CONFIG_RT_HWTIMER_ROCKCHIP=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_I2C_RK3X=y +CONFIG_RT_USING_MBOX=y +# CONFIG_RT_MBOX_BCM2835 is not set +CONFIG_RT_MBOX_ROCKCHIP=y +CONFIG_RT_USING_MFD=y +CONFIG_RT_MFD_SYSCON=y +CONFIG_RT_MFD_RK8XX=y +CONFIG_RT_MFD_RK8XX_I2C=y +# CONFIG_RT_MFD_RK8XX_SPI is not set +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_MTD_NOR 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_DIRECTFS is not set +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set +# CONFIG_RT_PCI_ECAM is not set +CONFIG_RT_PCI_DW_HOST=y +CONFIG_RT_PCI_DW_HOST_ROCKCHIP=y +CONFIG_RT_USING_PHY=y +CONFIG_RT_PHY_ROCKCHIP_NANENG_COMBO=y +CONFIG_RT_PHY_ROCKCHIP_SNPS_PCIE3=y +CONFIG_RT_USING_PIC=y +CONFIG_MAX_HANDLERS=512 +# CONFIG_RT_PIC_BCM2835_INTC is not set +# CONFIG_RT_PIC_BCM2836_L1_INTC is not set +# CONFIG_RT_PIC_ARM_GIC is not set +# CONFIG_RT_PIC_ARM_GIC_V2M is not set +CONFIG_RT_PIC_ARM_GIC_V3=y +# CONFIG_RT_PIC_ARM_GIC_V3_ITS is not set +CONFIG_RT_USING_PINCTRL=y +CONFIG_RT_PINCTRL_ROCKCHIP=y +CONFIG_RT_USING_PIN=y +# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_ROCKCHIP=y +CONFIG_RT_USING_PM=y +CONFIG_PM_TICKLESS_THRESHOLD_TIME=2 +# CONFIG_PM_USING_CUSTOM_CONFIG is not set +# CONFIG_PM_ENABLE_DEBUG is not set +# CONFIG_PM_ENABLE_SUSPEND_SLEEP_MODE is not set +# CONFIG_PM_ENABLE_THRESHOLD_SLEEP_MODE is not set +# CONFIG_RT_PM_BCM2835 is not set +# CONFIG_RT_PM_SYSCON_POWEROFF is not set +# CONFIG_RT_PM_SYSCON_REBOOT is not set +CONFIG_RT_USING_PWM=y +CONFIG_RT_PWM_ROCKCHIP=y +CONFIG_RT_USING_REGULATOR=y +CONFIG_RT_REGULATOR_GPIO=y +CONFIG_RT_REGULATOR_RK8XX=y +CONFIG_RT_USING_RESET=y +CONFIG_RT_USING_RTC=y +CONFIG_RT_USING_ALARM=y +# CONFIG_RT_USING_SOFT_RTC is not set +# CONFIG_RT_RTC_GOLDFISH is not set +CONFIG_RT_RTC_HYM8563=y +# CONFIG_RT_RTC_PL031 is not set +CONFIG_RT_RTC_RK8XX=y +# CONFIG_RT_RTC_RK_TIMER 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_THREAD_PREORITY=22 +CONFIG_RT_MMCSD_MAX_PARTITION=16 +# CONFIG_RT_SDIO_DEBUG is not set +CONFIG_RT_SDIO_SDHCI_DWCMSHC=y +CONFIG_RT_SDIO_DW_MMC=y +# CONFIG_RT_SDIO_DW_MMC_PCI is not set +CONFIG_RT_SDIO_DW_MMC_ROCKCHIP=y +CONFIG_RT_USING_SENSOR=y +CONFIG_RT_USING_SENSOR_CMD=y +CONFIG_RT_ADC_ROCKCHIP_TSADC=y +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_SERIAL_PL011 is not set +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_BCM2835AUX is not set +CONFIG_RT_SERIAL_8250_DW=y +# CONFIG_RT_SERIAL_8250_OFW is not set +# CONFIG_RT_SERIAL_8250_PCI is not set +CONFIG_RT_USING_SOC=y +CONFIG_RT_SOC_ROCKCHIP=y +CONFIG_RT_SOC_ROCKCHIP_FIQ_DEBUGGER=y +CONFIG_RT_SOC_ROCKCHIP_GRF=y +CONFIG_RT_SOC_ROCKCHIP_IODOMAIN=y +CONFIG_RT_USING_SPI=y +# CONFIG_RT_USING_SPI_BITOPS 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_ENC28J60 is not set +# CONFIG_RT_USING_SPI_WIFI is not set +CONFIG_RT_SPI_ROCKCHIP=y # CONFIG_RT_USING_VIRTIO is not set +CONFIG_RT_USING_WDT=y +# CONFIG_RT_WDT_BCM2835 is not set +CONFIG_RT_WDT_DW=y # # Using USB @@ -181,10 +378,18 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # # 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 is not set +# CONFIG_RT_USING_POSIX_SELECT 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 @@ -216,6 +421,10 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 # CONFIG_RT_USING_UTEST is not set # CONFIG_RT_USING_VAR_EXPORT is not set CONFIG_RT_USING_ADT=y +CONFIG_RT_USING_ADT_AVL=y +CONFIG_RT_USING_ADT_BITMAP=y +CONFIG_RT_USING_ADT_HASHMAP=y +CONFIG_RT_USING_ADT_REF=y # CONFIG_RT_USING_RT_LINK is not set # CONFIG_RT_USING_VBUS is not set @@ -452,7 +661,15 @@ CONFIG_RT_USING_ADT=y # # CONFIG_PKG_USING_RT_MEMCPY_CM is not set # CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set -# CONFIG_PKG_USING_RT_VSNPRINTF_FULL is not set +CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y +CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full" +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set +# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set +CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y +CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest" # # acceleration: Assembly language or algorithmic acceleration packages @@ -513,6 +730,7 @@ CONFIG_RT_USING_ADT=y # CONFIG_PKG_USING_QPC is not set # CONFIG_PKG_USING_AGILE_UPGRADE is not set # CONFIG_PKG_USING_FLASH_BLOB is not set +# CONFIG_PKG_USING_MLIBC is not set # # peripheral libraries and drivers @@ -609,7 +827,6 @@ CONFIG_RT_USING_ADT=y # CONFIG_PKG_USING_LKDGUI is not set # CONFIG_PKG_USING_NRF5X_SDK is not set # CONFIG_PKG_USING_NRFX is not set -# CONFIG_PKG_USING_WM_LIBRARIES is not set # # Kendryte SDK @@ -667,14 +884,15 @@ CONFIG_RT_USING_ADT=y # CONFIG_PKG_USING_MISAKA_AT24CXX is not set # CONFIG_PKG_USING_MISAKA_RGB_BLING is not set # CONFIG_PKG_USING_LORA_MODEM_DRIVER is not set -# CONFIG_PKG_USING_BL_MCU_SDK is not set # CONFIG_PKG_USING_SOFT_SERIAL is not set # CONFIG_PKG_USING_MB85RS16 is not set # CONFIG_PKG_USING_RFM300 is not set # CONFIG_PKG_USING_IO_INPUT_FILTER is not set # CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set # CONFIG_PKG_USING_LRF_NV7LIDAR is not set +# CONFIG_PKG_USING_AIP650 is not set # CONFIG_PKG_USING_FINGERPRINT is not set +# CONFIG_PKG_USING_SPI_TOOLS is not set # # AI packages @@ -688,6 +906,7 @@ CONFIG_RT_USING_ADT=y # CONFIG_PKG_USING_ULAPACK is not set # CONFIG_PKG_USING_QUEST is not set # CONFIG_PKG_USING_NAXOS is not set +# CONFIG_PKG_USING_NCNN is not set # # Signal Processing and Control Algorithm Packages @@ -972,20 +1191,3 @@ CONFIG_RT_USING_ADT=y # Uncategorized # CONFIG_SOC_RK3568=y - -# -# Hardware Drivers Config -# -CONFIG_BSP_USING_UART=y -# CONFIG_RT_USING_UART0 is not set -# CONFIG_RT_USING_UART1 is not set -CONFIG_RT_USING_UART2=y -# CONFIG_RT_USING_UART3 is not set -# CONFIG_RT_USING_UART4 is not set -# CONFIG_RT_USING_UART5 is not set -# CONFIG_RT_USING_UART6 is not set -# CONFIG_RT_USING_UART7 is not set -# CONFIG_RT_USING_UART8 is not set -# CONFIG_RT_USING_UART9 is not set -CONFIG_BSP_USING_GIC=y -CONFIG_BSP_USING_GICV3=y diff --git a/bsp/rockchip/rk3568/Kconfig b/bsp/rockchip/rk3568/Kconfig index 8dc3754d64d4..29f614e59407 100644 --- a/bsp/rockchip/rk3568/Kconfig +++ b/bsp/rockchip/rk3568/Kconfig @@ -22,9 +22,8 @@ config SOC_RK3568 bool select ARCH_ARMV8 select ARCH_CPU_64BIT + select ARCH_ARM_MMU select RT_USING_CACHE select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN default y - -source "$BSP_DIR/driver/Kconfig" diff --git a/bsp/rockchip/rk3568/applications/led.c b/bsp/rockchip/rk3568/applications/led.c new file mode 100644 index 000000000000..bb90685d5ea9 --- /dev/null +++ b/bsp/rockchip/rk3568/applications/led.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-3-08 GuEe-GUI the first version + */ + +#include +#include +#include + +#define DBG_TAG "app.led" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_PIN + +struct led +{ + struct rt_device parent; + + char name[RT_NAME_MAX]; + + rt_base_t pin; + struct rt_device_pwm *pwm; + + rt_uint8_t status; +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 8192 +#define THREAD_TIMESLICE 10 + rt_thread_t flow; +}; + +static rt_ssize_t led_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_uint8_t status = ((char *)buffer)[0]; + struct led *led = rt_container_of(dev, struct led, parent); + static const char * const modes[] = + { + "none", + "default-on", + "timer", + "heartbeat", + }; + + if (status >= '0' && status <= '3') + { + led->status = status; + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, led, sizeof(*led)); + rt_thread_resume(led->flow); + + LOG_I("Switch %s to status = %c (%s)", led->name, status, modes[status - '0']); + } + else + { + LOG_E("Invalid status = %c, (0:%s 1:%s 2:%s 3:%s)", status, + modes[0], modes[1], modes[2], modes[3]); + } + + return size; +} + +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops led_ops = +{ + .write = led_write, +}; +#endif + +static void led_flow(void *param) +{ + struct led *led = param; + struct rt_device_pwm *pwm = led->pwm; + +_loop: + + switch (led->status) + { + case '0' ... '1': + rt_pin_mode(led->pin, PIN_MODE_OUTPUT); + rt_pin_write(led->pin, led->status - '0'); + rt_thread_suspend(led->flow); + rt_schedule(); + break; + + case '2': + if (pwm) + { + #ifdef RT_USING_PWM + rt_bool_t dir = RT_TRUE; + rt_uint32_t period = 500000, pulse = 0; + + rt_pwm_set(pwm, 0, period, pulse); + rt_pwm_enable(pwm, 0); + + while (led->status == '2') + { + rt_thread_mdelay(5); + + pulse += dir ? 5000 : -5000; + + if (pulse >= period) + { + dir = RT_FALSE; + } + + if (0 >= pulse) + { + dir = RT_TRUE; + } + + rt_pwm_set(pwm, 0, period, pulse); + } + + rt_pwm_disable(pwm, 0); + #endif + } + else + { + LOG_E("PWM not found"); + led->status = '1'; + } + + case '3': + rt_pin_mode(led->pin, PIN_MODE_OUTPUT); + + while (led->status == '3') + { + rt_pin_write(led->pin, PIN_HIGH); + rt_thread_mdelay(500); + + rt_pin_write(led->pin, PIN_LOW); + rt_thread_mdelay(500); + } + break; + } + + goto _loop; +} + +static rt_err_t crate_led_fops(int idx, struct rt_ofw_node *led_np, rt_base_t pin) +{ + int pin_bank = pin / 32; + char dev_name[RT_NAME_MAX]; + struct led *led = rt_calloc(1, sizeof(*led)); + + if (!led) + { + return -RT_ENOMEM; + } + + led->pin = pin; + + rt_strncpy(led->name, rt_ofw_node_full_name(led_np), sizeof(led->name)); + led->flow = rt_thread_create(led->name, led_flow, led, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + + if (!led->flow) + { + goto _fail; + } + +#ifdef RT_USING_PWM + for (int pwm_id = 0, goon = 1; goon; ++pwm_id) + { + rt_phandle gpio_phandle; + rt_uint32_t pwm_pin, pwm_pin_bank; + struct rt_ofw_node *pwm_pin_np; + + rt_snprintf(dev_name, sizeof(dev_name), "pwm%d", pwm_id); + led->pwm = (struct rt_device_pwm *)rt_device_find(dev_name); + + if (!led->pwm) + { + break; + } + + rt_ofw_prop_read_u32(led->pwm->parent.ofw_node, "pinctrl-0", &gpio_phandle); + pwm_pin_np = rt_ofw_find_node_by_phandle(gpio_phandle); + + if (!pwm_pin_np) + { + continue; + } + + if (!rt_ofw_prop_read_u32_index(pwm_pin_np, "rockchip,pins", 0, &pwm_pin_bank) && + !rt_ofw_prop_read_u32_index(pwm_pin_np, "rockchip,pins", 1, &pwm_pin) && + pwm_pin_bank == pin_bank && pwm_pin == led->pin) + { + rt_device_open(&led->pwm->parent, 0); + + goon = 0; + } + + rt_ofw_node_put(pwm_pin_np); + } +#endif /* RT_USING_PWM */ + + if (led->pwm) + { + led->status = '2'; + } + else + { + led->status = '1'; + } + + rt_thread_startup(led->flow); + + led->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + led->parent.ops = &led_ops; +#else + led->parent.write = led_write; +#endif + + rt_snprintf(dev_name, sizeof(dev_name), "led%d", idx); + rt_device_register(&led->parent, dev_name, RT_DEVICE_FLAG_WRONLY); + + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, led, sizeof(*led)); + + return RT_EOK; + +_fail: + return -RT_ERROR; +} + +static int led_init(void) +{ + int idx = 0; + struct rt_ofw_node *led_np, *leds_np; + + if (!rt_ofw_machine_is_compatible("radxa,rock3a")) + { + return -RT_ENOSYS; + } + + leds_np = rt_ofw_find_node_by_compatible(RT_NULL, "gpio-leds"); + + if (!leds_np) + { + return -RT_ENOSYS; + } + + rt_ofw_foreach_child_node(leds_np, led_np) + { + rt_base_t pin = rt_ofw_get_named_pin(led_np, "gpios", 0, RT_NULL, RT_NULL); + + if (pin >= 0 && !crate_led_fops(idx, led_np, pin)) + { + ++idx; + } + } + + rt_ofw_node_put(leds_np); + + return RT_EOK; +} +INIT_APP_EXPORT(led_init); + +#endif /* RT_USING_PIN */ diff --git a/bsp/rockchip/rk3568/applications/main.c b/bsp/rockchip/rk3568/applications/main.c index 780e49d0918c..27b230e675b5 100644 --- a/bsp/rockchip/rk3568/applications/main.c +++ b/bsp/rockchip/rk3568/applications/main.c @@ -8,11 +8,24 @@ * 2017-5-30 Bernard the first version */ +#include #include int main(int argc, char** argv) { - rt_kprintf("Hi, this is RT-Thread!!\n"); + const char *oem; + +#ifdef RT_USING_SMART + oem = "Smart"; +#else + oem = "Thread"; +#endif + + rt_ubase_t level = rt_hw_interrupt_disable(); + + rt_kprintf("Hi, this is RT-%s!!\n", oem); + + rt_hw_interrupt_enable(level); return 0; } diff --git a/bsp/rockchip/rk3568/driver/Kconfig b/bsp/rockchip/rk3568/driver/Kconfig deleted file mode 100644 index 55041eba5b39..000000000000 --- a/bsp/rockchip/rk3568/driver/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -menu "Hardware Drivers Config" - - 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 n - - config RT_USING_UART1 - bool "Enable UART 1" - default n - - config RT_USING_UART2 - bool "Enable UART 2" - default y - - 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 - - config RT_USING_UART6 - bool "Enable UART 6" - default n - - config RT_USING_UART7 - bool "Enable UART 7" - default n - - config RT_USING_UART8 - bool "Enable UART 8" - default n - - config RT_USING_UART9 - bool "Enable UART 9" - default n - endif - - config BSP_USING_GIC - bool - default y - - config BSP_USING_GICV3 - bool - default y - -endmenu diff --git a/bsp/rockchip/rk3568/driver/board.c b/bsp/rockchip/rk3568/driver/board.c index 592262cb4d58..6771c2f4c1c4 100644 --- a/bsp/rockchip/rk3568/driver/board.c +++ b/bsp/rockchip/rk3568/driver/board.c @@ -6,120 +6,20 @@ * Change Logs: * Date Author Notes * 2022-3-08 GuEe-GUI the first version + * 2023-02-21 GuEe-GUI move common init to setup */ -#include -#include - -#include -#include -#include -#include -#include -#include - +#include #include -#include - -struct mem_desc platform_mem_desc[] = -{ - {0x200000, 0x80000000, 0x200000, NORMAL_MEM}, - {UART0_MMIO_BASE, UART0_MMIO_BASE + 0x10000, UART0_MMIO_BASE, DEVICE_MEM}, - {UART1_MMIO_BASE, UART1_MMIO_BASE + 0x90000, UART1_MMIO_BASE, DEVICE_MEM}, - {GIC_PL600_DISTRIBUTOR_PPTR, GIC_PL600_DISTRIBUTOR_PPTR + 0x10000, GIC_PL600_DISTRIBUTOR_PPTR, DEVICE_MEM}, - {GIC_PL600_REDISTRIBUTOR_PPTR, GIC_PL600_REDISTRIBUTOR_PPTR + 0xc0000, GIC_PL600_REDISTRIBUTOR_PPTR, DEVICE_MEM}, -}; - -const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc) / sizeof(platform_mem_desc[0]); - -void idle_wfi(void) -{ - __asm__ volatile ("wfi"); -} 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(); - /* initialize uart */ - rt_hw_uart_init(); - /* initialize timer for os tick */ - rt_hw_gtimer_init(); - - rt_thread_idle_sethook(idle_wfi); - - // TODO porting to FDT-driven PSCI: arm_psci_init(PSCI_METHOD_SMC, RT_NULL, RT_NULL); - -#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(RT_SCHEDULE_IPI, rt_scheduler_ipi_handler); - arm_gic_umask(0, IRQ_ARM_IPI_KICK); -#endif -} - -void reboot(void) -{ - // TODO poring to FDT to use new PSCI: arm_psci_system_reboot(); -} -MSH_CMD_EXPORT(reboot, reboot...); - -#ifdef RT_USING_SMP -rt_uint64_t rt_cpu_mpidr_early[] = -{ - [0] = 0x81000000, - [1] = 0x81000100, - [2] = 0x81000200, - [3] = 0x81000300, -}; - -void rt_hw_secondary_cpu_up(void) -{ - int i; - extern void secondary_cpu_start(void); - - for (i = 1; i < RT_CPUS_NR; ++i) + rt_fdt_commit_memregion_early(&(rt_region_t) { - arm_psci_cpu_on(rt_cpu_mpidr_early[i], (rt_uint64_t)secondary_cpu_start); - } -} - -void secondary_cpu_c_start(void) -{ - rt_hw_mmu_init(); - rt_hw_spin_lock(&_cpus_lock); - - arm_gic_cpu_init(0, platform_get_gic_cpu_base()); - arm_gic_redist_init(0, platform_get_gic_redist_base()); - rt_hw_vector_init(); - rt_hw_gtimer_local_enable(); - arm_gic_umask(0, IRQ_ARM_IPI_KICK); + .name = "memheap", + .start = (rt_size_t)rt_kmem_v2p(HEAP_BEGIN), + .end = (rt_size_t)rt_kmem_v2p(HEAP_END), + }, RT_TRUE); - rt_kprintf("\rcall cpu %d on success\n", rt_hw_cpu_id()); - - rt_system_scheduler_start(); -} - -void rt_hw_secondary_cpu_idle_exec(void) -{ - __WFE(); + rt_hw_common_setup(); } -#endif diff --git a/bsp/rockchip/rk3568/driver/board.h b/bsp/rockchip/rk3568/driver/board.h index 9f57b7b0b6db..53318a1dc39f 100644 --- a/bsp/rockchip/rk3568/driver/board.h +++ b/bsp/rockchip/rk3568/driver/board.h @@ -11,18 +11,13 @@ #ifndef __BOARD_H__ #define __BOARD_H__ -#include +#include 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 +#define HEAP_BEGIN (void *)&__bss_end +#define HEAP_END ((void *)HEAP_BEGIN + 64 * 1024 * 1024) void rt_hw_board_init(void); diff --git a/bsp/rockchip/rk3568/driver/drv_uart.c b/bsp/rockchip/rk3568/driver/drv_uart.c deleted file mode 100644 index 477c2f077d1a..000000000000 --- a/bsp/rockchip/rk3568/driver/drv_uart.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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 - -/* - * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the - * LCR is written whilst busy. If it is, then a busy detect interrupt is - * raised, the LCR needs to be rewritten and the uart status register read. - */ - -#define UART_RX 0 /* In: Receive buffer */ -#define UART_TX 0 /* Out: Transmit buffer */ - -#define UART_DLL 0 /* Out: Divisor Latch Low */ -#define UART_DLM 1 /* Out: Divisor Latch High */ - -#define UART_IER 1 /* Out: Interrupt Enable Register */ -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ - -#define UART_SSR 0x22 /* In: Software Reset Register */ -#define UART_USR 0x1f /* UART Status Register */ - -#define UART_LCR 3 /* Out: Line Control Register */ -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ -#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ -#define UART_LCR_PARITY 0x8 /* Parity Enable */ -#define UART_LCR_STOP 0x4 /* Stop bits: 0=1 bit, 1=2 bits */ -#define UART_LCR_WLEN8 0x3 /* Wordlength: 8 bits */ - -#define UART_MCR 4 /* Out: Modem Control Register */ -#define UART_MCR_RTS 0x02 /* RTS complement */ - -#define UART_LSR 5 /* In: Line Status Register */ -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ -#define UART_LSR_DR 0x01 /* Receiver data ready */ - -#define UART_IIR 2 /* In: Interrupt ID Register */ -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */ -#define UART_IIR_RX_TIMEOUT 0x0c /* OMAP RX Timeout interrupt */ - -#define UART_FCR 2 /* Out: FIFO Control Register */ -#define UART_FCR_EN_FIFO 0x01 /* Enable the FIFO */ -#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ -#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ - -#define UART_REG_SHIFT 0x2 /* Register Shift*/ -#define UART_INPUT_CLK 24000000 - -struct hw_uart_device -{ - rt_ubase_t hw_base; - rt_uint32_t irqno; -#ifdef RT_USING_SMP - struct rt_spinlock spinlock; -#endif -}; - -#define BSP_DEFINE_UART_DEVICE(no) \ -static struct hw_uart_device _uart##no##_device = \ -{ \ - UART##no##_MMIO_BASE, \ - UART##no##_IRQ \ -}; \ -static struct rt_serial_device _serial##no; - -#ifdef RT_USING_UART0 -BSP_DEFINE_UART_DEVICE(0); -#endif - -#ifdef RT_USING_UART1 -BSP_DEFINE_UART_DEVICE(1); -#endif - -#ifdef RT_USING_UART2 -BSP_DEFINE_UART_DEVICE(2); -#endif - -#ifdef RT_USING_UART3 -BSP_DEFINE_UART_DEVICE(3); -#endif - -#ifdef RT_USING_UART4 -BSP_DEFINE_UART_DEVICE(4); -#endif - -#ifdef RT_USING_UART5 -BSP_DEFINE_UART_DEVICE(5); -#endif - -#ifdef RT_USING_UART6 -BSP_DEFINE_UART_DEVICE(6); -#endif - -#ifdef RT_USING_UART7 -BSP_DEFINE_UART_DEVICE(7); -#endif - -#ifdef RT_USING_UART8 -BSP_DEFINE_UART_DEVICE(8); -#endif - -#ifdef RT_USING_UART9 -BSP_DEFINE_UART_DEVICE(9); -#endif - -rt_inline rt_uint32_t dw8250_read32(rt_ubase_t addr, rt_ubase_t offset) -{ - return *((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT))); -} - -rt_inline void dw8250_write32(rt_ubase_t addr, rt_ubase_t offset, rt_uint32_t value) -{ - *((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT))) = value; - - if (offset == UART_LCR) - { - int tries = 1000; - - /* Make sure LCR write wasn't ignored */ - while (tries--) - { - unsigned int lcr = dw8250_read32(addr, UART_LCR); - - if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) - { - return; - } - - dw8250_write32(addr, UART_FCR, UART_FCR_EN_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - dw8250_read32(addr, UART_RX); - - *((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT))) = value; - } - } -} - -static rt_err_t dw8250_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) -{ - rt_base_t base, rate; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - base = uart->hw_base; - -#ifdef RT_USING_SMP - rt_spin_lock_init(&uart->spinlock); -#endif - - /* Resset UART */ - dw8250_write32(base, UART_SSR, 1); - dw8250_write32(base, UART_SSR, 0); - - dw8250_write32(base, UART_IER, !UART_IER_RDI); - dw8250_write32(base, UART_FCR, UART_FCR_EN_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - - /* Disable flow ctrl */ - dw8250_write32(base, UART_MCR, 0); - /* Clear RTS */ - dw8250_write32(base, UART_MCR, dw8250_read32(base, UART_MCR) | UART_MCR_RTS); - - rate = UART_INPUT_CLK / 16 / serial->config.baud_rate; - - /* Enable access DLL & DLH */ - dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) | UART_LCR_DLAB); - dw8250_write32(base, UART_DLL, (rate & 0xff)); - dw8250_write32(base, UART_DLM, (rate & 0xff00) >> 8); - /* Clear DLAB bit */ - dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_DLAB)); - - dw8250_write32(base, UART_LCR, (dw8250_read32(base, UART_LCR) & (~UART_LCR_WLEN8)) | UART_LCR_WLEN8); - dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_STOP)); - dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_PARITY)); - - dw8250_write32(base, UART_IER, UART_IER_RDI); - - return RT_EOK; -} - -static rt_err_t dw8250_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 */ - dw8250_write32(uart->hw_base, UART_IER, !UART_IER_RDI); - rt_hw_interrupt_mask(uart->irqno); - break; - - case RT_DEVICE_CTRL_SET_INT: - /* Enable rx irq */ - dw8250_write32(uart->hw_base, UART_IER, UART_IER_RDI); - rt_hw_interrupt_umask(uart->irqno); - break; - } - - return RT_EOK; -} - -static int dw8250_uart_putc(struct rt_serial_device *serial, char c) -{ - rt_base_t base; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - base = uart->hw_base; - - while ((dw8250_read32(base, UART_USR) & 0x2) == 0) - { - } - - dw8250_write32(base, UART_TX, c); - - return 1; -} - -static int dw8250_uart_getc(struct rt_serial_device *serial) -{ - int ch = -1; - rt_base_t base; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - base = uart->hw_base; - - if ((dw8250_read32(base, UART_LSR) & 0x1)) - { - ch = dw8250_read32(base, UART_RX) & 0xff; - } - - return ch; -} - -static const struct rt_uart_ops _uart_ops = -{ - dw8250_uart_configure, - dw8250_uart_control, - dw8250_uart_putc, - dw8250_uart_getc, -}; - -static void rt_hw_uart_isr(int irqno, void *param) -{ - unsigned int iir, status; - struct rt_serial_device *serial = (struct rt_serial_device *)param; - struct hw_uart_device *uart = (struct hw_uart_device *)serial->parent.user_data; - - iir = dw8250_read32(uart->hw_base, UART_IIR); - - /* If don't do this in non-DMA mode then the "RX TIMEOUT" interrupt will fire forever. */ - if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) - { -#ifdef RT_USING_SMP - rt_base_t level = rt_spin_lock_irqsave(&uart->spinlock); -#endif - - status = dw8250_read32(uart->hw_base, UART_LSR); - - if (!(status & (UART_LSR_DR | UART_LSR_BI))) - { - dw8250_read32(uart->hw_base, UART_RX); - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&uart->spinlock, level); -#endif - } - - if (!(iir & UART_IIR_NO_INT)) - { - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); - } - - if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) - { - /* Clear the USR */ - dw8250_read32(uart->hw_base, UART_USR); - - return; - } -} - -int rt_hw_uart_init(void) -{ - struct hw_uart_device *uart; - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - - config.baud_rate = 1500000; - -#define BSP_INSTALL_UART_DEVICE(no) \ - uart = &_uart##no##_device; \ - _serial##no.ops = &_uart_ops; \ - _serial##no.config = config; \ - rt_hw_serial_register(&_serial##no, "uart" #no, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); \ - rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, &_serial##no, "uart" #no); - -#ifdef RT_USING_UART0 - BSP_INSTALL_UART_DEVICE(0); -#endif - -#ifdef RT_USING_UART1 - BSP_INSTALL_UART_DEVICE(1); -#endif - -#ifdef RT_USING_UART2 - BSP_INSTALL_UART_DEVICE(2); -#endif - -#ifdef RT_USING_UART3 - BSP_INSTALL_UART_DEVICE(3); -#endif - -#ifdef RT_USING_UART4 - BSP_INSTALL_UART_DEVICE(4); -#endif - -#ifdef RT_USING_UART5 - BSP_INSTALL_UART_DEVICE(5); -#endif - -#ifdef RT_USING_UART6 - BSP_INSTALL_UART_DEVICE(6); -#endif - -#ifdef RT_USING_UART7 - BSP_INSTALL_UART_DEVICE(7); -#endif - -#ifdef RT_USING_UART8 - BSP_INSTALL_UART_DEVICE(8); -#endif - -#ifdef RT_USING_UART9 - BSP_INSTALL_UART_DEVICE(9); -#endif - - return 0; -} diff --git a/bsp/rockchip/rk3568/driver/rk3568.h b/bsp/rockchip/rk3568/driver/rk3568.h deleted file mode 100644 index c170940ca2eb..000000000000 --- a/bsp/rockchip/rk3568/driver/rk3568.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 - */ - -#ifndef __RK3568_H__ -#define __RK3568_H__ - -#include - -/* UART */ -#define UART_MMIO_BASE 0xfe650000 -#define UART0_MMIO_BASE 0xfdd50000 -#define UART1_MMIO_BASE (UART_MMIO_BASE + 0) -#define UART2_MMIO_BASE (UART_MMIO_BASE + 0x10000) -#define UART3_MMIO_BASE (UART_MMIO_BASE + 0x20000) -#define UART4_MMIO_BASE (UART_MMIO_BASE + 0x30000) -#define UART5_MMIO_BASE (UART_MMIO_BASE + 0x40000) -#define UART6_MMIO_BASE (UART_MMIO_BASE + 0x50000) -#define UART7_MMIO_BASE (UART_MMIO_BASE + 0x60000) -#define UART8_MMIO_BASE (UART_MMIO_BASE + 0x70000) -#define UART9_MMIO_BASE (UART_MMIO_BASE + 0x80000) - -#define UART_MMIO_SIZE 0x100 - -#define UART_IRQ_BASE (32 + 116) -#define UART0_IRQ (UART_IRQ_BASE + 0) -#define UART1_IRQ (UART_IRQ_BASE + 1) -#define UART2_IRQ (UART_IRQ_BASE + 2) -#define UART3_IRQ (UART_IRQ_BASE + 3) -#define UART4_IRQ (UART_IRQ_BASE + 4) -#define UART5_IRQ (UART_IRQ_BASE + 5) -#define UART6_IRQ (UART_IRQ_BASE + 6) -#define UART7_IRQ (UART_IRQ_BASE + 7) -#define UART8_IRQ (UART_IRQ_BASE + 8) -#define UART9_IRQ (UART_IRQ_BASE + 9) - -/* GPIO */ -#define GPIO0_MMIO_BASE 0xfdd60000 -#define GPIO1_MMIO_BASE 0xfe740000 -#define GPIO2_MMIO_BASE 0xfe750000 -#define GPIO3_MMIO_BASE 0xfe760000 -#define GPIO4_MMIO_BASE 0xfe770000 - -#define GPIO_MMIO_SIZE 0x100 - -#define GPIO_IRQ_BASE (32 + 33) -#define GPIO0_IRQ (GPIO_IRQ_BASE + 0) -#define GPIO1_IRQ (GPIO_IRQ_BASE + 1) -#define GPIO2_IRQ (GPIO_IRQ_BASE + 2) -#define GPIO3_IRQ (GPIO_IRQ_BASE + 3) -#define GPIO4_IRQ (GPIO_IRQ_BASE + 4) - -/* MMC */ -#define MMC0_MMIO_BASE 0xfe310000 /* sdhci */ -#define MMC1_MMIO_BASE 0xfe2b0000 /* sdmmc0 */ -#define MMC2_MMIO_BASE 0xfe2c0000 /* sdmmc1 */ -#define MMC3_MMIO_BASE 0xfe000000 /* sdmmc2 */ - -#define MMC0_MMIO_SIZE 0x10000 -#define MMC_MMIO_SIZE 0x4000 - -#define MMC0_IRQ (32 + 19) -#define MMC1_IRQ (32 + 98) -#define MMC2_IRQ (32 + 99) -#define MMC3_IRQ (32 + 100) - -/* Ethernet */ -#define GMAC0_MMIO_BASE 0xfe2a0000 -#define GMAC1_MMIO_BASE 0xfe010000 - -#define GMAC_MMIO_SIZE 0x10000 - -#define GMAC0_MAC_IRQ (32 + 27) -#define GMAC0_WAKE_IRQ (32 + 24) -#define GMAC1_MAC_IRQ (32 + 32) -#define GMAC1_WAKE_IRQ (32 + 29) - -/* GIC */ -#define MAX_HANDLERS 256 -#define GIC_IRQ_START 0 -#define ARM_GIC_NR_IRQS 256 -#define ARM_GIC_MAX_NR 1 - -#define IRQ_ARM_IPI_KICK 0 -#define IRQ_ARM_IPI_CALL 1 - -#define GIC_PL600_DISTRIBUTOR_PPTR 0xfd400000 -#define GIC_PL600_REDISTRIBUTOR_PPTR 0xfd460000 -#define GIC_PL600_CONTROLLER_PPTR RT_NULL -#define GIC_PL600_ITS_PPTR 0xfd440000 - -rt_inline rt_uint32_t platform_get_gic_dist_base(void) -{ - return GIC_PL600_DISTRIBUTOR_PPTR; -} - -rt_inline rt_uint32_t platform_get_gic_redist_base(void) -{ - return GIC_PL600_REDISTRIBUTOR_PPTR; -} - -rt_inline rt_uint32_t platform_get_gic_cpu_base(void) -{ - return GIC_PL600_CONTROLLER_PPTR; -} - -rt_inline rt_uint32_t platform_get_gic_its_base(void) -{ - return GIC_PL600_ITS_PPTR; -} - -#endif /* __RK3568_H__ */ diff --git a/bsp/rockchip/rk3568/link.lds b/bsp/rockchip/rk3568/link.lds deleted file mode 100644 index dd62ae35d071..000000000000 --- a/bsp/rockchip/rk3568/link.lds +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2017-5-30 bernard first version - */ - -OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") -OUTPUT_ARCH(aarch64) - -SECTIONS -{ - . = 0x208000; - . = 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) - - . = ALIGN(16); - 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/rockchip/rk3568/rtconfig.h b/bsp/rockchip/rk3568/rtconfig.h index 93f112617855..55a4d644515b 100644 --- a/bsp/rockchip/rk3568/rtconfig.h +++ b/bsp/rockchip/rk3568/rtconfig.h @@ -6,7 +6,10 @@ /* RT-Thread Kernel */ -#define RT_NAME_MAX 8 +#define RT_NAME_MAX 16 +#define RT_USING_SMART +#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 @@ -17,6 +20,7 @@ #define RT_USING_IDLE_HOOK #define RT_IDLE_HOOK_LIST_SIZE 4 #define IDLE_THREAD_STACK_SIZE 4096 +#define SYSTEM_THREAD_STACK_SIZE 4096 #define RT_USING_TIMER_SOFT #define RT_TIMER_THREAD_PRIO 4 #define RT_TIMER_THREAD_STACK_SIZE 4096 @@ -50,17 +54,30 @@ #define RT_USING_DEVICE #define RT_USING_DEVICE_OPS +#define RT_USING_DM +#define RT_USING_DM_FDT +#define RT_USING_INTERRUPT_INFO #define RT_USING_CONSOLE -#define RT_CONSOLEBUF_SIZE 128 +#define RT_CONSOLEBUF_SIZE 256 #define RT_CONSOLE_DEVICE_NAME "uart2" -#define RT_VER_NUM 0x50000 +#define RT_VER_NUM 0x50001 + +/* RT-Thread Architecture */ + #define ARCH_CPU_64BIT #define RT_USING_CACHE #define RT_USING_HW_ATOMIC #define ARCH_MM_MMU #define ARCH_ARM #define ARCH_ARM_MMU +#define KERNEL_VADDR_START 0xffff000000000000 #define ARCH_ARMV8 +#define ARCH_ARMV8_EXTENSIONS 0 +#define ARCH_TEXT_OFFSET 0x200000 +#define ARCH_RAM_OFFSET 0x200000 +#define ARCH_ASPACE_SIZE 0xffffffff +#define ARCH_SECONDARY_CPU_STACK_SIZE 4096 +#define ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS /* RT-Thread Components */ @@ -73,7 +90,7 @@ #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 @@ -82,14 +99,145 @@ #define FINSH_USING_DESCRIPTION #define FINSH_ARG_MAX 10 +/* DFS: device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_POSIX +#define DFS_USING_WORKDIR +#define DFS_FD_MAX 16 +#define RT_USING_DFS_V1 +#define DFS_FILESYSTEMS_MAX 4 +#define DFS_FILESYSTEM_TYPES_MAX 4 +#define RT_USING_DFS_ELMFAT + +/* elm-chan's FatFs, Generic FAT Filesystem Module */ + +#define RT_DFS_ELM_CODE_PAGE 437 +#define RT_DFS_ELM_WORD_ACCESS +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_LFN_UNICODE_0 +#define RT_DFS_ELM_LFN_UNICODE 0 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 2 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 +#define RT_DFS_ELM_REENTRANT +#define RT_DFS_ELM_MUTEX_TIMEOUT 3000 +#define RT_USING_DFS_DEVFS +#define RT_USING_LWP +#define RT_LWP_MAX_NR 30 +#define LWP_TASK_STACK_SIZE 16384 +#define RT_CH_MSG_MAX_NR 1024 +#define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024 +#define LWP_TID_MAX_NR 64 +#define RT_LWP_SHM_MAX_NR 64 + /* Device Drivers */ +#define RT_USING_TTY +#define RT_USING_NULL +#define RT_USING_ZERO +#define RT_USING_RANDOM #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_ADC +#define RT_ADC_ROCKCHIP_SARADC +#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_ROCKCHIP +#define RT_AUDIO_ROCKCHIP_I2S +#define RT_AUDIO_ROCKCHIP_I2S_TDM +#define RT_AUDIO_ROCKCHIP_PDM +#define RT_AUDIO_ROCKCHIP_SPDIF +#define RT_USING_CAN +#define RT_CAN_USING_CANFD +#define RT_CAN_CANFD_ROCKCHIP +#define RT_USING_CLK +#define RT_CLK_ROCKCHIP +#define RT_CLK_ROCKCHIP_RK3568 +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_PSCI +#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_ROCKCHIP +#define RT_USING_HWSPINLOCK +#define RT_HWSPINLOCK_ROCKCHIP +#define RT_USING_HWTIMER +#define RT_HWTIMER_ARM_ARCH +#define RT_HWTIMER_ROCKCHIP +#define RT_USING_I2C +#define RT_USING_I2C_BITOPS +#define RT_I2C_RK3X +#define RT_USING_MBOX +#define RT_MBOX_ROCKCHIP +#define RT_USING_MFD +#define RT_MFD_SYSCON +#define RT_MFD_RK8XX +#define RT_MFD_RK8XX_I2C +#define RT_USING_OFW +#define RT_FDT_EARLYCON_MSG_SIZE 128 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 +#define RT_PCI_DW_HOST +#define RT_PCI_DW_HOST_ROCKCHIP +#define RT_USING_PHY +#define RT_PHY_ROCKCHIP_NANENG_COMBO +#define RT_PHY_ROCKCHIP_SNPS_PCIE3 +#define RT_USING_PIC +#define MAX_HANDLERS 512 +#define RT_PIC_ARM_GIC_V3 +#define RT_USING_PINCTRL +#define RT_PINCTRL_ROCKCHIP +#define RT_USING_PIN +#define RT_PIN_ROCKCHIP +#define RT_USING_PM +#define PM_TICKLESS_THRESHOLD_TIME 2 +#define RT_USING_PWM +#define RT_PWM_ROCKCHIP +#define RT_USING_REGULATOR +#define RT_REGULATOR_GPIO +#define RT_REGULATOR_RK8XX +#define RT_USING_RESET +#define RT_USING_RTC +#define RT_USING_ALARM +#define RT_RTC_HYM8563 +#define RT_RTC_RK8XX +#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_THREAD_PREORITY 22 +#define RT_MMCSD_MAX_PARTITION 16 +#define RT_SDIO_SDHCI_DWCMSHC +#define RT_SDIO_DW_MMC +#define RT_SDIO_DW_MMC_ROCKCHIP +#define RT_USING_SENSOR +#define RT_USING_SENSOR_CMD +#define RT_ADC_ROCKCHIP_TSADC #define RT_USING_SERIAL #define RT_USING_SERIAL_V1 #define RT_SERIAL_RB_BUFSZ 64 -#define RT_USING_PIN +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_DW +#define RT_USING_SOC +#define RT_SOC_ROCKCHIP +#define RT_SOC_ROCKCHIP_FIQ_DEBUGGER +#define RT_SOC_ROCKCHIP_GRF +#define RT_SOC_ROCKCHIP_IODOMAIN +#define RT_USING_SPI +#define RT_SPI_ROCKCHIP +#define RT_USING_WDT +#define RT_WDT_DW /* Using USB */ @@ -100,6 +248,13 @@ /* 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_TERMIOS +#define RT_USING_POSIX_DELAY +#define RT_USING_POSIX_CLOCK +#define RT_USING_POSIX_TIMER /* Interprocess Communication (IPC) */ @@ -113,6 +268,10 @@ /* Utilities */ #define RT_USING_ADT +#define RT_USING_ADT_AVL +#define RT_USING_ADT_BITMAP +#define RT_USING_ADT_HASHMAP +#define RT_USING_ADT_REF /* RT-Thread Utestcases */ @@ -159,6 +318,8 @@ /* enhanced kernel services */ +#define PKG_USING_RT_VSNPRINTF_FULL +#define PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION /* acceleration: Assembly language or algorithmic acceleration packages */ @@ -232,11 +393,4 @@ #define SOC_RK3568 -/* Hardware Drivers Config */ - -#define BSP_USING_UART -#define RT_USING_UART2 -#define BSP_USING_GIC -#define BSP_USING_GICV3 - #endif diff --git a/bsp/rockchip/rk3568/rtconfig.py b/bsp/rockchip/rk3568/rtconfig.py index 78fb406389a7..5612a030b6c9 100644 --- a/bsp/rockchip/rk3568/rtconfig.py +++ b/bsp/rockchip/rk3568/rtconfig.py @@ -16,8 +16,7 @@ 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') +EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin' BUILD = 'debug' @@ -26,6 +25,7 @@ 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 +34,8 @@ OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' - DEVICE = ' -g -march=armv8-a -mtune=cortex-a53' + DEVICE = ' -g -march=armv8-a -mtune=cortex-a55 -fdiagnostics-color=always' + CPPFLAGS= ' -E -P -x assembler-with-cpp' 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' diff --git a/components/dfs/dfs_v1/Kconfig b/components/dfs/dfs_v1/Kconfig index 0d003339f5d4..3ab2e350c05f 100644 --- a/components/dfs/dfs_v1/Kconfig +++ b/components/dfs/dfs_v1/Kconfig @@ -106,6 +106,12 @@ if RT_USING_DFS_V1 bool "Using devfs for device objects" default y + config RT_USING_DFS_DIRECTFS + bool "Enable filesystem for direct access rt_object" + select RT_USING_ADT_REF + depends on RT_USING_MEMHEAP + default n + config RT_USING_DFS_ROMFS bool "Enable ReadOnly file system on flash" default n diff --git a/components/dfs/dfs_v1/filesystems/directfs/SConscript b/components/dfs/dfs_v1/filesystems/directfs/SConscript new file mode 100644 index 000000000000..0a8493f6d125 --- /dev/null +++ b/components/dfs/dfs_v1/filesystems/directfs/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_DIRECTFS'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.c b/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.c new file mode 100644 index 000000000000..d1069a36c515 --- /dev/null +++ b/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-01 GuEe-GUI first version + */ + +#include +#include +#include +#include +#include +#include + +#include "dfs_directfs.h" + +struct directfs_entry +{ + rt_list_t list; + rt_list_t gift_list; + rt_list_t child_nodes; + + char *name; + rt_size_t name_len; + + struct directfs_entry *parent; + + rt_object_t obj; + struct directfs_bin_attribute *attr; +}; + +static struct rt_spinlock _directfs_lock = { 0 }; +static rt_size_t _directfs_base_len = RT_UINT32_MAX; +static rt_list_t _gift_nodes = RT_LIST_OBJECT_INIT(_gift_nodes); +static rt_list_t _directfs_root = RT_LIST_OBJECT_INIT(_directfs_root); +static struct directfs_bin_attribute _directfs_default_attr = +{ + .attr = + { + .name = RT_NULL, + }, +}; + +static struct directfs_entry *find_directfs_entry_by_object(rt_object_t object) +{ + struct directfs_entry *ret = RT_NULL, *entry; + + rt_spin_lock(&_directfs_lock); + + rt_list_for_each_entry(entry, &_gift_nodes, gift_list) + { + if (entry->obj == object) + { + ret = entry; + + break; + } + } + + rt_spin_unlock(&_directfs_lock); + + return ret; +} + +static rt_bool_t directfs_namecheck(const char *name, const char *path, rt_ssize_t len) +{ + rt_bool_t ret = RT_TRUE; + unsigned char c1, c2; + + while (len) + { + c1 = *name++; + c2 = *path++; + + if (c1 != c2) + { + ret = RT_FALSE; + break; + } + + if (!c1) + { + break; + } + + --len; + } + + if (len <= 0 && (*path && *path != '/')) + { + ret = RT_FALSE; + } + + return ret; +} + +static struct directfs_entry *find_directfs_entry_by_path(rt_object_t parent, const char *path) +{ + rt_list_t *root = &_directfs_root; + struct directfs_entry *entry = RT_NULL, *ret = RT_NULL; + static rt_object_t parent_cache = RT_NULL; + static struct directfs_entry *entry_cache = RT_NULL; + + if (parent) + { + root = RT_NULL; + + rt_spin_lock(&_directfs_lock); + + if (parent_cache == parent) + { + parent = parent_cache; + entry = entry_cache; + } + else + { + rt_spin_unlock(&_directfs_lock); + + entry = find_directfs_entry_by_object(parent); + + rt_spin_lock(&_directfs_lock); + + parent_cache = parent; + entry_cache = entry; + } + + rt_spin_unlock(&_directfs_lock); + + if (entry) + { + root = &entry->child_nodes; + entry = RT_NULL; + } + } + + rt_spin_lock(&_directfs_lock); + + while (root) + { + rt_bool_t next = RT_FALSE; + + rt_list_for_each_entry(entry, root, list) + { + if (directfs_namecheck(entry->name, path, entry->name_len)) + { + path += entry->name_len; + + if (*path) + { + /* Pass '/' */ + ++path; + next = RT_TRUE; + root = &entry->child_nodes; + } + else + { + next = RT_FALSE; + ret = entry; + } + + break; + } + } + + if (!next) + { + break; + } + } + + rt_spin_unlock(&_directfs_lock); + + return ret; +} + +rt_object_t dfs_directfs_find_object(rt_object_t parent, const char *path) +{ + rt_object_t ret = RT_NULL; + struct directfs_entry *entry = find_directfs_entry_by_path(parent, path); + + if (entry) + { + ret = entry->obj; + } + + return ret; +} + +static rt_err_t directfs_entry_init(struct directfs_entry *entry, rt_object_t object, const char *name) +{ + rt_err_t ret = RT_EOK; + + rt_list_init(&entry->list); + rt_list_init(&entry->gift_list); + rt_list_init(&entry->child_nodes); + + entry->name = rt_strdup(name); + + if (entry->name) + { + entry->name_len = rt_strlen(name); + + entry->obj = object; + entry->attr = &_directfs_default_attr; + } + else + { + ret = -RT_ENOMEM; + } + + return ret; +} + +rt_err_t dfs_directfs_create_link(rt_object_t parent, rt_object_t object, const char *name) +{ + rt_err_t ret = RT_EOK; + rt_list_t *child_nodes = RT_NULL; + struct directfs_entry *parent_entry = RT_NULL; + + if (object && name) + { + if (parent) + { + parent_entry = find_directfs_entry_by_object(parent); + + if (parent_entry) + { + child_nodes = &parent_entry->child_nodes; + } + } + else + { + child_nodes = &_directfs_root; + } + } + + if (child_nodes) + { + struct directfs_entry *entry = rt_malloc(sizeof(struct directfs_entry)); + + if (entry) + { + ret = directfs_entry_init(entry, object, name); + } + else + { + ret = -RT_ENOMEM; + } + + if (!ret) + { + rt_spin_lock(&_directfs_lock); + + rt_list_insert_before(child_nodes, &entry->list); + rt_list_insert_before(&_gift_nodes, &entry->gift_list); + + entry->parent = parent_entry; + + rt_spin_unlock(&_directfs_lock); + } + else + { + if (entry) + { + rt_free(entry); + } + } + } + else + { + ret = -RT_EINVAL; + } + + return ret; +} + +rt_err_t dfs_directfs_create_bin_file(rt_object_t object, struct directfs_bin_attribute *attr) +{ + rt_err_t ret = RT_EOK; + + if (object && attr && attr->attr.name) + { + struct directfs_entry *entry = find_directfs_entry_by_object(object); + + if (entry) + { + entry->attr = attr; + } + } + else + { + ret = -RT_EINVAL; + } + + return ret; +} + +static int dfs_directfs_open(struct dfs_file *file) +{ + int ret = -EIO; + + do { + struct directfs_entry *entry = RT_NULL; + + if (rt_strcmp(file->vnode->path, "/")) + { + entry = find_directfs_entry_by_path(RT_NULL, file->vnode->path + _directfs_base_len); + + if (!entry) + { + ret = -EIO; + break; + } + + if ((file->flags & O_DIRECTORY) && entry->attr->attr.name) + { + ret = -ENOENT; + break; + } + + file->vnode->size = entry->attr->attr.name ? 0 : rt_list_len(&entry->child_nodes); + } + else + { + file->vnode->size = rt_list_len(&_directfs_root); + } + + file->vnode->data = entry; + file->pos = 0; + + ret = 0; + } while (0); + + return ret; +} + +static int dfs_directfs_close(struct dfs_file *file) +{ + int ret = -EIO; + struct directfs_entry *entry = file->vnode->data; + + file->vnode->data = RT_NULL; + + if (entry) + { + ret = 0; + } + + return ret; +} + +static int dfs_directfs_read(struct dfs_file *file, void *buf, size_t count) +{ + int ret = 0; + struct directfs_entry *entry = file->vnode->data; + + if (entry && entry->attr->read && count > 0) + { + ret = entry->attr->read(entry->obj, entry->attr, buf, file->pos, count); + + if (ret > 0) + { + /* update file current position */ + file->pos += ret; + } + } + + return ret; +} + +static int dfs_directfs_write(struct dfs_file *file, const void *buf, size_t count) +{ + int ret = 0; + struct directfs_entry *entry = file->vnode->data; + + if (entry && entry->attr->write && count > 0) + { + ret = entry->attr->write(entry->obj, entry->attr, (void *)buf, file->pos, count); + + if (ret > 0) + { + /* update file current position */ + file->pos += ret; + } + } + + return ret; +} + +static int dfs_directfs_lseek(struct dfs_file *file, off_t offset) +{ + int ret = -EIO; + + if (offset <= file->vnode->size) + { + file->pos = offset; + ret = file->pos; + } + + return ret; +} + +static int dfs_directfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) +{ + int ret = -EIO; + rt_list_t *root = &_directfs_root; + struct directfs_entry *entry = file->vnode->data, *sub; + + /* make integer count */ + count = (count / sizeof(struct dirent)); + + if (entry) + { + root = &entry->child_nodes; + } + + if (count) + { + struct dirent *d; + rt_size_t index = 0, end = file->pos + count, count = 0; + + rt_list_for_each_entry(sub, root, list) + { + if (index >= (rt_size_t)file->pos) + { + rt_size_t eon; + + d = dirp + count; + + /* fill dirent */ + if (!sub->attr->attr.name) + { + d->d_type = DT_DIR; + } + else + { + d->d_type = DT_REG; + } + + eon = sub->name_len < DFS_PATH_MAX ? sub->name_len : DFS_PATH_MAX; + + d->d_namlen = sub->name_len; + d->d_reclen = (rt_uint16_t)sizeof(struct dirent); + rt_strncpy(d->d_name, sub->name, eon); + d->d_name[eon] = '\0'; + + ++count; + + /* move to next position */ + file->pos++; + } + + ++index; + + if (index >= end) + { + break; + } + } + + ret = count * sizeof(struct dirent); + } + else + { + ret = -EINVAL; + } + + return ret; +} + +static const struct dfs_file_ops _sys_fops = +{ + .open = dfs_directfs_open, + .close = dfs_directfs_close, + .read = dfs_directfs_read, + .write = dfs_directfs_write, + .lseek = dfs_directfs_lseek, + .getdents = dfs_directfs_getdents, +}; + +static int dfs_directfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data) +{ + int ret = RT_EOK; + + if (_directfs_base_len != RT_UINT32_MAX) + { + ret = -RT_EIO; + } + else + { + _directfs_base_len = 1; + } + + return ret; +} + +static int dfs_directfs_unmount(struct dfs_filesystem *fs) +{ + return RT_EOK; +} + +static int dfs_directfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st) +{ + rt_size_t size; + struct directfs_entry *entry = find_directfs_entry_by_path(RT_NULL, path + _directfs_base_len); + + st->st_dev = 0; + st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | + S_IWUSR | S_IWGRP | S_IWOTH; + + if (!entry->attr->attr.name) + { + st->st_mode &= ~S_IFREG; + st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + } + else + { + size = rt_list_len(&entry->child_nodes); + } + + st->st_size = size; + st->st_mtime = 0; + + return RT_EOK; +} + +static const struct dfs_filesystem_ops _directfs = +{ + .name = "direct", + .flags = DFS_FS_FLAG_DEFAULT, + .fops = &_sys_fops, + + .mount = dfs_directfs_mount, + .unmount = dfs_directfs_unmount, + .stat = dfs_directfs_stat, +}; + +int dfs_directfs_init(void) +{ + /* register direct file system */ + return dfs_register(&_directfs); +} +INIT_COMPONENT_EXPORT(dfs_directfs_init); diff --git a/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.h b/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.h new file mode 100644 index 000000000000..d8fd8a93877b --- /dev/null +++ b/components/dfs/dfs_v1/filesystems/directfs/dfs_directfs.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-01 GuEe-GUI first version + */ + +#ifndef __DFS_DIRECTFS_H__ +#define __DFS_DIRECTFS_H__ + +#include + +struct rt_varea; + +struct directfs_attribute +{ + const char *name; + rt_uint32_t mode; +}; + +struct directfs_bin_attribute +{ + struct directfs_attribute attr; + rt_size_t size; + + rt_ssize_t (*read)(rt_object_t, struct directfs_bin_attribute *, char *, rt_off_t, rt_size_t); + rt_ssize_t (*write)(rt_object_t, struct directfs_bin_attribute *, char *, rt_off_t, rt_size_t); + rt_err_t (*mmap)(rt_object_t, struct directfs_bin_attribute *attr, struct rt_varea *varea); +}; + +rt_object_t dfs_directfs_find_object(rt_object_t parent, const char *path); +rt_err_t dfs_directfs_create_link(rt_object_t parent, rt_object_t object, const char *name); +rt_err_t dfs_directfs_create_bin_file(rt_object_t object, struct directfs_bin_attribute *attr); + +int dfs_directfs_init(void); + +#endif /* __DFS_SYSFS_H__ */ diff --git a/components/dfs/dfs_v1/src/dfs_file.c b/components/dfs/dfs_v1/src/dfs_file.c index bc9ac3ccdc78..9fa5cf48e188 100644 --- a/components/dfs/dfs_v1/src/dfs_file.c +++ b/components/dfs/dfs_v1/src/dfs_file.c @@ -794,15 +794,16 @@ void ls(const char *pathname) if (dfs_file_stat(fullpath, &stat) == 0) { - rt_kprintf("%-20s", dirent.d_name); if (S_ISDIR(stat.st_mode)) { - rt_kprintf("%-25s\n", ""); + rt_kprintf("%*.s ", 11, ""); } else { - rt_kprintf("%-25lu\n", (unsigned long)stat.st_size); + rt_kprintf("%11d ", (unsigned long)stat.st_size); } + rt_kputs(dirent.d_name); + rt_kputs("\n"); } else rt_kprintf("BAD file: %s\n", dirent.d_name); diff --git a/components/dfs/dfs_v1/src/dfs_fs.c b/components/dfs/dfs_v1/src/dfs_fs.c index 42407367786a..64ce396bbb4b 100644 --- a/components/dfs/dfs_v1/src/dfs_fs.c +++ b/components/dfs/dfs_v1/src/dfs_fs.c @@ -269,7 +269,7 @@ int dfs_mount(const char *device_name, } /* Check if the path exists or not, raw APIs call, fixme */ - if ((strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0)) + if ((strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0) && (strcmp(fullpath, "/direct") != 0)) { struct dfs_file fd; diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c index fd97976cf113..761f25833e41 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -794,15 +794,16 @@ void ls(const char *pathname) if (dfs_file_stat(fullpath, &stat) == 0) { - rt_kprintf("%-20s", dirent.d_name); if (S_ISDIR(stat.st_mode)) { - rt_kprintf("%-25s\n", ""); + rt_kprintf("%*.s ", 11, ""); } else { - rt_kprintf("%-25lu\n", (unsigned long)stat.st_size); + rt_kprintf("%11d ", (unsigned long)stat.st_size); } + rt_kputs(dirent.d_name); + rt_kputs("\n"); } else rt_kprintf("BAD file: %s\n", dirent.d_name); diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index c6d327a6cfa7..5bda85eac11d 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -35,19 +35,6 @@ if RT_USING_TTY default n endif -config RT_USING_CAN - bool "Using CAN device drivers" - default n - -if RT_USING_CAN - config RT_CAN_USING_HDR - bool "Enable CAN hardware filter" - default n - config RT_CAN_USING_CANFD - bool "Enable CANFD support" - default n -endif - config RT_USING_CPUTIME bool "Enable CPU time for high resolution clock counter" default n @@ -83,34 +70,6 @@ if RT_USING_CPUTIME default 0 endif -config RT_USING_I2C - bool "Using I2C device drivers" - default n - -if RT_USING_I2C - config RT_I2C_DEBUG - bool "Use I2C debug message" - default n - - config RT_USING_I2C_BITOPS - bool "Use GPIO to simulate I2C" - default y - - if RT_USING_I2C_BITOPS - config RT_I2C_BITOPS_DEBUG - bool "Use simulate I2C debug message" - default n - endif -endif - -config RT_USING_PHY - bool "Using ethernet phy device drivers" - default n - -config RT_USING_ADC - bool "Using ADC device drivers" - default n - config RT_USING_DAC bool "Using DAC device drivers" default n @@ -127,141 +86,6 @@ config RT_USING_RANDOM bool "Using RANDOM device drivers" default n -config RT_USING_PWM - bool "Using PWM device drivers" - default n - -config RT_USING_SDIO - bool "Using SD/MMC device drivers" - default n - - if RT_USING_SDIO - config RT_SDIO_STACK_SIZE - int "The stack size for sdio irq thread" - default 512 - - config RT_SDIO_THREAD_PRIORITY - int "The priority level value of sdio irq thread" - default 15 - - config RT_MMCSD_STACK_SIZE - int "The stack size for mmcsd thread" - default 1024 - - config RT_MMCSD_THREAD_PREORITY - int "The priority level value of mmcsd thread" - default 22 - - config RT_MMCSD_MAX_PARTITION - int "mmcsd max partition" - default 16 - config RT_SDIO_DEBUG - bool "Enable SDIO debug log output" - default n - endif - -config RT_USING_SPI - bool "Using SPI Bus/Device device drivers" - default n - - if RT_USING_SPI - config RT_USING_SPI_BITOPS - select RT_USING_PIN - bool "Use GPIO to simulate SPI" - default n - - if RT_USING_SPI_BITOPS - config RT_SPI_BITOPS_DEBUG - bool "Use simulate SPI debug message" - default n - endif - - config RT_USING_QSPI - bool "Enable QSPI mode" - default n - - config RT_USING_SPI_MSD - bool "Using SD/TF card driver with spi" - select RT_USING_DFS - default n - - config RT_USING_SFUD - bool "Using Serial Flash Universal Driver" - default n - help - An using JEDEC's SFDP standard serial (SPI) flash universal driver library - - if RT_USING_SFUD - config RT_SFUD_USING_SFDP - bool "Using auto probe flash JEDEC SFDP parameter" - default y - - config RT_SFUD_USING_FLASH_INFO_TABLE - bool "Using defined supported flash chip information table" - default y - - config RT_SFUD_USING_QSPI - bool "Using QSPI mode support" - select RT_USING_QSPI - default n - - config RT_SFUD_SPI_MAX_HZ - int "Default spi maximum speed(HZ)" - range 0 50000000 - default 50000000 - help - Read the JEDEC SFDP command must run at 50 MHz or less,and you also can use rt_spi_configure(); to config spi speed. - - config RT_DEBUG_SFUD - bool "Show more SFUD debug information" - default n - endif - - config RT_USING_ENC28J60 - bool "Using ENC28J60 SPI Ethernet network interface" - select RT_USING_LWIP - default n - - config RT_USING_SPI_WIFI - bool "Using RW009/007 SPI Wi-Fi wireless interface" - select RT_USING_LWIP - default n - endif - -config RT_USING_WDT - bool "Using Watch Dog device drivers" - default n - -config RT_USING_AUDIO - bool "Using Audio device drivers" - default n - - if RT_USING_AUDIO - config RT_AUDIO_REPLAY_MP_BLOCK_SIZE - int "Replay memory pool block size" - default 4096 - - config RT_AUDIO_REPLAY_MP_BLOCK_COUNT - int "Replay memory pool block count" - default 2 - - config RT_AUDIO_RECORD_PIPE_SIZE - int "Record pipe size" - default 2048 - endif - -config RT_USING_SENSOR - bool "Using Sensor device drivers" - select RT_USING_PIN - default n - -if RT_USING_SENSOR - config RT_USING_SENSOR_CMD - bool "Using Sensor cmd" - select PKG_USING_RT_VSNPRINTF_FULL - default y -endif - config RT_USING_TOUCH bool "Using Touch device drivers" default n @@ -275,172 +99,6 @@ config RT_USING_LCD bool "Using LCD graphic drivers" default n -menuconfig RT_USING_HWCRYPTO - bool "Using Hardware Crypto drivers" - default n - - if RT_USING_HWCRYPTO - config RT_HWCRYPTO_DEFAULT_NAME - string "Hardware crypto device name" - default "hwcryto" - - config RT_HWCRYPTO_IV_MAX_SIZE - int "IV max size" - default "16" - - config RT_HWCRYPTO_KEYBIT_MAX_SIZE - int "Key max bit length" - default 256 - - config RT_HWCRYPTO_USING_GCM - bool "Using Hardware GCM" - default n - - config RT_HWCRYPTO_USING_AES - bool "Using Hardware AES" - default n - - if RT_HWCRYPTO_USING_AES - config RT_HWCRYPTO_USING_AES_ECB - bool "Using Hardware AES ECB mode" - default y - - config RT_HWCRYPTO_USING_AES_CBC - bool "Using Hardware AES CBC mode" - default n - - config RT_HWCRYPTO_USING_AES_CFB - bool "Using Hardware AES CFB mode" - default n - - config RT_HWCRYPTO_USING_AES_CTR - bool "Using Hardware AES CTR mode" - default n - - config RT_HWCRYPTO_USING_AES_OFB - bool "Using Hardware AES OFB mode" - default n - endif - - config RT_HWCRYPTO_USING_DES - bool "Using Hardware DES" - default n - - if RT_HWCRYPTO_USING_DES - config RT_HWCRYPTO_USING_DES_ECB - bool "Using Hardware DES ECB mode" - default y - - config RT_HWCRYPTO_USING_DES_CBC - bool "Using Hardware DES CBC mode" - default n - endif - - config RT_HWCRYPTO_USING_3DES - bool "Using Hardware 3DES" - default n - - if RT_HWCRYPTO_USING_3DES - config RT_HWCRYPTO_USING_3DES_ECB - bool "Using Hardware 3DES ECB mode" - default y - - config RT_HWCRYPTO_USING_3DES_CBC - bool "Using Hardware 3DES CBC mode" - default n - endif - - config RT_HWCRYPTO_USING_RC4 - bool "Using Hardware RC4" - default n - - config RT_HWCRYPTO_USING_MD5 - bool "Using Hardware MD5" - default n - - config RT_HWCRYPTO_USING_SHA1 - bool "Using Hardware SHA1" - default n - - config RT_HWCRYPTO_USING_SHA2 - bool "Using Hardware SHA2" - default n - - if RT_HWCRYPTO_USING_SHA2 - config RT_HWCRYPTO_USING_SHA2_224 - bool "Using Hardware SHA2_224 mode" - default n - - config RT_HWCRYPTO_USING_SHA2_256 - bool "Using Hardware SHA2_256 mode" - default y - - config RT_HWCRYPTO_USING_SHA2_384 - bool "Using Hardware SHA2_384 mode" - default n - - config RT_HWCRYPTO_USING_SHA2_512 - bool "Using Hardware SHA2_512 mode" - default n - endif - - config RT_HWCRYPTO_USING_RNG - bool "Using Hardware RNG" - default n - - config RT_HWCRYPTO_USING_CRC - bool "Using Hardware CRC" - default n - - if RT_HWCRYPTO_USING_CRC - config RT_HWCRYPTO_USING_CRC_07 - bool "Using Hardware CRC-8 0x07 polynomial" - default n - - config RT_HWCRYPTO_USING_CRC_8005 - bool "Using Hardware CRC-16 0x8005 polynomial" - default n - - config RT_HWCRYPTO_USING_CRC_1021 - bool "Using Hardware CRC-16 0x1021 polynomial" - default n - - config RT_HWCRYPTO_USING_CRC_3D65 - bool "Using Hardware CRC-16 0x3D65 polynomial" - default n - - config RT_HWCRYPTO_USING_CRC_04C11DB7 - bool "Using Hardware CRC-32 0x04C11DB7 polynomial" - default n - endif - - config RT_HWCRYPTO_USING_BIGNUM - bool "Using Hardware bignum" - default n - - if RT_HWCRYPTO_USING_BIGNUM - config RT_HWCRYPTO_USING_BIGNUM_EXPTMOD - bool "Using Hardware bignum expt_mod operation" - default y - - config RT_HWCRYPTO_USING_BIGNUM_MULMOD - bool "Using Hardware bignum mul_mod operation" - default y - - config RT_HWCRYPTO_USING_BIGNUM_MUL - bool "Using Hardware bignum mul operation" - default n - - config RT_HWCRYPTO_USING_BIGNUM_ADD - bool "Using Hardware bignum add operation" - default n - - config RT_HWCRYPTO_USING_BIGNUM_SUB - bool "Using Hardware bignum sub operation" - default n - endif - endif - config RT_USING_PULSE_ENCODER bool "Using PULSE ENCODER device drivers" default n @@ -611,19 +269,36 @@ menuconfig RT_USING_WIFI endif endif +source "$RTT_DIR/components/drivers/adc/Kconfig" +source "$RTT_DIR/components/drivers/audio/Kconfig" +source "$RTT_DIR/components/drivers/can/Kconfig" source "$RTT_DIR/components/drivers/clk/Kconfig" source "$RTT_DIR/components/drivers/firmware/Kconfig" +source "$RTT_DIR/components/drivers/hwcrypto/Kconfig" +source "$RTT_DIR/components/drivers/hwspinlock/Kconfig" source "$RTT_DIR/components/drivers/hwtimer/Kconfig" +source "$RTT_DIR/components/drivers/i2c/Kconfig" +source "$RTT_DIR/components/drivers/mailbox/Kconfig" source "$RTT_DIR/components/drivers/mfd/Kconfig" source "$RTT_DIR/components/drivers/mtd/Kconfig" source "$RTT_DIR/components/drivers/ofw/Kconfig" source "$RTT_DIR/components/drivers/pci/Kconfig" +source "$RTT_DIR/components/drivers/phy/Kconfig" source "$RTT_DIR/components/drivers/pic/Kconfig" +source "$RTT_DIR/components/drivers/pinctrl/Kconfig" source "$RTT_DIR/components/drivers/pin/Kconfig" source "$RTT_DIR/components/drivers/pm/Kconfig" +source "$RTT_DIR/components/drivers/pwm/Kconfig" +source "$RTT_DIR/components/drivers/regulator/Kconfig" +source "$RTT_DIR/components/drivers/reset/Kconfig" source "$RTT_DIR/components/drivers/rtc/Kconfig" +source "$RTT_DIR/components/drivers/sdio/Kconfig" +source "$RTT_DIR/components/drivers/sensor/Kconfig" source "$RTT_DIR/components/drivers/serial/Kconfig" +source "$RTT_DIR/components/drivers/soc/Kconfig" +source "$RTT_DIR/components/drivers/spi/Kconfig" source "$RTT_DIR/components/drivers/virtio/Kconfig" +source "$RTT_DIR/components/drivers/watchdog/Kconfig" menu "Using USB" config RT_USING_USB diff --git a/components/drivers/adc/Kconfig b/components/drivers/adc/Kconfig new file mode 100755 index 000000000000..8217dad9506f --- /dev/null +++ b/components/drivers/adc/Kconfig @@ -0,0 +1,11 @@ +menuconfig RT_USING_ADC + bool "Using ADC device drivers" + default n + +config RT_ADC_ROCKCHIP_SARADC + bool "Rockchip SARADC driver" + depends on RT_USING_DM + depends on RT_USING_ADC + select RT_USING_RESET + select RT_USING_REGULATOR + default n diff --git a/components/drivers/adc/SConscript b/components/drivers/adc/SConscript new file mode 100755 index 000000000000..b1843b1620fc --- /dev/null +++ b/components/drivers/adc/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_ADC']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['adc.c'] + +if GetDepend(['RT_ADC_ROCKCHIP_SARADC']): + src += ['adc-rockchip_saradc.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/adc/adc-rockchip_saradc.c b/components/drivers/adc/adc-rockchip_saradc.c new file mode 100644 index 000000000000..d45fcd1e2c3e --- /dev/null +++ b/components/drivers/adc/adc-rockchip_saradc.c @@ -0,0 +1,505 @@ +/* + * 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 SARADC_DATA 0x00 + +#define SARADC_STAS 0x04 +#define SARADC_STAS_BUSY RT_BIT(0) + +#define SARADC_CTRL 0x08 +#define SARADC_CTRL_IRQ_STATUS RT_BIT(6) +#define SARADC_CTRL_IRQ_ENABLE RT_BIT(5) +#define SARADC_CTRL_POWER_CTRL RT_BIT(3) +#define SARADC_CTRL_CHN_MASK 0x7 + +#define SARADC_DLY_PU_SOC 0x0c +#define SARADC_DLY_PU_SOC_MASK 0x3f + +#define SARADC_TIMEOUT rt_tick_from_millisecond(100) +#define SARADC_MAX_CHANNELS 8 + +/* v2 registers */ +#define SARADC2_CONV_CON 0x000 +#define SARADC_T_PD_SOC 0x004 +#define SARADC_T_DAS_SOC 0x00c +#define SARADC2_END_INT_EN 0x104 +#define SARADC2_ST_CON 0x108 +#define SARADC2_STATUS 0x10c +#define SARADC2_END_INT_ST 0x110 +#define SARADC2_DATA_BASE 0x120 + +#define SARADC2_EN_END_INT RT_BIT(0) +#define SARADC2_START RT_BIT(4) +#define SARADC2_SINGLE_MODE RT_BIT(5) + +#define SARADC2_CONV_CHANNELS RT_GENMASK(15, 0) + +struct saradc_channel +{ + int channel; + int scan_index; + + struct + { + char sign; + rt_uint8_t realbits; + rt_uint8_t storagebits; + rt_uint8_t repeat; + } scan_type; + + rt_base_t info_mask_separate; + rt_base_t info_mask_shared_by_type; + + const char *datasheet_name; +}; + +struct rockchip_saradc; + +struct rockchip_saradc_soc_data +{ + const struct saradc_channel *channels; + int num_channels; + + rt_ubase_t clk_rate; + void (*start)(struct rockchip_saradc *rk_saradc, int chn); + int (*read)(struct rockchip_saradc *rk_saradc); + void (*power_down)(struct rockchip_saradc *rk_saradc); +}; + +struct rockchip_saradc +{ + struct rt_adc_device parent; + + int irq; + void *regs; + struct rt_clk *clk; + struct rt_clk *pclk; + struct rt_regulator *vref; + struct rt_reset_control *rstc; + + const struct rockchip_saradc_soc_data *soc_data; + + rt_uint16_t last_val; + struct saradc_channel *last_chan; + + struct rt_mutex lock; + struct rt_completion completion; +}; + +#define raw_to_rockchip_saradc(raw) rt_container_of(raw, struct rockchip_saradc, parent) + +#define SARADC_CHANNEL(INDEX, ID, RES) \ +{ \ + .channel = INDEX, \ + .info_mask_separate = RT_BIT(0), \ + .info_mask_shared_by_type = RT_BIT(2), \ + .datasheet_name = ID, \ + .scan_index = INDEX, \ + .scan_type = \ + { \ + .sign = 'u', \ + .realbits = RES, \ + .storagebits = 16, \ + }, \ +} + +static void rockchip_saradc_start_v1(struct rockchip_saradc *rk_saradc, int chn) +{ + /* 8 clock periods as delay between power up and start cmd */ + HWREG32(rk_saradc->regs + SARADC_DLY_PU_SOC) = 8; + /* Select the channel to be used and trigger conversion */ + HWREG32(rk_saradc->regs + SARADC_CTRL) = SARADC_CTRL_POWER_CTRL | + (chn & SARADC_CTRL_CHN_MASK) | SARADC_CTRL_IRQ_ENABLE; +} + +static void rockchip_saradc_reset_controller(struct rockchip_saradc *rk_saradc); + +static void rockchip_saradc_start_v2(struct rockchip_saradc *rk_saradc, int chn) +{ + int val; + + if (rk_saradc->rstc) + { + rockchip_saradc_reset_controller(rk_saradc); + } + + HWREG32(rk_saradc->regs + SARADC_T_DAS_SOC) = 0xc; + HWREG32(rk_saradc->regs + SARADC_T_PD_SOC) = 0x20; + + val = RT_FIELD_PREP(SARADC2_EN_END_INT, 1); + val |= val << 16; + HWREG32(rk_saradc->regs + SARADC2_END_INT_EN) = val; + + val = RT_FIELD_PREP(SARADC2_START, 1) | + RT_FIELD_PREP(SARADC2_SINGLE_MODE, 1) | + RT_FIELD_PREP(SARADC2_CONV_CHANNELS, chn); + val |= val << 16; + HWREG32(rk_saradc->regs + SARADC2_CONV_CON) = val; +} + +static int rockchip_saradc_read_v1(struct rockchip_saradc *rk_saradc) +{ + return HWREG32(rk_saradc->regs + SARADC_DATA); +} + +static int rockchip_saradc_read_v2(struct rockchip_saradc *rk_saradc) +{ + int offset; + + /* Clear irq */ + HWREG32(rk_saradc->regs + SARADC2_END_INT_ST) = 0x1; + + offset = SARADC2_DATA_BASE + rk_saradc->last_chan->channel * 0x4; + + return HWREG32(rk_saradc->regs + offset); +} + +static void rockchip_saradc_power_down_v1(struct rockchip_saradc *rk_saradc) +{ + HWREG32(rk_saradc->regs + SARADC_CTRL) = 0; +} + +static const struct saradc_channel rockchip_saradc_channels[] = +{ + SARADC_CHANNEL(0, "adc0", 10), + SARADC_CHANNEL(1, "adc1", 10), + SARADC_CHANNEL(2, "adc2", 10), +}; + +static const struct rockchip_saradc_soc_data saradc_data = +{ + .channels = rockchip_saradc_channels, + .num_channels = RT_ARRAY_SIZE(rockchip_saradc_channels), + .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, +}; + +static const struct saradc_channel rk3066_tsadc_channels[] = +{ + SARADC_CHANNEL(0, "adc0", 12), + SARADC_CHANNEL(1, "adc1", 12), +}; + +static const struct rockchip_saradc_soc_data rk3066_tsadc_data = +{ + .channels = rk3066_tsadc_channels, + .num_channels = RT_ARRAY_SIZE(rk3066_tsadc_channels), + .clk_rate = 50000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, +}; + +static const struct saradc_channel rk3399_saradc_channels[] = +{ + SARADC_CHANNEL(0, "adc0", 10), + SARADC_CHANNEL(1, "adc1", 10), + SARADC_CHANNEL(2, "adc2", 10), + SARADC_CHANNEL(3, "adc3", 10), + SARADC_CHANNEL(4, "adc4", 10), + SARADC_CHANNEL(5, "adc5", 10), +}; + +static const struct rockchip_saradc_soc_data rk3399_saradc_data = +{ + .channels = rk3399_saradc_channels, + .num_channels = RT_ARRAY_SIZE(rk3399_saradc_channels), + .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, +}; + +static const struct saradc_channel rk3568_saradc_channels[] = +{ + SARADC_CHANNEL(0, "adc0", 10), + SARADC_CHANNEL(1, "adc1", 10), + SARADC_CHANNEL(2, "adc2", 10), + SARADC_CHANNEL(3, "adc3", 10), + SARADC_CHANNEL(4, "adc4", 10), + SARADC_CHANNEL(5, "adc5", 10), + SARADC_CHANNEL(6, "adc6", 10), + SARADC_CHANNEL(7, "adc7", 10), +}; + +static const struct rockchip_saradc_soc_data rk3568_saradc_data = +{ + .channels = rk3568_saradc_channels, + .num_channels = RT_ARRAY_SIZE(rk3568_saradc_channels), + .clk_rate = 1000000, + .start = rockchip_saradc_start_v1, + .read = rockchip_saradc_read_v1, + .power_down = rockchip_saradc_power_down_v1, +}; + +static const struct saradc_channel rk3588_saradc_channels[] = +{ + SARADC_CHANNEL(0, "adc0", 12), + SARADC_CHANNEL(1, "adc1", 12), + SARADC_CHANNEL(2, "adc2", 12), + SARADC_CHANNEL(3, "adc3", 12), + SARADC_CHANNEL(4, "adc4", 12), + SARADC_CHANNEL(5, "adc5", 12), + SARADC_CHANNEL(6, "adc6", 12), + SARADC_CHANNEL(7, "adc7", 12), +}; + +static const struct rockchip_saradc_soc_data rk3588_saradc_data = +{ + .channels = rk3588_saradc_channels, + .num_channels = RT_ARRAY_SIZE(rk3588_saradc_channels), + .clk_rate = 1000000, + .start = rockchip_saradc_start_v2, + .read = rockchip_saradc_read_v2, +}; + +static void rockchip_saradc_start(struct rockchip_saradc *rk_saradc, int chn) +{ + rk_saradc->soc_data->start(rk_saradc, chn); +} + +static int rockchip_saradc_read(struct rockchip_saradc *rk_saradc) +{ + return rk_saradc->soc_data->read(rk_saradc); +} + +static void rockchip_saradc_power_down(struct rockchip_saradc *rk_saradc) +{ + if (rk_saradc->soc_data->power_down) + { + rk_saradc->soc_data->power_down(rk_saradc); + } +} + +static rt_err_t rockchip_saradc_enabled(struct rt_adc_device *adc, rt_int8_t channel, rt_bool_t enabled) +{ + return RT_EOK; +} + +static rt_err_t rockchip_saradc_convert(struct rt_adc_device *adc, rt_int8_t channel, rt_uint32_t *value) +{ + rt_err_t err = RT_EOK; + struct rockchip_saradc *rk_saradc = raw_to_rockchip_saradc(adc); + + rt_mutex_take(&rk_saradc->lock, RT_WAITING_FOREVER); + + rk_saradc->last_chan = (struct saradc_channel *)&rk_saradc->soc_data->channels[channel]; + rockchip_saradc_start(rk_saradc, channel); + + /* Select the channel to be used and trigger conversion */ + HWREG32(rk_saradc->regs + SARADC_CTRL) =SARADC_CTRL_POWER_CTRL | + (channel & SARADC_CTRL_CHN_MASK) | SARADC_CTRL_IRQ_ENABLE; + + /* Delay 100ms */ + if (!(err = rt_completion_wait(&rk_saradc->completion, SARADC_TIMEOUT))) + { + *value = rk_saradc->last_val; + } + + rt_mutex_release(&rk_saradc->lock); + + return err; +} + +static const struct rt_adc_ops rockchip_saradc_ops = +{ + .enabled = rockchip_saradc_enabled, + .convert = rockchip_saradc_convert, +}; + +static void rockchip_saradc_isr(int irqno, void *param) +{ + struct rockchip_saradc *rk_saradc = (struct rockchip_saradc *)param; + + /* Read value */ + rk_saradc->last_val = rockchip_saradc_read(rk_saradc); + rk_saradc->last_val &= RT_GENMASK(rk_saradc->last_chan->scan_type.realbits - 1, 0); + + rockchip_saradc_power_down(rk_saradc); + + rt_completion_done(&rk_saradc->completion); +} + +static void rockchip_saradc_reset_controller(struct rockchip_saradc *rk_saradc) +{ + rt_reset_control_assert(rk_saradc->rstc); + rt_hw_us_delay(15); + rt_reset_control_deassert(rk_saradc->rstc); +} + +static void rockchip_saradc_free(struct rockchip_saradc *rk_saradc) +{ + if (rk_saradc->regs) + { + rt_iounmap(rk_saradc->regs); + } + + if (rk_saradc->rstc) + { + rt_reset_control_put(rk_saradc->rstc); + } + + if (rk_saradc->vref) + { + rt_regulator_disable(rk_saradc->vref); + } + + if (rk_saradc->clk) + { + rt_clk_disable(rk_saradc->clk); + rt_clk_put(rk_saradc->clk); + } + + if (rk_saradc->pclk) + { + rt_clk_disable(rk_saradc->pclk); + rt_clk_put(rk_saradc->pclk); + } + + rt_free(rk_saradc); +} + +static rt_err_t rockchip_saradc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + const struct rockchip_saradc_soc_data *soc_data = pdev->id->data; + struct rockchip_saradc *rk_saradc = rt_calloc(1, sizeof(*rk_saradc)); + + if (!rk_saradc) + { + return -RT_ENOMEM; + } + + rk_saradc->soc_data = soc_data; + rk_saradc->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_saradc->regs) + { + err = -RT_EIO; + goto _free_res; + } + + rk_saradc->irq = rt_dm_dev_get_irq(dev, 0); + + if (rk_saradc->irq < 0) + { + err = rk_saradc->irq; + goto _free_res; + } + + rk_saradc->vref = rt_regulator_get_optional(dev, "vref"); + + if (!rk_saradc->vref) + { + err = -RT_EIO; + goto _free_res; + } + + if (rt_dm_dev_prop_read_bool(dev, "resets")) + { + if (!(rk_saradc->rstc = rt_reset_control_get_by_name(dev, "saradc-apb"))) + { + err = -RT_EIO; + goto _free_res; + } + } + + if (rk_saradc->rstc) + { + rockchip_saradc_reset_controller(rk_saradc); + } + + rk_saradc->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!rk_saradc->pclk) + { + err = -RT_EIO; + goto _free_res; + } + + if ((err = rt_clk_enable(rk_saradc->pclk))) + { + goto _free_res; + } + + rk_saradc->clk = rt_clk_get_by_name(dev, "saradc"); + + if (!rk_saradc->clk) + { + err = -RT_EIO; + goto _free_res; + } + + if ((err = rt_clk_set_rate(rk_saradc->clk, soc_data->clk_rate))) + { + goto _free_res; + } + + if ((err = rt_clk_enable(rk_saradc->clk))) + { + goto _free_res; + } + + if ((err = rt_regulator_enable(rk_saradc->vref))) + { + goto _free_res; + } + + rt_dm_dev_set_name_auto(&rk_saradc->parent.parent, "saradc"); + dev_name = rt_dm_dev_get_name(&rk_saradc->parent.parent); + + rt_mutex_init(&rk_saradc->lock, dev_name, RT_IPC_FLAG_PRIO); + rt_completion_init(&rk_saradc->completion); + + rt_hw_adc_register(&rk_saradc->parent, dev_name, &rockchip_saradc_ops, rk_saradc); + rt_hw_interrupt_install(rk_saradc->irq, rockchip_saradc_isr, rk_saradc, dev_name); + rt_hw_interrupt_umask(rk_saradc->irq); + + return RT_EOK; + +_free_res: + rockchip_saradc_free(rk_saradc); + + return err; +} + +static const struct rt_ofw_node_id rockchip_saradc_ofw_ids[] = +{ + { .compatible = "rockchip,saradc", .data = &saradc_data }, + { .compatible = "rockchip,rk3066-tsadc", .data = &rk3066_tsadc_data }, + { .compatible = "rockchip,rk3399-saradc", .data = &rk3399_saradc_data }, + { .compatible = "rockchip,rk3568-saradc", .data = &rk3568_saradc_data }, + { .compatible = "rockchip,rk3588-saradc", .data = &rk3588_saradc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_saradc_driver = +{ + .name = "rockchip-saradc", + .ids = rockchip_saradc_ofw_ids, + + .probe = rockchip_saradc_probe, +}; + +static int rockchip_saradc_drv_register(void) +{ + rt_platform_driver_register(&rockchip_saradc_driver); + + return 0; +} +INIT_DRIVER_LATE_EXPORT(rockchip_saradc_drv_register); diff --git a/components/drivers/misc/adc.c b/components/drivers/adc/adc.c similarity index 98% rename from components/drivers/misc/adc.c rename to components/drivers/adc/adc.c index 0f71e096f248..1216a1de1718 100644 --- a/components/drivers/misc/adc.c +++ b/components/drivers/adc/adc.c @@ -47,11 +47,11 @@ static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args) if (cmd == RT_ADC_CMD_ENABLE && adc->ops->enabled) { - result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE); + result = adc->ops->enabled(adc, (rt_uint8_t)(rt_ubase_t)args, RT_TRUE); } else if (cmd == RT_ADC_CMD_DISABLE && adc->ops->enabled) { - result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE); + result = adc->ops->enabled(adc, (rt_uint8_t)(rt_ubase_t)args, RT_FALSE); } else if (cmd == RT_ADC_CMD_GET_RESOLUTION && adc->ops->get_resolution && args) { diff --git a/components/drivers/audio/Kconfig b/components/drivers/audio/Kconfig new file mode 100644 index 000000000000..ec95d4f7e17a --- /dev/null +++ b/components/drivers/audio/Kconfig @@ -0,0 +1,29 @@ +menuconfig RT_USING_AUDIO + select RT_USING_MEMPOOL + bool "Using Audio device drivers" + default n + + if RT_USING_AUDIO + config RT_AUDIO_REPLAY_MP_BLOCK_SIZE + int "Replay memory pool block size" + default 4096 + + config RT_AUDIO_REPLAY_MP_BLOCK_COUNT + int "Replay memory pool block count" + default 2 + + config RT_AUDIO_RECORD_PIPE_SIZE + int "Record pipe size" + default 2048 + endif + +config RT_AUDIO_INTEL_HDA + bool "Enable Intel High Definition Audio" + depends on RT_USING_DM + depends on RT_USING_AUDIO + select RT_USING_PCI + default n + +if RT_USING_DM && RT_USING_AUDIO +source "$RTT_DIR/components/drivers/audio/rockchip/Kconfig" +endif diff --git a/components/drivers/audio/SConscript b/components/drivers/audio/SConscript index 1ea671d5555a..69e0ce516b3b 100644 --- a/components/drivers/audio/SConscript +++ b/components/drivers/audio/SConscript @@ -1,9 +1,23 @@ from building import * -cwd = GetCurrentDir() -src = Glob('*.c') +group = [] +objs = [] + +if not GetDepend('RT_USING_AUDIO'): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) CPPPATH = [cwd] -group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH) +src = ['audio.c', 'audio_pipe.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group -Return('group') +Return('objs') diff --git a/components/drivers/audio/intel-hda/SConscript b/components/drivers/audio/intel-hda/SConscript new file mode 100644 index 000000000000..b8dddc11a092 --- /dev/null +++ b/components/drivers/audio/intel-hda/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_AUDIO_INTEL_HDA']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = Glob('*.c') + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/audio/intel-hda/hda-defs.h b/components/drivers/audio/intel-hda/hda-defs.h new file mode 100644 index 000000000000..3c349b0ad124 --- /dev/null +++ b/components/drivers/audio/intel-hda/hda-defs.h @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#ifndef __INTEL_HDA_DEFS_H__ +#define __INTEL_HDA_DEFS_H__ + +/* + * registers + */ +#define ICH6_REG_GCAP 0x00 /* Global Capabilities */ +#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ +#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ +#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ +#define ICH6_REG_VMIN 0x02 /* Minor Version */ +#define ICH6_REG_VMAJ 0x03 /* Major Version */ +#define ICH6_REG_OUTPAY 0x04 /* Output Payload Capability */ +#define ICH6_REG_INPAY 0x06 /* Input Payload Capability */ +#define ICH6_REG_GCTL 0x08 /* Global Control */ +#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ +#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ +#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define ICH6_REG_WAKEEN 0x0c /* Wake Enable */ +#define ICH6_REG_STATESTS 0x0e /* State Change Status */ +#define ICH6_REG_GSTS 0x10 /* Global Status */ +#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ +#define ICH6_REG_OUTSTRMPAY 0x18 /* Output Stream Payload Capability */ +#define ICH6_REG_INSTRMPAY 0x1a /* Input Stream Payload Capability */ +#define ICH6_REG_INTCTL 0x20 /* Interrupt Control */ +#define ICH6_REG_INTSTS 0x24 /* Interrupt Status */ +#define ICH6_REG_WALLCLK 0x30 /* Wall Clock Counter: 24Mhz source */ +#define ICH6_REG_SYNC 0x34 +#define ICH6_REG_SSYNC 0x38 /* Stream Synchronization */ +#define ICH6_REG_CORBLBASE 0x40 /* CORB Lower Base Address */ +#define ICH6_REG_CORBUBASE 0x44 /* CORB Upper Base Address */ +#define ICH6_REG_CORBWP 0x48 /* CORB Write Pointer */ +#define ICH6_REG_CORBRP 0x4a /* CORB Read Pointer */ +#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ +#define ICH6_REG_CORBCTL 0x4c /* CORB Control */ +#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define ICH6_REG_CORBSTS 0x4d /* CORB Status */ +#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define ICH6_REG_CORBSIZE 0x4e /* CORB Size */ + +#define ICH6_REG_RIRBLBASE 0x50 /* RIRB Lower Base Address */ +#define ICH6_REG_RIRBUBASE 0x54 /* RIRB Upper Base Address */ +#define ICH6_REG_RIRBWP 0x58 /* RIRB Write Pointer */ +#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define ICH6_REG_RINTCNT 0x5a /* Response Interrupt Count */ +#define ICH6_REG_RIRBCTL 0x5c /* RIRB Control */ +#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define ICH6_REG_RIRBSTS 0x5d /* RIRB Status */ +#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ +#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define ICH6_REG_RIRBSIZE 0x5e /* RIRB Size */ + +#define ICH6_REG_IC 0x60 /* Immediate Command Output Interface */ +#define ICH6_REG_IR 0x64 /* Immediate Response Input Interface */ +#define ICH6_REG_IRS 0x68 /* Immediate Command Status */ +#define ICH6_IRS_VALID (1 << 1) +#define ICH6_IRS_BUSY (1 << 0) + +#define ICH6_REG_DPLBASE 0x70 /* DMA Position Lower Base Address */ +#define ICH6_REG_DPUBASE 0x74 /* DMA Position Upper Base Address */ +#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ + +#define ICH6_SDI0_OFF 0x080 +#define ICH6_SDI1_OFF 0x0a0 +#define ICH6_SDI2_OFF 0x0c0 +#define ICH6_SDI3_OFF 0x0e0 +#define ICH6_SDO0_OFF 0x100 +#define ICH6_REG_SDO0_CTLL (ICH6_SDO0_OFF + 0x00) +#define ICH6_REG_SDO0_CTLU (ICH6_SDO0_OFF + 0x02) +#define ICH6_REG_SDO0_STS (ICH6_SDO0_OFF + 0x03) +#define SDO0_STS_BCIS (1 << 2) +#define SDO0_STS_FIFOE (1 << 3) +#define SDO0_STS_DESE (1 << 4) +#define SDO0_STS_FIFORDY (1 << 5) +#define ICH6_REG_SDO0_CBL (ICH6_SDO0_OFF + 0x08) +#define ICH6_REG_SDO0_STLVI (ICH6_SDO0_OFF + 0x0c) +#define ICH6_REG_SDO0_FMT (ICH6_SDO0_OFF + 0x12) +#define ICH6_REG_SDO0_BDLPL (ICH6_SDO0_OFF + 0x18) +#define ICH6_REG_SDO0_BDLPU (ICH6_SDO0_OFF + 0x1c) +#define ICH6_SDO1_OFF 0x120 +#define ICH6_SDO2_OFF 0x140 +#define ICH6_SDO3_OFF 0x160 + +/* stream register offsets from stream base */ +#define ICH6_REG_SD_CTL 0x00 +#define ICH6_REG_SD_STS 0x03 +#define ICH6_REG_SD_LPIB 0x04 +#define ICH6_REG_SD_CBL 0x08 +#define ICH6_REG_SD_LVI 0x0c +#define ICH6_REG_SD_FIFOW 0x0e +#define ICH6_REG_SD_FIFOSIZE 0x10 +#define ICH6_REG_SD_FORMAT 0x12 +#define ICH6_REG_SD_BDLPL 0x18 +#define ICH6_REG_SD_BDLPU 0x1c + +/* PCI space */ +#define ICH6_PCIREG_TCSEL 0x44 + +/* + * other constants + */ + +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI has 1 playback and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 1 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + +/* this number is statically defined for simplicity */ +#define MAX_AZX_DEV 16 + +/* max number of fragments - we may use more if allocating more pages for BDL */ +#define BDL_SIZE 4096 +#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) +#define AZX_MAX_FRAG 32 +/* max buffer size - no h/w limit, you can increase as you like */ +#define AZX_MAX_BUF_SIZE (1024 * 1024 * 1024) + +/* RIRB int mask: overrun[2], response[0] */ +#define RIRB_INT_RESPONSE 0x01 +#define RIRB_INT_OVERRUN 0x04 +#define RIRB_INT_MASK 0x05 + +/* STATESTS int mask: S3,SD2,SD1,SD0 */ +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 +#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) + +/* SD_CTL bits */ +#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ +#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ +#define SD_CTL_STRIPE (3 << 16) /* stripe control */ +#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ +#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ +#define SD_CTL_STREAM_TAG_MASK (0xf << 20) +#define SD_CTL_STREAM_TAG_SHIFT 20 + +/* SD_CTL and SD_STS */ +#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ +#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SD_INT_COMPLETE 0x04 /* completion interrupt */ +#define SD_INT_MASK (SD_INT_DESC_ERR | SD_INT_FIFO_ERR | SD_INT_COMPLETE) + +/* SD_STS */ +#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ + +/* INTCTL and INTSTS */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ + +/* below are so far hardcoded - should read registers in future */ +#define ICH6_MAX_CORB_ENTRIES 256 +#define ICH6_MAX_RIRB_ENTRIES 256 + +/* position fix mode */ +enum +{ + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, +}; + +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1 << 11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + +/* + * nodes + */ +#define AC_NODE_ROOT 0x00 + +/* + * function group types + */ +enum +{ + AC_GRP_AUDIO_FUNCTION = 0x01, + AC_GRP_MODEM_FUNCTION = 0x02, +}; + +/* + * widget types + */ +enum +{ + AC_WID_AUD_OUT, /* Audio Out */ + AC_WID_AUD_IN, /* Audio In */ + AC_WID_AUD_MIX, /* Audio Mixer */ + AC_WID_AUD_SEL, /* Audio Selector */ + AC_WID_PIN, /* Pin Complex */ + AC_WID_POWER, /* Power */ + AC_WID_VOL_KNB, /* Volume Knob */ + AC_WID_BEEP, /* Beep Generator */ + AC_WID_VENDOR = 0x0f /* Vendor specific */ +}; + +/* + * GET verbs + */ +#define AC_VERB_GET_STREAM_FORMAT 0x0a00 +#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 +#define AC_VERB_GET_PROC_COEF 0x0c00 +#define AC_VERB_GET_COEF_INDEX 0x0d00 +#define AC_VERB_PARAMETERS 0x0f00 +#define AC_VERB_GET_CONNECT_SEL 0x0f01 +#define AC_VERB_GET_CONNECT_LIST 0x0f02 +#define AC_VERB_GET_PROC_STATE 0x0f03 +#define AC_VERB_GET_SDI_SELECT 0x0f04 +#define AC_VERB_GET_POWER_STATE 0x0f05 +#define AC_VERB_GET_CONV 0x0f06 +#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 +#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 +#define AC_VERB_GET_PIN_SENSE 0x0f09 +#define AC_VERB_GET_BEEP_CONTROL 0x0f0a +#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c +#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d +#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ +#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f +/* f10-f1a: GPIO */ +#define AC_VERB_GET_GPIO_DATA 0x0f15 +#define AC_VERB_GET_GPIO_MASK 0x0f16 +#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 +#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 +#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 +#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a +#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c +/* f20: AFG/MFG */ +#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 +#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d +#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e +#define AC_VERB_GET_HDMI_ELDD 0x0f2f +#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 +#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 +#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 +#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 +#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 + +/* + * SET verbs + */ +#define AC_VERB_SET_STREAM_FORMAT 0x200 +#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 +#define AC_VERB_SET_PROC_COEF 0x400 +#define AC_VERB_SET_COEF_INDEX 0x500 +#define AC_VERB_SET_CONNECT_SEL 0x701 +#define AC_VERB_SET_PROC_STATE 0x703 +#define AC_VERB_SET_SDI_SELECT 0x704 +#define AC_VERB_SET_POWER_STATE 0x705 +#define AC_VERB_SET_CHANNEL_STREAMID 0x706 +#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 +#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 +#define AC_VERB_SET_PIN_SENSE 0x709 +#define AC_VERB_SET_BEEP_CONTROL 0x70a +#define AC_VERB_SET_EAPD_BTLENABLE 0x70c +#define AC_VERB_SET_DIGI_CONVERT_1 0x70d +#define AC_VERB_SET_DIGI_CONVERT_2 0x70e +#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f +#define AC_VERB_SET_GPIO_DATA 0x715 +#define AC_VERB_SET_GPIO_MASK 0x716 +#define AC_VERB_SET_GPIO_DIRECTION 0x717 +#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 +#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 +#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f +#define AC_VERB_SET_EAPD 0x788 +#define AC_VERB_SET_CODEC_RESET 0x7ff +#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d +#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 +#define AC_VERB_SET_HDMI_DIP_DATA 0x731 +#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 +#define AC_VERB_SET_HDMI_CP_CTRL 0x733 +#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 + +/* + * Parameter IDs + */ +#define AC_PAR_VENDOR_ID 0x00 +#define AC_PAR_SUBSYSTEM_ID 0x01 +#define AC_PAR_REV_ID 0x02 +#define AC_PAR_NODE_COUNT 0x04 +#define AC_PAR_FUNCTION_TYPE 0x05 +#define AC_PAR_AUDIO_FG_CAP 0x08 +#define AC_PAR_AUDIO_WIDGET_CAP 0x09 +#define AC_PAR_PCM 0x0a +#define AC_PAR_STREAM 0x0b +#define AC_PAR_PIN_CAP 0x0c +#define AC_PAR_AMP_IN_CAP 0x0d +#define AC_PAR_CONNLIST_LEN 0x0e +#define AC_PAR_POWER_STATE 0x0f +#define AC_PAR_PROC_CAP 0x10 +#define AC_PAR_GPIO_CAP 0x11 +#define AC_PAR_AMP_OUT_CAP 0x12 +#define AC_PAR_VOL_KNB_CAP 0x13 +#define AC_PAR_HDMI_LPCM_CAP 0x20 + +/* + * AC_VERB_PARAMETERS results (32bit) + */ + +/* Function Group Type */ +#define AC_FGT_TYPE (0xff << 0) +#define AC_FGT_TYPE_SHIFT 0 +#define AC_FGT_UNSOL_CAP (1 << 8) + +/* Audio Function Group Capabilities */ +#define AC_AFG_OUT_DELAY (0xf << 0) +#define AC_AFG_IN_DELAY (0xf << 8) +#define AC_AFG_BEEP_GEN (1 << 16) + +/* Audio Widget Capabilities */ +#define AC_WCAP_STEREO (1 << 0) /* stereo I/O */ +#define AC_WCAP_IN_AMP (1 << 1) /* AMP-in present */ +#define AC_WCAP_OUT_AMP (1 << 2) /* AMP-out present */ +#define AC_WCAP_AMP_OVRD (1 << 3) /* AMP-parameter override */ +#define AC_WCAP_FORMAT_OVRD (1 << 4) /* format override */ +#define AC_WCAP_STRIPE (1 << 5) /* stripe */ +#define AC_WCAP_PROC_WID (1 << 6) /* Proc Widget */ +#define AC_WCAP_UNSOL_CAP (1 << 7) /* Unsol capable */ +#define AC_WCAP_CONN_LIST (1 << 8) /* connection list */ +#define AC_WCAP_DIGITAL (1 << 9) /* digital I/O */ +#define AC_WCAP_POWER (1 << 10) /* power control */ +#define AC_WCAP_LR_SWAP (1 << 11) /* L/R swap */ +#define AC_WCAP_CP_CAPS (1 << 12) /* content protection */ +#define AC_WCAP_CHAN_CNT_EXT (7 << 13) /* channel count ext */ +#define AC_WCAP_DELAY (0xf << 16) +#define AC_WCAP_DELAY_SHIFT 16 +#define AC_WCAP_TYPE (0xf << 20) +#define AC_WCAP_TYPE_SHIFT 20 + +/* supported PCM rates and bits */ +#define AC_SUPPCM_RATES (0xfff << 0) +#define AC_SUPPCM_BITS_8 (1 << 16) +#define AC_SUPPCM_BITS_16 (1 << 17) +#define AC_SUPPCM_BITS_20 (1 << 18) +#define AC_SUPPCM_BITS_24 (1 << 19) +#define AC_SUPPCM_BITS_32 (1 << 20) + +/* supported PCM stream format */ +#define AC_SUPFMT_PCM (1 << 0) +#define AC_SUPFMT_FLOAT32 (1 << 1) +#define AC_SUPFMT_AC3 (1 << 2) + +/* GP I/O count */ +#define AC_GPIO_IO_COUNT (0xff << 0) +#define AC_GPIO_O_COUNT (0xff << 8) +#define AC_GPIO_O_COUNT_SHIFT 8 +#define AC_GPIO_I_COUNT (0xff << 16) +#define AC_GPIO_I_COUNT_SHIFT 16 +#define AC_GPIO_UNSOLICITED (1 << 30) +#define AC_GPIO_WAKE (1 << 31) + +/* Converter stream, channel */ +#define AC_CONV_CHANNEL (0xf << 0) +#define AC_CONV_STREAM (0xf << 4) +#define AC_CONV_STREAM_SHIFT 4 + +/* Input converter SDI select */ +#define AC_SDI_SELECT (0xf << 0) + +/* stream format id */ +#define AC_FMT_CHAN_SHIFT 0 +#define AC_FMT_CHAN_MASK (0x0f << 0) +#define AC_FMT_BITS_SHIFT 4 +#define AC_FMT_BITS_MASK (7 << 4) +#define AC_FMT_BITS_8 (0 << 4) +#define AC_FMT_BITS_16 (1 << 4) +#define AC_FMT_BITS_20 (2 << 4) +#define AC_FMT_BITS_24 (3 << 4) +#define AC_FMT_BITS_32 (4 << 4) +#define AC_FMT_DIV_SHIFT 8 +#define AC_FMT_DIV_MASK (7 << 8) +#define AC_FMT_MULT_SHIFT 11 +#define AC_FMT_MULT_MASK (7 << 11) +#define AC_FMT_BASE_SHIFT 14 +#define AC_FMT_BASE_48K (0 << 14) +#define AC_FMT_BASE_44K (1 << 14) +#define AC_FMT_TYPE_SHIFT 15 +#define AC_FMT_TYPE_PCM (0 << 15) +#define AC_FMT_TYPE_NON_PCM (1 << 15) + +/* Unsolicited response control */ +#define AC_UNSOL_TAG (0x3f << 0) +#define AC_UNSOL_ENABLED (1 << 7) +#define AC_USRSP_EN AC_UNSOL_ENABLED + +/* Unsolicited responses */ +#define AC_UNSOL_RES_TAG (0x3f << 26) +#define AC_UNSOL_RES_TAG_SHIFT 26 +#define AC_UNSOL_RES_SUBTAG (0x1f << 21) +#define AC_UNSOL_RES_SUBTAG_SHIFT 21 +#define AC_UNSOL_RES_ELDV (1 << 1) /* ELD Data valid (for HDMI) */ +#define AC_UNSOL_RES_PD (1 << 0) /* pinsense detect */ +#define AC_UNSOL_RES_CP_STATE (1 << 1) /* content protection */ +#define AC_UNSOL_RES_CP_READY (1 << 0) /* content protection */ + +/* Pin widget capabilies */ +#define AC_PINCAP_IMP_SENSE (1 << 0) /* impedance sense capable */ +#define AC_PINCAP_TRIG_REQ (1 << 1) /* trigger required */ +#define AC_PINCAP_PRES_DETECT (1 << 2) /* presence detect capable */ +#define AC_PINCAP_HP_DRV (1 << 3) /* headphone drive capable */ +#define AC_PINCAP_OUT (1 << 4) /* output capable */ +#define AC_PINCAP_IN (1 << 5) /* input capable */ +#define AC_PINCAP_BALANCE (1 << 6) /* balanced I/O capable */ +/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, + * but is marked reserved in the Intel HDA specification. + */ +#define AC_PINCAP_LR_SWAP (1 << 7) /* L/R swap */ +/* Note: The same bit as LR_SWAP is newly defined as HDMI capability + * in HD-audio specification + */ +#define AC_PINCAP_HDMI (1 << 7) /* HDMI pin */ +#define AC_PINCAP_DP (1 << 24) /* DisplayPort pin, can coexist with AC_PINCAP_HDMI */ +#define AC_PINCAP_VREF (0x37 << 8) +#define AC_PINCAP_VREF_SHIFT 8 +#define AC_PINCAP_EAPD (1 << 16) /* EAPD capable */ +#define AC_PINCAP_HBR (1 << 27) /* High Bit Rate */ +/* Vref status (used in pin cap) */ +#define AC_PINCAP_VREF_HIZ (1 << 0) /* Hi-Z */ +#define AC_PINCAP_VREF_50 (1 << 1) /* 50% */ +#define AC_PINCAP_VREF_GRD (1 << 2) /* ground */ +#define AC_PINCAP_VREF_80 (1 << 4) /* 80% */ +#define AC_PINCAP_VREF_100 (1 << 5) /* 100% */ + +/* Amplifier capabilities */ +#define AC_AMPCAP_OFFSET (0x7f << 0) /* 0dB offset */ +#define AC_AMPCAP_OFFSET_SHIFT 0 +#define AC_AMPCAP_NUM_STEPS (0x7f << 8) /* number of steps */ +#define AC_AMPCAP_NUM_STEPS_SHIFT 8 +#define AC_AMPCAP_STEP_SIZE (0x7f << 16) /* step size 0-32dB in 0.25dB */ +#define AC_AMPCAP_STEP_SIZE_SHIFT 16 +#define AC_AMPCAP_MUTE (1 << 31) /* mute capable */ +#define AC_AMPCAP_MUTE_SHIFT 31 + +/* Connection list */ +#define AC_CLIST_LENGTH (0x7f << 0) +#define AC_CLIST_LONG (1 << 7) + +/* Supported power status */ +#define AC_PWRST_D0SUP (1 << 0) +#define AC_PWRST_D1SUP (1 << 1) +#define AC_PWRST_D2SUP (1 << 2) +#define AC_PWRST_D3SUP (1 << 3) +#define AC_PWRST_D3COLDSUP (1 << 4) +#define AC_PWRST_S3D3COLDSUP (1 << 29) +#define AC_PWRST_CLKSTOP (1 << 30) +#define AC_PWRST_EPSS (1U << 31) + +/* Power state values */ +#define AC_PWRST_SETTING (0xf << 0) +#define AC_PWRST_ACTUAL (0xf << 4) +#define AC_PWRST_ACTUAL_SHIFT 4 +#define AC_PWRST_D0 0x00 +#define AC_PWRST_D1 0x01 +#define AC_PWRST_D2 0x02 +#define AC_PWRST_D3 0x03 + +/* Processing capabilies */ +#define AC_PCAP_BENIGN (1 << 0) +#define AC_PCAP_NUM_COEF (0xff << 8) +#define AC_PCAP_NUM_COEF_SHIFT 8 + +/* Volume knobs capabilities */ +#define AC_KNBCAP_NUM_STEPS (0x7f << 0) +#define AC_KNBCAP_DELTA (1 << 7) + +/* HDMI LPCM capabilities */ +#define AC_LPCMCAP_48K_CP_CHNS (0x0f << 0) /* max channels w/ CP-on */ +#define AC_LPCMCAP_48K_NO_CHNS (0x0f << 4) /* max channels w/o CP-on */ +#define AC_LPCMCAP_48K_20BIT (1 << 8) /* 20b bitrate supported */ +#define AC_LPCMCAP_48K_24BIT (1 << 9) /* 24b bitrate supported */ +#define AC_LPCMCAP_96K_CP_CHNS (0x0f << 10) /* max channels w/ CP-on */ +#define AC_LPCMCAP_96K_NO_CHNS (0x0f << 14) /* max channels w/o CP-on */ +#define AC_LPCMCAP_96K_20BIT (1 << 18) /* 20b bitrate supported */ +#define AC_LPCMCAP_96K_24BIT (1 << 19) /* 24b bitrate supported */ +#define AC_LPCMCAP_192K_CP_CHNS (0x0f << 20) /* max channels w/ CP-on */ +#define AC_LPCMCAP_192K_NO_CHNS (0x0f << 24) /* max channels w/o CP-on */ +#define AC_LPCMCAP_192K_20BIT (1 << 28) /* 20b bitrate supported */ +#define AC_LPCMCAP_192K_24BIT (1 << 29) /* 24b bitrate supported */ +#define AC_LPCMCAP_44K (1 << 30) /* 44.1kHz support */ +#define AC_LPCMCAP_44K_MS (1 << 31) /* 44.1kHz-multiplies support */ + +/* + * Control Parameters + */ + +/* Amp gain/mute */ +#define AC_AMP_MUTE (1 << 7) +#define AC_AMP_GAIN (0x7f) +#define AC_AMP_GET_INDEX (0xf << 0) + +#define AC_AMP_GET_LEFT (1 << 13) +#define AC_AMP_GET_RIGHT (0 << 13) +#define AC_AMP_GET_OUTPUT (1 << 15) +#define AC_AMP_GET_INPUT (0 << 15) + +#define AC_AMP_SET_INDEX (0xf << 8) +#define AC_AMP_SET_INDEX_SHIFT 8 +#define AC_AMP_SET_RIGHT (1 << 12) +#define AC_AMP_SET_LEFT (1 << 13) +#define AC_AMP_SET_INPUT (1 << 14) +#define AC_AMP_SET_OUTPUT (1 << 15) + +/* DIGITAL1 bits */ +#define AC_DIG1_ENABLE (1 << 0) +#define AC_DIG1_V (1 << 1) +#define AC_DIG1_VCFG (1 << 2) +#define AC_DIG1_EMPHASIS (1 << 3) +#define AC_DIG1_COPYRIGHT (1 << 4) +#define AC_DIG1_NONAUDIO (1 << 5) +#define AC_DIG1_PROFESSIONAL (1 << 6) +#define AC_DIG1_LEVEL (1 << 7) + +/* DIGITAL2 bits */ +#define AC_DIG2_CC (0x7f << 0) + +/* Pin widget control - 8bit */ +#define AC_PINCTL_EPT (0x3 << 0) +#define AC_PINCTL_EPT_NATIVE 0 +#define AC_PINCTL_EPT_HBR 3 +#define AC_PINCTL_VREFEN (0x7 << 0) +#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ +#define AC_PINCTL_VREF_50 1 /* 50% */ +#define AC_PINCTL_VREF_GRD 2 /* ground */ +#define AC_PINCTL_VREF_80 4 /* 80% */ +#define AC_PINCTL_VREF_100 5 /* 100% */ +#define AC_PINCTL_IN_EN (1 << 5) +#define AC_PINCTL_OUT_EN (1 << 6) +#define AC_PINCTL_HP_EN (1 << 7) + +/* Pin sense - 32bit */ +#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) +#define AC_PINSENSE_PRESENCE (1 << 31) +#define AC_PINSENSE_ELDV (1 << 30) /* ELD valid (HDMI) */ + +/* EAPD/BTL enable - 32bit */ +#define AC_EAPDBTL_BALANCED (1 << 0) +#define AC_EAPDBTL_EAPD (1 << 1) +#define AC_EAPDBTL_LR_SWAP (1 << 2) + +/* HDMI ELD data */ +#define AC_ELDD_ELD_VALID (1 << 31) +#define AC_ELDD_ELD_DATA 0xff + +/* HDMI DIP size */ +#define AC_DIPSIZE_ELD_BUF (1 << 3) /* ELD buf size of packet size */ +#define AC_DIPSIZE_PACK_IDX (0x07 << 0) /* packet index */ + +/* HDMI DIP index */ +#define AC_DIPIDX_PACK_IDX (0x07 << 5) /* packet idnex */ +#define AC_DIPIDX_BYTE_IDX (0x1f << 0) /* byte index */ + +/* HDMI DIP xmit (transmit) control */ +#define AC_DIPXMIT_MASK (0x3 << 6) +#define AC_DIPXMIT_DISABLE (0x0 << 6) /* disable xmit */ +#define AC_DIPXMIT_ONCE (0x2 << 6) /* xmit once then disable */ +#define AC_DIPXMIT_BEST (0x3 << 6) /* best effort */ + +/* HDMI content protection (CP) control */ +#define AC_CPCTRL_CES (1 << 9) /* current encryption state */ +#define AC_CPCTRL_READY (1 << 8) /* ready bit */ +#define AC_CPCTRL_SUBTAG (0x1f << 3) /* subtag for unsol-resp */ +#define AC_CPCTRL_STATE (3 << 0) /* current CP request state */ + +/* Converter channel <-> HDMI slot mapping */ +#define AC_CVTMAP_HDMI_SLOT (0xf << 0) /* HDMI slot number */ +#define AC_CVTMAP_CHAN (0xf << 4) /* converter channel number */ + +/* configuration default - 32bit */ +#define AC_DEFCFG_SEQUENCE (0xf << 0) +#define AC_DEFCFG_DEF_ASSOC (0xf << 4) +#define AC_DEFCFG_ASSOC_SHIFT 4 +#define AC_DEFCFG_MISC (0xf << 8) +#define AC_DEFCFG_MISC_SHIFT 8 +#define AC_DEFCFG_MISC_NO_PRESENCE (1 << 0) +#define AC_DEFCFG_COLOR (0xf << 12) +#define AC_DEFCFG_COLOR_SHIFT 12 +#define AC_DEFCFG_CONN_TYPE (0xf << 16) +#define AC_DEFCFG_CONN_TYPE_SHIFT 16 +#define AC_DEFCFG_DEVICE (0xf << 20) +#define AC_DEFCFG_DEVICE_SHIFT 20 +#define AC_DEFCFG_LOCATION (0x3f << 24) +#define AC_DEFCFG_LOCATION_SHIFT 24 +#define AC_DEFCFG_PORT_CONN (0x3 << 30) +#define AC_DEFCFG_PORT_CONN_SHIFT 30 + +/* device device types (0x0-0xf) */ +enum +{ + AC_JACK_LINE_OUT, + AC_JACK_SPEAKER, + AC_JACK_HP_OUT, + AC_JACK_CD, + AC_JACK_SPDIF_OUT, + AC_JACK_DIG_OTHER_OUT, + AC_JACK_MODEM_LINE_SIDE, + AC_JACK_MODEM_HAND_SIDE, + AC_JACK_LINE_IN, + AC_JACK_AUX, + AC_JACK_MIC_IN, + AC_JACK_TELEPHONY, + AC_JACK_SPDIF_IN, + AC_JACK_DIG_OTHER_IN, + AC_JACK_OTHER = 0xf, +}; + +/* jack connection types (0x0-0xf) */ +enum +{ + AC_JACK_CONN_UNKNOWN, + AC_JACK_CONN_1_8, + AC_JACK_CONN_1_4, + AC_JACK_CONN_ATAPI, + AC_JACK_CONN_RCA, + AC_JACK_CONN_OPTICAL, + AC_JACK_CONN_OTHER_DIGITAL, + AC_JACK_CONN_OTHER_ANALOG, + AC_JACK_CONN_DIN, + AC_JACK_CONN_XLR, + AC_JACK_CONN_RJ11, + AC_JACK_CONN_COMB, + AC_JACK_CONN_OTHER = 0xf, +}; + +/* jack colors (0x0-0xf) */ +enum +{ + AC_JACK_COLOR_UNKNOWN, + AC_JACK_COLOR_BLACK, + AC_JACK_COLOR_GREY, + AC_JACK_COLOR_BLUE, + AC_JACK_COLOR_GREEN, + AC_JACK_COLOR_RED, + AC_JACK_COLOR_ORANGE, + AC_JACK_COLOR_YELLOW, + AC_JACK_COLOR_PURPLE, + AC_JACK_COLOR_PINK, + AC_JACK_COLOR_WHITE = 0xe, + AC_JACK_COLOR_OTHER, +}; + +/* Jack location (0x0-0x3f) */ +/* common case */ +enum +{ + AC_JACK_LOC_NONE, + AC_JACK_LOC_REAR, + AC_JACK_LOC_FRONT, + AC_JACK_LOC_LEFT, + AC_JACK_LOC_RIGHT, + AC_JACK_LOC_TOP, + AC_JACK_LOC_BOTTOM, +}; +/* bits 4-5 */ +enum +{ + AC_JACK_LOC_EXTERNAL = 0x00, + AC_JACK_LOC_INTERNAL = 0x10, + AC_JACK_LOC_SEPARATE = 0x20, + AC_JACK_LOC_OTHER = 0x30, +}; + +enum +{ + /* external on primary chasis */ + AC_JACK_LOC_REAR_PANEL = 0x07, + AC_JACK_LOC_DRIVE_BAY, + /* internal */ + AC_JACK_LOC_RISER = 0x17, + AC_JACK_LOC_HDMI, + AC_JACK_LOC_ATAPI, + /* others */ + AC_JACK_LOC_MOBILE_IN = 0x37, + AC_JACK_LOC_MOBILE_OUT, +}; + +/* Port connectivity (0-3) */ +enum +{ + AC_JACK_PORT_COMPLEX, + AC_JACK_PORT_NONE, + AC_JACK_PORT_FIXED, + AC_JACK_PORT_BOTH, +}; + +/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32 + +/* max. codec address */ +#define HDA_MAX_CODEC_ADDRESS 0x0f + +/* max number of PCM devics per card */ +#define HDA_MAX_PCMS 10 + +#endif /* __INTEL_HDA_DEFS_H__ */ diff --git a/components/drivers/audio/intel-hda/hda.c b/components/drivers/audio/intel-hda/hda.c new file mode 100644 index 000000000000..4df1b19d1b78 --- /dev/null +++ b/components/drivers/audio/intel-hda/hda.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-10-24 GuEe-GUI first version + */ + +#include +#include + +#include + +#define DBG_TAG "audio.hda" +#define DBG_LVL DBG_INFO +#include + +#include "hda-defs.h" + +#define ICH6_REG_BAR 0 + +#define CORB_ALIGNED 128 + +struct hda_bdl_entry +{ + rt_uint32_t paddr; + rt_uint32_t length; + rt_uint32_t flags; +} __attribute__((packed)); + +struct hda_output +{ + rt_uint8_t codec; + rt_uint16_t node_id; + + rt_uint32_t sample_rate; + int amp_gain_steps; + int num_channels; +}; + +struct intel_hda +{ + struct rt_audio_device parent; + + void *ich6_reg_base; + struct rt_pci_device *pdev; + + int stream; + + struct hda_output output; + + void *ring_buffer; + rt_uint32_t *corb; /* command outbound ring buffer */ + rt_uint64_t *rirb; /* response inbound ring buffer */ + struct hda_bdl_entry *bdl; /* buffer descriptor list */ + rt_uint64_t *dma_pos; /* dma position in current buffer */ + + rt_size_t corb_entries; /* number of CORB entries */ + rt_size_t rirb_entries; /* number of RIRB entries */ + rt_uint16_t rirb_read_pointer; /* RIRB read pointer */ + + rt_uint32_t *buffer; + rt_uint32_t buffers_completed; +}; +#define raw_to_intel_hda(raw) rt_container_of(raw, struct intel_hda, parent) + +#define intel_hda_writel(hda, reg, val) HWREG32((hda)->ich6_reg_base + ICH6_REG_##reg) = (val) +#define intel_hda_writew(hda, reg, val) HWREG16((hda)->ich6_reg_base + ICH6_REG_##reg) = (val) +#define intel_hda_writeb(hda, reg, val) HWREG8((hda)->ich6_reg_base + ICH6_REG_##reg) = (val) + +#define intel_hda_readl(hda, reg) HWREG32((hda)->ich6_reg_base + ICH6_REG_##reg) +#define intel_hda_readw(hda, reg) HWREG16((hda)->ich6_reg_base + ICH6_REG_##reg) +#define intel_hda_readb(hda, reg) HWREG8((hda)->ich6_reg_base + ICH6_REG_##reg) + +static rt_err_t intel_hda_audio_getcaps(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + return RT_EOK; +} + +static rt_err_t intel_hda_audio_configure(struct rt_audio_device *audio, + struct rt_audio_caps *caps) +{ + return RT_EOK; +} + +static rt_err_t intel_hda_audio_init(struct rt_audio_device *audio) +{ + return RT_EOK; +} + +static rt_err_t intel_hda_audio_start(struct rt_audio_device *audio, int stream) +{ + return RT_EOK; +} + +static rt_err_t intel_hda_audio_stop(struct rt_audio_device *audio, int stream) +{ + return RT_EOK; +} + +static rt_ssize_t intel_hda_audio_transmit(struct rt_audio_device *audio, + const void *write_buf, void *read_buf, rt_size_t size) +{ + return RT_EOK; +} + +static void intel_hda_audio_buffer_info(struct rt_audio_device *audio, + struct rt_audio_buf_info *info) +{ +} + +static struct rt_audio_ops intel_hda_audio_ops = +{ + .getcaps = intel_hda_audio_getcaps, + .configure = intel_hda_audio_configure, + .init = intel_hda_audio_init, + .start = intel_hda_audio_start, + .stop = intel_hda_audio_stop, + .transmit = intel_hda_audio_transmit, + .buffer_info = intel_hda_audio_buffer_info, +}; + +static void intel_hda_isr(int irqno, void *param) +{ + rt_uint8_t sts; + rt_uint32_t isr; + struct intel_hda *hda = param; + + isr = intel_hda_readl(hda, INTSTS); + sts = intel_hda_readb(hda, SDO0_CTLL); + + if (sts & SDO0_STS_BCIS) + { + if (hda->stream == AUDIO_STREAM_REPLAY) + { + rt_audio_tx_complete(&hda->parent); + + hda->buffers_completed++; + hda->buffers_completed %= BDL_SIZE; + } + else if (hda->stream == AUDIO_STREAM_RECORD) + { + // rt_audio_rx_done(); + } + else + { + LOG_E("Unknow stream = %d", hda->stream); + } + } + + /* Reset interrupt status registers */ + intel_hda_writel(hda, INTSTS, isr); + intel_hda_writeb(hda, SDO0_CTLL, sts); +} + +static void intel_hda_reset(struct intel_hda *hda) +{ + /* Clear CORB/RIRB RUN bits before reset */ + intel_hda_writel(hda, CORBCTL, 0); + intel_hda_writel(hda, RIRBCTL, 0); + + while ((intel_hda_readl(hda, CORBCTL) & ICH6_CORBCTL_RUN) || + (intel_hda_readl(hda, RIRBCTL) & ICH6_RBCTL_DMA_EN)) + { + rt_hw_cpu_relax(); + } + + /* Reset the CRST bit and wait until hardware is in reset */ + intel_hda_writel(hda, GCTL, 0); + + while (intel_hda_readl(hda, GCTL) & ICH6_GCTL_RESET) + { + rt_hw_cpu_relax(); + } + + rt_hw_dmb(); + + /* Take the hardware out of reset */ + intel_hda_writel(hda, GCTL, ICH6_GCTL_RESET); + + while ((intel_hda_readl(hda, GCTL) & ICH6_GCTL_RESET) == 0) + { + rt_hw_cpu_relax(); + } + + /* Enable all interrupts */ + intel_hda_writew(hda, WAKEEN, 0xffff); + intel_hda_writel(hda, INTCTL, 0x800000ff); + + rt_thread_mdelay(1); +} + +static rt_err_t intel_hda_probe(struct rt_pci_device *pdev) +{ + rt_err_t err; + const char *audio_name; + char dev_name[RT_NAME_MAX]; + struct intel_hda *hda = rt_calloc(1, sizeof(*hda)); + + if (!hda) + { + return -RT_ENOMEM; + } + + hda->ich6_reg_base = rt_pci_iomap(pdev, ICH6_REG_BAR); + + if (!hda->ich6_reg_base) + { + err = -RT_EIO; + + goto _free_res; + } + + // hda->ring_buffer = rt_malloc_align(, CORB_ALIGNED); + + intel_hda_reset(hda); + + rt_dm_dev_set_name_auto(&hda->parent.parent, "audio"); + audio_name = rt_dm_dev_get_name(&hda->parent.parent); + + hda->parent.ops = &intel_hda_audio_ops; + if ((err = rt_audio_register(&hda->parent, audio_name, RT_DEVICE_FLAG_RDWR, hda))) + { + goto _free_res; + } + + rt_snprintf(dev_name, sizeof(dev_name), "%s-hda", audio_name); + rt_hw_interrupt_install(pdev->irq, intel_hda_isr, hda, dev_name); + rt_hw_interrupt_umask(pdev->irq); + rt_pci_intx(pdev, RT_TRUE); + + LOG_I("Intel HD Audio Controller v%d.%d (ich%s)", + intel_hda_readb(hda, VMAJ), intel_hda_readb(hda, VMIN), pdev->id->data); + + return RT_EOK; + +_free_res: + if (hda->ich6_reg_base) + { + rt_iounmap(hda->ich6_reg_base); + } + rt_free(hda); + + return err; +} + +static struct rt_pci_device_id intel_hda_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_INTEL, 0x2668), .data = "6" }, + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_INTEL, 0x293e), .data = "9" }, + { /* sentinel */ } +}; + +static struct rt_pci_driver intel_hda_driver = +{ + .name = "intel-hda", + + .ids = intel_hda_pci_ids, + .probe = intel_hda_probe, +}; +RT_PCI_DRIVER_EXPORT(intel_hda_driver); diff --git a/components/drivers/audio/rockchip/Kconfig b/components/drivers/audio/rockchip/Kconfig new file mode 100644 index 000000000000..d92200cbcab2 --- /dev/null +++ b/components/drivers/audio/rockchip/Kconfig @@ -0,0 +1,24 @@ +menuconfig RT_AUDIO_ROCKCHIP + bool "Enable Rockchip Audio" + select RT_USING_OFW + default n + +config RT_AUDIO_ROCKCHIP_I2S + bool "Rockchip I2S Device Driver" + depends on RT_AUDIO_ROCKCHIP + default n + +config RT_AUDIO_ROCKCHIP_I2S_TDM + bool "Rockchip I2S/TDM Device Driver" + depends on RT_AUDIO_ROCKCHIP + default n + +config RT_AUDIO_ROCKCHIP_PDM + bool "Rockchip PDM Controller Driver" + depends on RT_AUDIO_ROCKCHIP + default n + +config RT_AUDIO_ROCKCHIP_SPDIF + bool "Rockchip SPDIF Controller Driver" + depends on RT_AUDIO_ROCKCHIP + default n diff --git a/components/drivers/can/Kconfig b/components/drivers/can/Kconfig new file mode 100755 index 000000000000..20726985a9e6 --- /dev/null +++ b/components/drivers/can/Kconfig @@ -0,0 +1,20 @@ +menuconfig RT_USING_CAN + bool "Using CAN device drivers" + default n + +if RT_USING_CAN + config RT_CAN_USING_HDR + bool "Enable CAN hardware filter" + default n + config RT_CAN_USING_CANFD + bool "Enable CANFD support" + default n +endif + +config RT_CAN_CANFD_ROCKCHIP + bool "Rockchip CANFD controller" + depends on RT_USING_DM + depends on RT_USING_CAN + depends on RT_CAN_USING_CANFD + select RT_USING_RESET + default n diff --git a/components/drivers/can/SConscript b/components/drivers/can/SConscript index 84ae2a10daaa..e91ab216a42a 100644 --- a/components/drivers/can/SConscript +++ b/components/drivers/can/SConscript @@ -1,8 +1,15 @@ from building import * cwd = GetCurrentDir() -src = Glob('*.c') +src = ['can.c'] CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_USING_DM']): + src += ['can_dm.c'] + + if GetDepend(['RT_CAN_CANFD_ROCKCHIP']): + src += ['canfd-rockchip.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CAN'], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/can/can.c b/components/drivers/can/can.c index 63b738b2c525..55f57c1e4ff5 100644 --- a/components/drivers/can/can.c +++ b/components/drivers/can/can.c @@ -152,7 +152,7 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da rt_list_remove(&tx_tosnd->list); rt_hw_interrupt_enable(level); - no = ((rt_uint32_t)tx_tosnd - (rt_uint32_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list); + no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list); tx_tosnd->result = RT_CAN_SND_RESULT_WAIT; if (can->ops->sendmsg(can, data, no) != RT_EOK) { @@ -514,7 +514,7 @@ static rt_err_t rt_can_control(struct rt_device *dev, case RT_CAN_CMD_SET_PRIV: /* configure device */ - if ((rt_uint32_t)args != can->config.privmode) + if ((rt_ubase_t)args != can->config.privmode) { int i; rt_base_t level; diff --git a/components/drivers/can/can_dm.c b/components/drivers/can/can_dm.c new file mode 100644 index 000000000000..a61cf8e6aa74 --- /dev/null +++ b/components/drivers/can/can_dm.c @@ -0,0 +1,45 @@ +/* + * 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 "can_dm.h" + +static const rt_uint8_t dlc2len[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 +}; + +rt_uint8_t can_dlc2len(rt_uint8_t can_dlc) +{ + return dlc2len[can_dlc & 0x0F]; +} + +static const rt_uint8_t len2dlc[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ + 9, 9, 9, 9, /* 9 - 12 */ + 10, 10, 10, 10, /* 13 - 16 */ + 11, 11, 11, 11, /* 17 - 20 */ + 12, 12, 12, 12, /* 21 - 24 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 57 - 64 */ +}; + +rt_uint8_t can_len2dlc(rt_uint8_t len) +{ + if (len <= 64) + { + return len2dlc[len]; + } + + return 0xf; +} diff --git a/components/drivers/can/can_dm.h b/components/drivers/can/can_dm.h new file mode 100644 index 000000000000..e9b5f70de1b0 --- /dev/null +++ b/components/drivers/can/can_dm.h @@ -0,0 +1,37 @@ +/* + * 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 __CAN_DM_H__ +#define __CAN_DM_H__ + +#include +#include +#include + +/* CAN payload length and DLC definitions according to ISO 11898-1 */ +#define CAN_MAX_DLC 8 +#define CAN_MAX_RAW_DLC 15 +#define CAN_MAX_DLEN 8 + +/* CAN FD payload length and DLC definitions according to ISO 11898-7 */ +#define CANFD_MAX_DLC 15 +#define CANFD_MAX_DLEN 64 + +/* + * To be used in the CAN netdriver receive path to ensure conformance with + * ISO 11898-1 Chapter 8.4.2.3 (DLC field) + */ +#define can_get_dlc(v) (rt_min_t(rt_uint8_t, (v), CAN_MAX_DLC)) +#define canfd_get_dlc(v) (rt_min_t(rt_uint8_t, (v), CANFD_MAX_DLC)) + +rt_uint8_t can_dlc2len(rt_uint8_t can_dlc); +rt_uint8_t can_len2dlc(rt_uint8_t len); + +#endif /* __CAN_DM_H__ */ diff --git a/components/drivers/can/canfd-rockchip.c b/components/drivers/can/canfd-rockchip.c new file mode 100644 index 000000000000..e9a90398a574 --- /dev/null +++ b/components/drivers/can/canfd-rockchip.c @@ -0,0 +1,728 @@ +/* + * 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 "can_dm.h" + +#define DBG_TAG "canfd.rockchip" +#define DBG_LVL DBG_INFO +#include + +#define CAN_MODE 0x00 +#define CAN_CMD 0x04 +#define CAN_STATE 0x08 +#define CAN_INT 0x0c +#define CAN_INT_MASK 0x10 +#define CAN_LOSTARB_CODE 0x28 +#define CAN_ERR_CODE 0x2c +#define CAN_RX_ERR_CNT 0x34 +#define CAN_TX_ERR_CNT 0x38 +#define CAN_IDCODE 0x3c +#define CAN_IDMASK 0x40 +#define CAN_NBTP 0x100 +#define CAN_DBTP 0x104 +#define CAN_TDCR 0x108 +#define CAN_TSCC 0x10c +#define CAN_TSCV 0x110 +#define CAN_TXEFC 0x114 +#define CAN_RXFC 0x118 +#define CAN_AFC 0x11c +#define CAN_IDCODE0 0x120 +#define CAN_IDMASK0 0x124 +#define CAN_IDCODE1 0x128 +#define CAN_IDMASK1 0x12c +#define CAN_IDCODE2 0x130 +#define CAN_IDMASK2 0x134 +#define CAN_IDCODE3 0x138 +#define CAN_IDMASK3 0x13c +#define CAN_IDCODE4 0x140 +#define CAN_IDMASK4 0x144 +#define CAN_TXFIC 0x200 +#define CAN_TXID 0x204 +#define CAN_TXDAT0 0x208 +#define CAN_TXDAT1 0x20c +#define CAN_TXDAT2 0x210 +#define CAN_TXDAT3 0x214 +#define CAN_TXDAT4 0x218 +#define CAN_TXDAT5 0x21c +#define CAN_TXDAT6 0x220 +#define CAN_TXDAT7 0x224 +#define CAN_TXDAT8 0x228 +#define CAN_TXDAT9 0x22c +#define CAN_TXDAT10 0x230 +#define CAN_TXDAT11 0x234 +#define CAN_TXDAT12 0x238 +#define CAN_TXDAT13 0x23c +#define CAN_TXDAT14 0x240 +#define CAN_TXDAT15 0x244 +#define CAN_RXFIC 0x300 +#define CAN_RXID 0x304 +#define CAN_RXTS 0x308 +#define CAN_RXDAT0 0x30c +#define CAN_RXDAT1 0x310 +#define CAN_RXDAT2 0x314 +#define CAN_RXDAT3 0x318 +#define CAN_RXDAT4 0x31c +#define CAN_RXDAT5 0x320 +#define CAN_RXDAT6 0x324 +#define CAN_RXDAT7 0x328 +#define CAN_RXDAT8 0x32c +#define CAN_RXDAT9 0x330 +#define CAN_RXDAT10 0x334 +#define CAN_RXDAT11 0x338 +#define CAN_RXDAT12 0x33c +#define CAN_RXDAT13 0x340 +#define CAN_RXDAT14 0x344 +#define CAN_RXDAT15 0x348 +#define CAN_RXFRD 0x400 +#define CAN_TXEFRD 0x500 + +enum +{ + ROCKCHIP_CANFD_MODE = 0, + ROCKCHIP_CAN_MODE, +}; + +#define DATE_LENGTH_12_BYTE 0x9 +#define DATE_LENGTH_16_BYTE 0xa +#define DATE_LENGTH_20_BYTE 0xb +#define DATE_LENGTH_24_BYTE 0xc +#define DATE_LENGTH_32_BYTE 0xd +#define DATE_LENGTH_48_BYTE 0xe +#define DATE_LENGTH_64_BYTE 0xf + +#define SLEEP_STATE RT_BIT(6) +#define BUS_OFF_STATE RT_BIT(5) +#define ERROR_WARNING_STATE RT_BIT(4) +#define TX_PERIOD_STATE RT_BIT(3) +#define RX_PERIOD_STATE RT_BIT(2) +#define TX_BUFFER_FULL_STATE RT_BIT(1) +#define RX_BUFFER_FULL_STATE RT_BIT(0) + +#define CAN_TX0_REQ RT_BIT(0) +#define CAN_TX1_REQ RT_BIT(1) +#define CAN_TX_REQ_FULL ((CAN_TX0_REQ) | (CAN_TX1_REQ)) + +#define MODE_FDOE RT_BIT(15) +#define MODE_BRSD RT_BIT(13) +#define MODE_SPACE_RX RT_BIT(12) +#define MODE_AUTO_RETX RT_BIT(10) +#define MODE_RXSORT RT_BIT(7) +#define MODE_TXORDER RT_BIT(6) +#define MODE_RXSTX RT_BIT(5) +#define MODE_LBACK RT_BIT(4) +#define MODE_SILENT RT_BIT(3) +#define MODE_SELF_TEST RT_BIT(2) +#define MODE_SLEEP RT_BIT(1) +#define RESET_MODE 0 +#define WORK_MODE RT_BIT(0) + +#define RX_FINISH_INT RT_BIT(0) +#define TX_FINISH_INT RT_BIT(1) +#define ERR_WARN_INT RT_BIT(2) +#define RX_BUF_OV_INT RT_BIT(3) +#define PASSIVE_ERR_INT RT_BIT(4) +#define TX_LOSTARB_INT RT_BIT(5) +#define BUS_ERR_INT RT_BIT(6) +#define RX_FIFO_FULL_INT RT_BIT(7) +#define RX_FIFO_OV_INT RT_BIT(8) +#define BUS_OFF_INT RT_BIT(9) +#define BUS_OFF_RECOVERY_INT RT_BIT(10) +#define TSC_OV_INT RT_BIT(11) +#define TXE_FIFO_OV_INT RT_BIT(12) +#define TXE_FIFO_FULL_INT RT_BIT(13) +#define WAKEUP_INT RT_BIT(14) + +#define ERR_TYPE_MASK RT_GENMASK(28, 26) +#define ERR_TYPE_SHIFT 26 +#define BIT_ERR 0 +#define STUFF_ERR 1 +#define FORM_ERR 2 +#define ACK_ERR 3 +#define CRC_ERR 4 +#define ERR_DIR_RX RT_BIT(25) +#define ERR_LOC_MASK RT_GENMASK(15, 0) + +/* Nominal Bit Timing & Prescaler Register (NBTP) */ +#define NBTP_MODE_3_SAMPLES RT_BIT(31) +#define NBTP_NSJW_SHIFT 24 +#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT) +#define NBTP_NBRP_SHIFT 16 +#define NBTP_NBRP_MASK (0xff << NBTP_NBRP_SHIFT) +#define NBTP_NTSEG2_SHIFT 8 +#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT) +#define NBTP_NTSEG1_SHIFT 0 +#define NBTP_NTSEG1_MASK (0x7f << NBTP_NTSEG1_SHIFT) + +/* Data Bit Timing & Prescaler Register (DBTP) */ +#define DBTP_MODE_3_SAMPLES RT_BIT(21) +#define DBTP_DSJW_SHIFT 17 +#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) +#define DBTP_DBRP_SHIFT 9 +#define DBTP_DBRP_MASK (0xff << DBTP_DBRP_SHIFT) +#define DBTP_DTSEG2_SHIFT 5 +#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT) +#define DBTP_DTSEG1_SHIFT 0 +#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT) + +/* Transmitter Delay Compensation Register (TDCR) */ +#define TDCR_TDCO_SHIFT 1 +#define TDCR_TDCO_MASK (0x3f << TDCR_TDCO_SHIFT) +#define TDCR_TDC_ENABLE RT_BIT(0) + +#define TX_FD_ENABLE RT_BIT(5) +#define TX_FD_BRS_ENABLE RT_BIT(4) + +#define FIFO_ENABLE RT_BIT(0) + +#define FORMAT_SHIFT 7 +#define FORMAT_MASK (0x1 << FORMAT_SHIFT) +#define RTR_SHIFT 6 +#define RTR_MASK (0x1 << RTR_SHIFT) +#define FDF_SHIFT 5 +#define FDF_MASK (0x1 << FDF_SHIFT) +#define BRS_SHIFT 4 +#define BRS_MASK (0x1 << BRS_SHIFT) +#define TDC_SHIFT 1 +#define TDC_MASK (0x3f << TDC_SHIFT) +#define DLC_SHIFT 0 +#define DLC_MASK (0xf << DLC_SHIFT) + +#define CAN_RF_SIZE 0x48 +#define CAN_TEF_SIZE 0x8 +#define CAN_TXEFRD_OFFSET(n) (CAN_TXEFRD + CAN_TEF_SIZE * (n)) +#define CAN_RXFRD_OFFSET(n) (CAN_RXFRD + CAN_RF_SIZE * (n)) + +#define CAN_RX_FILTER_MASK 0x1fffffff + +struct rockchip_canfd +{ + struct rt_can_device parent; + + int irq; + void *regs; + rt_ubase_t mode; + + struct rt_can_msg rx_msg, tx_msg; + + struct rt_clk_array *clk_arr; + struct rt_reset_control *rstc; +}; + +#define raw_to_rockchip_canfd(raw) rt_container_of(raw, struct rockchip_canfd, parent) + +rt_inline rt_uint32_t rockchip_canfd_read(struct rockchip_canfd *rk_canfd, + int offset) +{ + return HWREG32(rk_canfd->regs + offset); +} + +rt_inline void rockchip_canfd_write(struct rockchip_canfd *rk_canfd, + int offset, rt_uint32_t val) +{ + HWREG32(rk_canfd->regs + offset) = val; +} + +static rt_err_t set_reset_mode(struct rockchip_canfd *rk_canfd) +{ + rt_reset_control_assert(rk_canfd->rstc); + rt_hw_us_delay(2); + rt_reset_control_deassert(rk_canfd->rstc); + + rockchip_canfd_write(rk_canfd, CAN_MODE, 0); + + return RT_EOK; +} + +static rt_err_t set_normal_mode(struct rockchip_canfd *rk_canfd) +{ + rt_uint32_t val; + + val = rockchip_canfd_read(rk_canfd, CAN_MODE); + val |= WORK_MODE; + rockchip_canfd_write(rk_canfd, CAN_MODE, val); + + return RT_EOK; +} + +static rt_err_t rockchip_canfd_configure(struct rt_can_device *can, struct can_configure *conf) +{ + rt_uint32_t val, reg_btp; + rt_uint16_t n_brp, n_tseg1, n_tseg2, d_brp, d_tseg1, d_tseg2, tdc = 0, sjw = 0; + struct rockchip_canfd *rk_canfd = raw_to_rockchip_canfd(can); + + set_reset_mode(rk_canfd); + + rockchip_canfd_write(rk_canfd, CAN_INT_MASK, 0xffff); + + /* RECEIVING FILTER, accept all */ + rockchip_canfd_write(rk_canfd, CAN_IDCODE, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK, CAN_RX_FILTER_MASK); + rockchip_canfd_write(rk_canfd, CAN_IDCODE0, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK0, CAN_RX_FILTER_MASK); + rockchip_canfd_write(rk_canfd, CAN_IDCODE1, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK1, CAN_RX_FILTER_MASK); + rockchip_canfd_write(rk_canfd, CAN_IDCODE2, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK2, CAN_RX_FILTER_MASK); + rockchip_canfd_write(rk_canfd, CAN_IDCODE3, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK3, CAN_RX_FILTER_MASK); + rockchip_canfd_write(rk_canfd, CAN_IDCODE4, 0); + rockchip_canfd_write(rk_canfd, CAN_IDMASK4, CAN_RX_FILTER_MASK); + + /* Set mode */ + val = rockchip_canfd_read(rk_canfd, CAN_MODE); + + /* RX fifo enable */ + rockchip_canfd_write(rk_canfd, CAN_RXFC, + rockchip_canfd_read(rk_canfd, CAN_RXFC) | FIFO_ENABLE); + + /* Mode */ + switch (conf->mode) + { + case RT_CAN_MODE_NORMAL: + val |= MODE_FDOE; + rockchip_canfd_write(rk_canfd, CAN_TXFIC, + rockchip_canfd_read(rk_canfd, CAN_TXFIC) | TX_FD_ENABLE); + break; + + case RT_CAN_MODE_LISTEN: + val |= MODE_SILENT; + break; + + case RT_CAN_MODE_LOOPBACK: + val |= MODE_SELF_TEST | MODE_LBACK; + break; + } + + val |= MODE_AUTO_RETX; + + rockchip_canfd_write(rk_canfd, CAN_MODE, val); + + switch (conf->baud_rate) + { + case CAN1MBaud: + d_brp = 4; + d_tseg1 = 13; + d_tseg2 = 4; + n_brp = 4; + n_tseg1 = 13; + n_tseg2 = 4; + break; + + case CAN800kBaud: + d_brp = 4; + d_tseg1 = 18; + d_tseg2 = 4; + n_brp = 4; + n_tseg1 = 18; + n_tseg2 = 4; + break; + + case CAN500kBaud: + d_brp = 9; + d_tseg1 = 13; + d_tseg2 = 4; + n_brp = 4; + n_tseg1 = 33; + n_tseg2 = 4; + break; + + case CAN250kBaud: + d_brp = 9; + d_tseg1 = 24; + d_tseg2 = 13; + n_brp = 4; + n_tseg1 = 68; + n_tseg2 = 9; + break; + + case CAN125kBaud: + d_brp = 24; + d_tseg1 = 13; + d_tseg2 = 4; + n_brp = 9; + n_tseg1 = 43; + n_tseg2 = 4; + break; + + case CAN100kBaud: + d_brp = 24; + d_tseg1 = 33; + d_tseg2 = 4; + n_brp = 24; + n_tseg1 = 33; + n_tseg2 = 4; + break; + + case CAN50kBaud: + d_brp = 49; + d_tseg1 = 13; + d_tseg2 = 4; + n_brp = 24; + n_tseg1 = 68; + n_tseg2 = 9; + break; + + default: + d_brp = 4; + d_tseg1 = 13; + d_tseg2 = 4; + n_brp = 4; + n_tseg1 = 13; + n_tseg2 = 4; + break; + } + + reg_btp = (n_brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) | + (n_tseg1 << NBTP_NTSEG1_SHIFT) | (n_tseg2 << NBTP_NTSEG2_SHIFT); + + rockchip_canfd_write(rk_canfd, CAN_NBTP, reg_btp); + + reg_btp |= (d_brp << DBTP_DBRP_SHIFT) | (sjw << DBTP_DSJW_SHIFT) | + (d_tseg1 << DBTP_DTSEG1_SHIFT) | (d_tseg2 << DBTP_DTSEG2_SHIFT); + + rockchip_canfd_write(rk_canfd, CAN_DBTP, reg_btp); + + if (tdc) + { + rockchip_canfd_write(rk_canfd, CAN_TDCR, + rockchip_canfd_read(rk_canfd, CAN_TDCR) | (tdc << TDC_SHIFT)); + } + + set_normal_mode(rk_canfd); + + rockchip_canfd_write(rk_canfd, CAN_INT_MASK, 0); + + return RT_EOK; +} + +static rt_err_t rockchip_canfd_control(struct rt_can_device *can, int cmd, void *args) +{ + struct rockchip_canfd *rk_canfd = raw_to_rockchip_canfd(can); + + switch (cmd) + { + case RT_CAN_CMD_SET_MODE: + switch ((rt_base_t)args) + { + case RT_CAN_MODE_NORMAL: + case RT_CAN_MODE_LISTEN: + case RT_CAN_MODE_LOOPBACK: + case RT_CAN_MODE_LOOPBACKANLISTEN: + can->config.mode = (rt_uint32_t)(rt_base_t)args; + break; + + default: + return -RT_ENOSYS; + } + break; + + case RT_CAN_CMD_SET_BAUD: + can->config.baud_rate = (rt_uint32_t)(rt_base_t)args; + break; + + case RT_CAN_CMD_GET_STATUS: + can->status.rcverrcnt = rockchip_canfd_read(rk_canfd, CAN_RX_ERR_CNT); + can->status.snderrcnt = rockchip_canfd_read(rk_canfd, CAN_TX_ERR_CNT); + can->status.errcode = rockchip_canfd_read(rk_canfd, CAN_ERR_CODE); + rt_memcpy(args, &can->status, sizeof(can->status)); + return RT_EOK; + + default: + return -RT_ENOSYS; + } + + rockchip_canfd_configure(can, &can->config); + + return RT_EOK; +} + +static int rockchip_canfd_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno) +{ + rt_uint32_t dlc, cmd; + struct rt_can_msg *tx_msg; + struct rockchip_canfd *rk_canfd = raw_to_rockchip_canfd(can); + + tx_msg = &rk_canfd->tx_msg; + rt_memcpy(tx_msg, buf, sizeof(*tx_msg)); + + if (rockchip_canfd_read(rk_canfd, CAN_CMD) & CAN_TX0_REQ) + { + cmd = CAN_TX1_REQ; + } + else + { + cmd = CAN_TX0_REQ; + } + + dlc = can_len2dlc(tx_msg->len) & DLC_MASK; + + if (tx_msg->ide) + { + dlc |= FORMAT_MASK; + } + + if (tx_msg->rtr) + { + dlc |= RTR_MASK; + } + + if (can->config.mode == RT_CAN_MODE_NORMAL) + { + dlc |= TX_FD_ENABLE; + } + + rockchip_canfd_write(rk_canfd, CAN_TXID, tx_msg->id); + rockchip_canfd_write(rk_canfd, CAN_TXFIC, dlc); + + for (int i = 0; i < tx_msg->len; i += 4) + { + rockchip_canfd_write(rk_canfd, CAN_TXDAT0 + i, + *(rt_uint32_t *)(tx_msg->data + i)); + } + + rockchip_canfd_write(rk_canfd, CAN_CMD, cmd); + + return RT_EOK; +} + +static int rockchip_canfd_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno) +{ + struct rockchip_canfd *rk_canfd = raw_to_rockchip_canfd(can); + + rt_memcpy(buf, &rk_canfd->rx_msg, sizeof(rk_canfd->rx_msg)); + + return RT_EOK; +} + +static const struct rt_can_ops rockchip_canfd_ops = +{ + .configure = rockchip_canfd_configure, + .control = rockchip_canfd_control, + .sendmsg = rockchip_canfd_sendmsg, + .recvmsg = rockchip_canfd_recvmsg, +}; + +static rt_err_t rockchip_canfd_rx(struct rockchip_canfd *rk_canfd) +{ + struct rt_can_msg *rx_msg = &rk_canfd->rx_msg; + rt_uint32_t id_rockchip_canfd, dlc, data[16] = { 0 }; + + dlc = rockchip_canfd_read(rk_canfd, CAN_RXFRD); + id_rockchip_canfd = rockchip_canfd_read(rk_canfd, CAN_RXFRD); + rockchip_canfd_read(rk_canfd, CAN_RXFRD); + + for (int i = 0; i < RT_ARRAY_SIZE(data); ++i) + { + data[i] = rockchip_canfd_read(rk_canfd, CAN_RXFRD); + } + + rx_msg->id = id_rockchip_canfd; + rx_msg->ide = (dlc & FORMAT_MASK) >> FORMAT_SHIFT; + rx_msg->rtr = (dlc & RTR_MASK) >> RTR_SHIFT; + + if (dlc & FDF_MASK) + { + rx_msg->len = can_dlc2len(dlc & DLC_MASK); + } + else + { + rx_msg->len = can_get_dlc(dlc & DLC_MASK); + } + + if (!rx_msg->rtr) + { + for (int i = 0; i < rx_msg->len; i += 4) + { + *(rt_uint32_t *)(rx_msg->data + i) = data[i / 4]; + } + } + + return RT_EOK; +} + +static rt_err_t rockchip_canfd_err(struct rockchip_canfd *rk_canfd, rt_uint8_t ints) +{ + rt_uint32_t sta_reg; + struct rt_can_device *can = &rk_canfd->parent; + + can->status.rcverrcnt = rockchip_canfd_read(rk_canfd, CAN_RX_ERR_CNT); + can->status.snderrcnt = rockchip_canfd_read(rk_canfd, CAN_TX_ERR_CNT); + can->status.errcode = rockchip_canfd_read(rk_canfd, CAN_ERR_CODE); + sta_reg = rockchip_canfd_read(rk_canfd, CAN_STATE); + + if (ints & BUS_OFF_INT) + { + can->status.errcode |= BUSOFF; + } + else if (ints & ERR_WARN_INT) + { + can->status.errcode |= ERRWARNING; + } + else if (ints & PASSIVE_ERR_INT) + { + can->status.errcode |= ERRPASSIVE; + } + + if ((can->status.errcode & BUSOFF) || (sta_reg & BUS_OFF_STATE)) + { + LOG_E("%s should bus off"); + } + + return RT_EOK; +} + +static void rockchip_canfd_isr(int irqno, void *param) +{ + rt_uint8_t ints; + struct rockchip_canfd *rk_canfd = param; + const rt_uint8_t err_ints = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | + TX_LOSTARB_INT | BUS_ERR_INT; + + ints = rockchip_canfd_read(rk_canfd, CAN_INT); + + if (ints & RX_FINISH_INT) + { + rockchip_canfd_rx(rk_canfd); + rt_hw_can_isr(&rk_canfd->parent, RT_CAN_EVENT_RX_IND); + } + else if (ints & TX_FINISH_INT) + { + rt_hw_can_isr(&rk_canfd->parent, RT_CAN_EVENT_TX_DONE); + } + else if (ints & (RX_FIFO_FULL_INT | RX_FIFO_OV_INT)) + { + rt_hw_can_isr(&rk_canfd->parent, RT_CAN_EVENT_RXOF_IND); + rockchip_canfd_rx(rk_canfd); + } + else if (ints & err_ints) + { + if (rockchip_canfd_err(rk_canfd, ints)) + { + LOG_E("Bus error in ISR"); + } + } + + rockchip_canfd_write(rk_canfd, CAN_INT, ints); +} + +static rt_err_t rockchip_canfd_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_can_device *can; + struct can_configure *conf; + struct rt_device *dev = &pdev->parent; + struct rockchip_canfd *rk_canfd = rt_calloc(1, sizeof(*rk_canfd)); + + if (!rk_canfd) + { + return -RT_ENOMEM; + } + + rk_canfd->mode = (rt_ubase_t)pdev->id->data; + rk_canfd->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_canfd->regs) + { + err = -RT_EIO; + goto _fail; + } + + rk_canfd->irq = rt_dm_dev_get_irq(dev, 0); + + if (rk_canfd->irq < 0) + { + err = rk_canfd->irq; + goto _fail; + } + + rk_canfd->clk_arr = rt_clk_get_array(dev); + + if (!rk_canfd->clk_arr) + { + err = -RT_EIO; + goto _fail; + } + + if (rt_dm_dev_prop_read_bool(dev, "resets")) + { + rk_canfd->rstc = rt_reset_control_get_array(dev); + + if (!rk_canfd->rstc) + { + err = -RT_EIO; + + goto _fail; + } + } + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + can = &rk_canfd->parent; + conf = &can->config; + + conf->baud_rate = rt_clk_get_rate(rk_canfd->clk_arr->clks[0]); + conf->msgboxsz = 1; + conf->sndboxnumber = 1; + conf->mode = RT_CAN_MODE_NORMAL; + conf->ticks = 50; +#ifdef RT_CAN_USING_HDR + conf->maxhdr = 4; +#endif + + rt_dm_dev_set_name_auto(&can->parent, "can"); + dev_name = rt_dm_dev_get_name(&can->parent); + + rt_hw_interrupt_install(rk_canfd->irq, rockchip_canfd_isr, rk_canfd, dev_name); + rt_hw_interrupt_umask(rk_canfd->irq); + + if ((err = rt_hw_can_register(can, dev_name, &rockchip_canfd_ops, rk_canfd))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rk_canfd->regs) + { + rt_iounmap(rk_canfd->regs); + } + + if (rk_canfd->clk_arr) + { + rt_clk_array_put(rk_canfd->clk_arr); + } + + if (rk_canfd->rstc) + { + rt_reset_control_put(rk_canfd->rstc); + } + + rt_free(rk_canfd); + + return err; +} + +static const struct rt_ofw_node_id rockchip_canfd_ofw_ids[] = +{ + { .compatible = "rockchip,canfd-1.0", .data = (void *)ROCKCHIP_CANFD_MODE }, + { .compatible = "rockchip,can-2.0", .data = (void *)ROCKCHIP_CAN_MODE }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_canfd_driver = +{ + .name = "canfd-rockchip", + .ids = rockchip_canfd_ofw_ids, + + .probe = rockchip_canfd_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_canfd_driver); diff --git a/components/drivers/clk/Kconfig b/components/drivers/clk/Kconfig index d9ab62684c58..f376f10d59f5 100755 --- a/components/drivers/clk/Kconfig +++ b/components/drivers/clk/Kconfig @@ -1,4 +1,7 @@ menuconfig RT_USING_CLK bool "Using Common Clock Framework (CLK)" depends on RT_USING_DM - default n + select RT_USING_ADT_REF + default y + +source "$RTT_DIR/components/drivers/clk/rockchip/Kconfig" diff --git a/components/drivers/clk/SConscript b/components/drivers/clk/SConscript index 9a9b21b8c657..af6ed4dbeb2c 100644 --- a/components/drivers/clk/SConscript +++ b/components/drivers/clk/SConscript @@ -1,15 +1,26 @@ from building import * group = [] +objs = [] if not GetDepend(['RT_USING_CLK']): Return('group') cwd = GetCurrentDir() +list = os.listdir(cwd) CPPPATH = [cwd + '/../include'] -src = ['clk.c', 'clk-fixed-rate.c'] +src = ['clk.c'] + +if GetDepend(['RT_USING_OFW']): + src += ['clk-fixed-rate.c'] group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) -Return('group') +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 + group + +Return('objs') diff --git a/components/drivers/clk/clk.c b/components/drivers/clk/clk.c index f11ecd19813e..a52c833a91df 100644 --- a/components/drivers/clk/clk.c +++ b/components/drivers/clk/clk.c @@ -8,7 +8,6 @@ * 2022-11-26 GuEe-GUI first version */ -#include #include #include @@ -21,35 +20,108 @@ static struct rt_spinlock _clk_lock = { 0 }; static rt_list_t _clk_nodes = RT_LIST_OBJECT_INIT(_clk_nodes); +static rt_list_t _clk_notifier_nodes = RT_LIST_OBJECT_INIT(_clk_notifier_nodes); static void clk_release(struct ref *r) { - struct rt_clk *clk = rt_container_of(r, struct rt_clk, ref); + struct rt_clk_node *clk_np = rt_container_of(r, struct rt_clk_node, ref); - LOG_E("%s is release", clk->name); + LOG_E("%s is release", clk_np->name); RT_ASSERT(0); } -rt_inline struct rt_clk *clk_get(struct rt_clk *clk) +rt_inline struct rt_clk_node *clk_get(struct rt_clk_node *clk_np) { - ref_get(&clk->ref); + ref_get(&clk_np->ref); + + return clk_np; +} + +rt_inline void clk_put(struct rt_clk_node *clk_np) +{ + ref_put(&clk_np->ref, &clk_release); +} + +static struct rt_clk *clk_alloc(struct rt_clk_node *clk_np, const char *dev_id, + const char *con_id, void *fw_node) +{ + struct rt_clk *clk = rt_calloc(1, sizeof(*clk)); + + if (clk) + { + clk->clk_np = clk_np; + clk->dev_id = dev_id; + clk->con_id = con_id; + + clk->fw_node = fw_node; + } + + return clk; +} + +static void clk_free(struct rt_clk *clk) +{ + struct rt_clk_node *clk_np = clk->clk_np; + + if (clk_np && clk_np->ops->finit) + { + clk_np->ops->finit(clk); + } + + rt_free(clk); +} + +static struct rt_clk *clk_create(struct rt_clk_node *clk_np, const char *dev_id, + const char *con_id, void *fw_data, void *fw_node) +{ + struct rt_clk *clk = clk_alloc(clk_np, dev_id, con_id, fw_node); + + if (clk) + { + clk_get(clk_np); + + if (clk_np->ops->init && clk_np->ops->init(clk, fw_data)) + { + LOG_E("Dev[%s] Con[%s] init fail", dev_id, con_id); + + clk_free(clk); + clk = RT_NULL; + } + } return clk; } -rt_inline void clk_put(struct rt_clk *clk) +static rt_err_t clk_notify(struct rt_clk_node *clk_np, rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate) { - ref_put(&clk->ref, &clk_release); + rt_err_t err = RT_EOK; + struct rt_clk_notifier *notifier; + + rt_list_for_each_entry(notifier, &_clk_notifier_nodes, list) + { + if (notifier->clk->clk_np == clk_np) + { + err = notifier->callback(notifier, msg, old_rate, new_rate); + + /* Only check hareware's error */ + if (err == -RT_EIO) + { + break; + } + } + } + + return err; } -static void clk_set_parent(struct rt_clk *clk, struct rt_clk *parent) +static void clk_set_parent(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np) { rt_spin_lock(&_clk_lock); - clk->parent = parent; + clk_np->parent = parent_np; - rt_list_insert_after(&parent->children_nodes, &clk->list); + rt_list_insert_after(&parent_np->children_nodes, &clk_np->list); rt_spin_unlock(&_clk_lock); } @@ -58,59 +130,72 @@ static const struct rt_clk_ops unused_clk_ops = { }; -rt_err_t rt_clk_register(struct rt_clk *clk, struct rt_clk *parent) +rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np) { rt_err_t err = RT_EOK; + struct rt_clk *clk = RT_NULL; - if (clk) + if (clk_np) + { + clk = clk_alloc(clk_np, RT_NULL, RT_NULL, RT_NULL); + } + else { - if (!clk->ops) + err = -RT_EINVAL; + } + + if (!err && clk_np) + { + clk_np->clk = clk; + + if (!clk_np->ops) { - clk->ops = &unused_clk_ops; + clk_np->ops = &unused_clk_ops; } - ref_init(&clk->ref); - rt_list_init(&clk->list); - rt_list_init(&clk->children_nodes); + ref_init(&clk_np->ref); + rt_list_init(&clk_np->list); + rt_list_init(&clk_np->children_nodes); - if (parent) + if (parent_np) { - clk_set_parent(clk, parent); + clk_set_parent(clk_np, parent_np); } else { - clk->parent = RT_NULL; + clk_np->parent = RT_NULL; rt_spin_lock(&_clk_lock); - rt_list_insert_after(&_clk_nodes, &clk->list); + rt_list_insert_after(&_clk_nodes, &clk_np->list); rt_spin_unlock(&_clk_lock); } } else { - err = -RT_EINVAL; + err = -RT_ENOMEM; } return err; } -rt_err_t rt_clk_unregister(struct rt_clk *clk) +rt_err_t rt_clk_unregister(struct rt_clk_node *clk_np) { rt_err_t err = RT_EOK; - if (clk) + if (clk_np) { err = -RT_EBUSY; rt_spin_lock(&_clk_lock); - if (rt_list_isempty(&clk->children_nodes)) + if (rt_list_isempty(&clk_np->children_nodes)) { - if (ref_read(&clk->ref) <= 1) + if (ref_read(&clk_np->ref) <= 1) { - rt_list_remove(&clk->list); + rt_list_remove(&clk_np->list); + clk_free(clk_np->clk); err = RT_EOK; } @@ -126,42 +211,63 @@ rt_err_t rt_clk_unregister(struct rt_clk *clk) return err; } -void rt_clk_put(struct rt_clk *clk) +rt_err_t rt_clk_notifier_register(struct rt_clk *clk, struct rt_clk_notifier *notifier) { - if (clk) + if (!clk || !clk->clk_np || !notifier) { - clk_put(clk); + return -RT_EINVAL; } + + rt_spin_lock(&_clk_lock); + + ++clk->clk_np->notifier_count; + rt_list_init(¬ifier->list); + rt_list_insert_after(&_clk_notifier_nodes, ¬ifier->list); + + rt_spin_unlock(&_clk_lock); + + return RT_EOK; } -struct rt_clk *rt_clk_get_parent(struct rt_clk *clk) +rt_err_t rt_clk_notifier_unregister(struct rt_clk *clk, struct rt_clk_notifier *notifier) { - struct rt_clk *parent = RT_NULL; + struct rt_clk_notifier *notifier_find; - if (clk) + if (!clk || !notifier) { - rt_spin_lock(&_clk_lock); + return -RT_EINVAL; + } - parent = clk->parent; + rt_spin_lock(&_clk_lock); - rt_spin_unlock(&_clk_lock); + rt_list_for_each_entry(notifier_find, &_clk_notifier_nodes, list) + { + if (notifier_find->clk->clk_np == notifier->clk->clk_np) + { + --clk->clk_np->notifier_count; + rt_list_remove(¬ifier->list); + + break; + } } - return parent; + rt_spin_unlock(&_clk_lock); + + return RT_EOK; } -static rt_err_t clk_prepare(struct rt_clk *clk) +static rt_err_t clk_prepare(struct rt_clk *clk, struct rt_clk_node *clk_np) { rt_err_t err = RT_EOK; - if (clk->parent) + if (clk_np->parent) { - clk_prepare(clk->parent); + clk_prepare(clk_np->clk, clk_np->parent); } - if (clk->ops->prepare) + if (clk_np->ops->prepare) { - err = clk->ops->prepare(clk); + err = clk_np->ops->prepare(clk); } return err; @@ -173,11 +279,11 @@ rt_err_t rt_clk_prepare(struct rt_clk *clk) RT_DEBUG_NOT_IN_INTERRUPT; - if (clk) + if (clk && clk->clk_np) { rt_spin_lock(&_clk_lock); - err = clk_prepare(clk); + err = clk_prepare(clk, clk->clk_np); rt_spin_unlock(&_clk_lock); } @@ -189,16 +295,16 @@ rt_err_t rt_clk_prepare(struct rt_clk *clk) return err; } -static void clk_unprepare(struct rt_clk *clk) +static void clk_unprepare(struct rt_clk *clk, struct rt_clk_node *clk_np) { - if (clk->parent) + if (clk_np->parent) { - clk_unprepare(clk->parent); + clk_unprepare(clk_np->clk, clk_np->parent); } - if (clk->ops->unprepare) + if (clk_np->ops->unprepare) { - clk->ops->unprepare(clk); + clk_np->ops->unprepare(clk); } } @@ -208,11 +314,11 @@ rt_err_t rt_clk_unprepare(struct rt_clk *clk) RT_DEBUG_NOT_IN_INTERRUPT; - if (clk) + if (clk && clk->clk_np) { rt_spin_lock(&_clk_lock); - clk_unprepare(clk); + clk_unprepare(clk, clk->clk_np); rt_spin_unlock(&_clk_lock); } @@ -224,18 +330,18 @@ rt_err_t rt_clk_unprepare(struct rt_clk *clk) return err; } -static rt_err_t clk_enable(struct rt_clk *clk) +static rt_err_t clk_enable(struct rt_clk *clk, struct rt_clk_node *clk_np) { rt_err_t err = RT_EOK; - if (clk->parent) + if (clk_np->parent) { - clk_enable(clk->parent); + clk_enable(clk_np->clk, clk_np->parent); } - if (clk->ops->enable) + if (clk_np->ops->enable) { - err = clk->ops->enable(clk); + err = clk_np->ops->enable(clk); } return err; @@ -245,11 +351,11 @@ rt_err_t rt_clk_enable(struct rt_clk *clk) { rt_err_t err = RT_EOK; - if (clk) + if (clk && clk->clk_np) { rt_spin_lock(&_clk_lock); - err = clk_enable(clk); + err = clk_enable(clk, clk->clk_np); rt_spin_unlock(&_clk_lock); } @@ -261,26 +367,26 @@ rt_err_t rt_clk_enable(struct rt_clk *clk) return err; } -static void clk_disable(struct rt_clk *clk) +static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np) { - if (clk->parent) + if (clk_np->parent) { - clk_disable(clk->parent); + clk_disable(clk_np->clk, clk_np->parent); } - if (clk->ops->disable) + if (clk_np->ops->disable) { - clk->ops->disable(clk); + clk_np->ops->disable(clk); } } void rt_clk_disable(struct rt_clk *clk) { - if (clk) + if (clk && clk->clk_np) { rt_spin_lock(&_clk_lock); - clk_disable(clk); + clk_disable(clk, clk->clk_np); rt_spin_unlock(&_clk_lock); } @@ -325,30 +431,170 @@ void rt_clk_disable_unprepare(struct rt_clk *clk) } } +rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr) +{ + rt_err_t err = RT_EOK; + + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + if ((err = rt_clk_prepare(clk_arr->clks[i]))) + { + LOG_E("CLK Array[%d] %s failed error = %s", i, + "prepare", rt_strerror(err)); + + while (i --> 0) + { + rt_clk_unprepare(clk_arr->clks[i]); + } + + break; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_clk_array_unprepare(struct rt_clk_array *clk_arr) +{ + rt_err_t err = RT_EOK; + + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + if ((err = rt_clk_unprepare(clk_arr->clks[i]))) + { + LOG_E("CLK Array[%d] %s failed error = %s", i, + "unprepare", rt_strerror(err)); + + break; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr) +{ + rt_err_t err = RT_EOK; + + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + if ((err = rt_clk_enable(clk_arr->clks[i]))) + { + LOG_E("CLK Array[%d] %s failed error = %s", i, + "enable", rt_strerror(err)); + + while (i --> 0) + { + rt_clk_disable(clk_arr->clks[i]); + } + + break; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +void rt_clk_array_disable(struct rt_clk_array *clk_arr) +{ + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + rt_clk_disable(clk_arr->clks[i]); + } + } +} + +rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr) +{ + rt_err_t err = RT_EOK; + + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + if ((err = rt_clk_prepare_enable(clk_arr->clks[i]))) + { + LOG_E("CLK Array[%d] %s failed error = %s", i, + "prepare_enable", rt_strerror(err)); + + while (i --> 0) + { + rt_clk_disable_unprepare(clk_arr->clks[i]); + } + + break; + } + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +void rt_clk_array_disable_unprepare(struct rt_clk_array *clk_arr) +{ + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + rt_clk_disable_unprepare(clk_arr->clks[i]); + } + } +} + rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max) { rt_err_t err = RT_EOK; - if (clk) + if (clk && clk->clk_np) { + struct rt_clk_node *clk_np = clk->clk_np; + rt_spin_lock(&_clk_lock); - if (clk->ops->set_rate) + if (clk_np->ops->set_rate) { - rt_ubase_t rate = clk->rate; - rt_ubase_t old_min = clk->min_rate; - rt_ubase_t old_max = clk->max_rate; + rt_ubase_t rate = clk_np->rate; + rt_ubase_t old_min = clk_np->min_rate; + rt_ubase_t old_max = clk_np->max_rate; - clk->min_rate = min; - clk->max_rate = max; + clk_np->min_rate = min; + clk_np->max_rate = max; rate = rt_clamp(rate, min, max); - err = clk->ops->set_rate(clk, rate, rt_clk_get_rate(clk->parent)); + err = clk_np->ops->set_rate(clk, rate, + rt_clk_get_rate(clk_np->parent ? clk_np->parent->clk : RT_NULL)); if (err) { - clk->min_rate = old_min; - clk->max_rate = old_max; + clk_np->min_rate = old_min; + clk_np->max_rate = old_max; } } else @@ -370,9 +616,11 @@ rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate) { rt_err_t err = RT_EOK; - if (clk) + if (clk && clk->clk_np) { - err = rt_clk_set_rate_range(clk, rate, clk->max_rate); + struct rt_clk_node *clk_np = clk->clk_np; + + err = rt_clk_set_rate_range(clk, rate, clk_np->max_rate); } else { @@ -386,9 +634,11 @@ rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate) { rt_err_t err = RT_EOK; - if (clk) + if (clk && clk->clk_np) { - err = rt_clk_set_rate_range(clk, clk->min_rate, rate); + struct rt_clk_node *clk_np = clk->clk_np; + + err = rt_clk_set_rate_range(clk, clk_np->min_rate, rate); } else { @@ -402,17 +652,40 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate) { rt_err_t err = RT_EOK; - if (clk) + if (clk && clk->clk_np) { + struct rt_clk_node *clk_np = clk->clk_np; + rt_spin_lock(&_clk_lock); - if (clk->ops->set_rate) + if (clk_np->min_rate && rate < clk_np->min_rate) { - err = clk->ops->set_rate(clk, rate, rt_clk_get_rate(clk->parent)); + err = -RT_EINVAL; } - else + + if (clk_np->max_rate && rate > clk_np->max_rate) { - err = -RT_ENOSYS; + err = -RT_EINVAL; + } + + if (!err) + { + if (clk_np->ops->set_rate) + { + rt_ubase_t old_rate = clk_np->rate; + + err = clk_np->ops->set_rate(clk, rate, + rt_clk_get_rate(clk_np->parent ? clk_np->parent->clk : RT_NULL)); + + if (clk_np->rate != old_rate) + { + clk_notify(clk_np, RT_CLK_MSG_PRE_RATE_CHANGE, old_rate, clk_np->rate); + } + } + else + { + err = -RT_ENOSYS; + } } rt_spin_unlock(&_clk_lock); @@ -427,37 +700,276 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate) rt_ubase_t rt_clk_get_rate(struct rt_clk *clk) { - return clk ? clk->rate : -1UL; + rt_ubase_t rate = -1UL; + + if (clk) + { + if (clk->rate) + { + rate = clk->rate; + } + else if (clk->clk_np) + { + rate = clk->clk_np->rate; + } + } + + return rate; +} + +rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees) +{ + rt_err_t err = RT_EOK; + + if (clk && clk->clk_np && clk->clk_np->ops->set_phase) + { + rt_spin_lock(&_clk_lock); + + err = clk->clk_np->ops->set_phase(clk, degrees); + + rt_spin_unlock(&_clk_lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_base_t rt_clk_get_phase(struct rt_clk *clk) +{ + rt_base_t res = RT_EOK; + + if (clk && clk->clk_np && clk->clk_np->ops->get_phase) + { + rt_spin_lock(&_clk_lock); + + res = clk->clk_np->ops->get_phase(clk); + + rt_spin_unlock(&_clk_lock); + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate) +{ + rt_base_t res = RT_EOK; + + if (clk && clk->clk_np && clk->clk_np->ops->round_rate) + { + rt_ubase_t best_parent_rate; + + rt_spin_lock(&_clk_lock); + + res = clk->clk_np->ops->round_rate(clk, rate, &best_parent_rate); + (void)best_parent_rate; + + rt_spin_unlock(&_clk_lock); + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent) +{ + rt_err_t err = RT_EOK; + + if (clk && clk->clk_np && clk->clk_np->ops->set_parent) + { + rt_spin_lock(&_clk_lock); + + err = clk->clk_np->ops->set_parent(clk, clk_parent); + + rt_spin_unlock(&_clk_lock); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +struct rt_clk *rt_clk_get_parent(struct rt_clk *clk) +{ + struct rt_clk *parent = RT_NULL; + + if (clk) + { + struct rt_clk_node *clk_np = clk->clk_np; + + rt_spin_lock(&_clk_lock); + + parent = clk_np->parent ? clk_np->parent->clk : RT_NULL; + + rt_spin_unlock(&_clk_lock); + } + + return parent; } +struct rt_clk_array *rt_clk_get_array(struct rt_device *dev) +{ + struct rt_clk_array *clk_arr = RT_NULL; + #ifdef RT_USING_OFW -struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index) + clk_arr = rt_ofw_get_clk_array(dev->ofw_node); +#endif + + return clk_arr; +} + +struct rt_clk *rt_clk_get_by_index(struct rt_device *dev, int index) { struct rt_clk *clk = RT_NULL; - if (np && index >= 0) +#ifdef RT_USING_OFW + clk = rt_ofw_get_clk(dev->ofw_node, index); +#endif + + return clk; +} + +struct rt_clk *rt_clk_get_by_name(struct rt_device *dev, const char *name) +{ + struct rt_clk *clk = RT_NULL; + +#ifdef RT_USING_OFW + clk = rt_ofw_get_clk_by_name(dev->ofw_node, name); +#endif + + return clk; +} + +void rt_clk_array_put(struct rt_clk_array *clk_arr) +{ + if (clk_arr) + { + for (int i = 0; i < clk_arr->count; ++i) + { + if (clk_arr->clks[i]) + { + rt_clk_put(clk_arr->clks[i]); + } + else + { + break; + } + } + + rt_free(clk_arr); + } +} + +void rt_clk_put(struct rt_clk *clk) +{ + if (clk) + { + clk_put(clk->clk_np); + clk_free(clk); + } +} + +#ifdef RT_USING_OFW +static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name) +{ + struct rt_clk *clk = RT_NULL; + struct rt_ofw_cell_args clk_args; + + if (!rt_ofw_parse_phandle_cells(np, "clocks", "#clock-cells", index, &clk_args)) { - rt_phandle phandle; + struct rt_clk_node *clk_np = rt_ofw_data(clk_args.data); - rt_spin_lock(&_clk_lock); + rt_ofw_node_put(clk_args.data); - if (!rt_ofw_prop_read_u32_index(np, "clocks", index, (rt_uint32_t *)&phandle)) + if (clk_np) { - struct rt_ofw_node *clk_np = rt_ofw_find_node_by_phandle(phandle); + clk = clk_create(clk_np, np->full_name, name, &clk_args, np); + } + } - if (clk_np) + return clk; +} + +static struct rt_clk *ofw_get_clk(struct rt_ofw_node *np, int index, const char *name) +{ + struct rt_clk *clk; + + rt_spin_lock(&_clk_lock); + + clk = ofw_get_clk_no_lock(np, index, name); + + rt_spin_unlock(&_clk_lock); + + return clk; +} + +struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np) +{ + int count; + struct rt_clk_array *clk_arr = RT_NULL; + + if ((count = rt_ofw_count_phandle_cells(np, "clocks", "#clock-cells")) > 0) + { + clk_arr = rt_calloc(1, sizeof(*clk_arr) + sizeof(clk_arr->clks[0]) * count); + + if (clk_arr) + { + int i; + rt_bool_t has_name = rt_ofw_prop_read_bool(np, "clock-names"); + + clk_arr->count = count; + + rt_spin_lock(&_clk_lock); + + for (i = 0; i < count; ++i) { - clk = rt_ofw_data(clk_np); - rt_ofw_node_put(clk_np); + const char *name = RT_NULL; + + if (has_name) + { + rt_ofw_prop_read_string_index(np, "clock-names", i, &name); + } + + clk_arr->clks[i] = ofw_get_clk_no_lock(np, i, name); - if (clk) + if (!clk_arr->clks[i]) { - clk = clk_get(clk); + --i; + break; } } + + rt_spin_unlock(&_clk_lock); + + if (i < count) + { + rt_clk_array_put(clk_arr); + clk_arr = RT_NULL; + } } + } - rt_spin_unlock(&_clk_lock); + return clk_arr; +} + +struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index) +{ + struct rt_clk *clk = RT_NULL; + + if (np && index >= 0) + { + clk = ofw_get_clk(np, index, RT_NULL); } return clk; @@ -469,26 +981,14 @@ struct rt_clk *rt_ofw_get_clk_by_name(struct rt_ofw_node *np, const char *name) if (np && name) { - int index; - struct rt_ofw_cell_args clk_args; - - rt_spin_lock(&_clk_lock); - - index = rt_ofw_prop_index_of_string(np, "clock-names", name); + int index = rt_ofw_prop_index_of_string(np, "clock-names", name); - if (index >= 0 && !rt_ofw_parse_phandle_cells(np, "clocks", "#clock-cells", index, &clk_args)) + if (index >= 0) { - clk = rt_ofw_data(clk_args.data); - - if (clk) - { - clk = clk_get(clk); - } + clk = ofw_get_clk(np, index, name); } - - rt_spin_unlock(&_clk_lock); } return clk; } -#endif /* RT_USING_OFW */ \ No newline at end of file +#endif /* RT_USING_OFW */ diff --git a/components/drivers/clk/rockchip/Kconfig b/components/drivers/clk/rockchip/Kconfig new file mode 100644 index 000000000000..14b1f278d4c7 --- /dev/null +++ b/components/drivers/clk/rockchip/Kconfig @@ -0,0 +1,16 @@ +menuconfig RT_CLK_ROCKCHIP + bool "Rockchip clock controller common" + depends on RT_USING_CLK + select RT_USING_OFW + select RT_USING_RESET + default n + +config RT_CLK_ROCKCHIP_RK3308 + bool "Rockchip RK3308 clock controller support" + depends on RT_CLK_ROCKCHIP + default n + +config RT_CLK_ROCKCHIP_RK3568 + bool "Rockchip RK3568 clock controller support" + depends on RT_CLK_ROCKCHIP + default n diff --git a/components/drivers/clk/rockchip/SConscript b/components/drivers/clk/rockchip/SConscript new file mode 100644 index 000000000000..1c61f6c6faa9 --- /dev/null +++ b/components/drivers/clk/rockchip/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_CLK_ROCKCHIP']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_CLK_ROCKCHIP_RK3308']): + src += ['clk-rk3308.c'] + +if GetDepend(['RT_CLK_ROCKCHIP_RK3568']): + src += ['clk-rk3568.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/clk/rockchip/clk-pll.c b/components/drivers/clk/rockchip/clk-pll.c new file mode 100644 index 000000000000..b1ac354a0aa4 --- /dev/null +++ b/components/drivers/clk/rockchip/clk-pll.c @@ -0,0 +1,403 @@ +/* + * 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 + */ + +/* Define pll mode */ +#define RKCLK_PLL_MODE_SLOW 0 +#define RKCLK_PLL_MODE_NORMAL 1 +#define RKCLK_PLL_MODE_DEEP 2 + +/* Only support RK3036 type CLK */ +#define PLLCON0_FBDIV_MASK 0xfff +#define PLLCON0_FBDIV_SHIFT 0 +#define PLLCON0_POSTDIV1_MASK (0x7 << 12) +#define PLLCON0_POSTDIV1_SHIFT 12 +#define PLLCON1_LOCK_STATUS (1 << 10) +#define PLLCON1_REFDIV_MASK 0x3f +#define PLLCON1_REFDIV_SHIFT 0 +#define PLLCON1_POSTDIV2_MASK (0x7 << 6) +#define PLLCON1_POSTDIV2_SHIFT 6 +#define PLLCON1_DSMPD_MASK (0x1 << 12) +#define PLLCON1_DSMPD_SHIFT 12 +#define PLLCON2_FRAC_MASK 0xffffff +#define PLLCON2_FRAC_SHIFT 0 +#define PLLCON1_PWRDOWN_SHIT 13 +#define PLLCON1_PWRDOWN (1 << PLLCON1_PWRDOWN_SHIT) + +#define MIN_FOUTVCO_FREQ (800 * MHZ) +#define MAX_FOUTVCO_FREQ (2000 * MHZ) + +static struct rk_pll_rate_table auto_table; + +static int gcd(int m, int n) +{ + while (m > 0) + { + if (n > m) + { + int t = m; + m = n; + n = t; + } + m -= n; + } + + return n; +} + +/* + * rational_best_approximation(31415, 10000, + * (1 << 8) - 1, (1 << 5) - 1, &n, &d); + * + * you may look at given_numerator as a fixed point number, + * with the fractional part size described in given_denominator. + * + * for theoretical background, see: + * http://en.wikipedia.org/wiki/Continued_fraction + */ +static void rational_best_approximation(rt_ubase_t given_numerator, + rt_ubase_t given_denominator, + rt_ubase_t max_numerator, + rt_ubase_t max_denominator, + rt_ubase_t *best_numerator, + rt_ubase_t *best_denominator) +{ + rt_ubase_t n, d, n0, d0, n1, d1; + + n = given_numerator; + d = given_denominator; + n0 = 0; + d1 = 0; + n1 = 1; + d0 = 1; + + for (;;) + { + rt_ubase_t t, a; + + if (n1 > max_numerator || d1 > max_denominator) + { + n1 = n0; + d1 = d0; + break; + } + if (d == 0) + { + break; + } + t = d; + a = n / d; + d = n % d; + n = t; + t = n0 + a * n1; + n0 = n1; + n1 = t; + t = d0 + a * d1; + d0 = d1; + d1 = t; + } + *best_numerator = n1; + *best_denominator = d1; +} + +/* + * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): + * Formulas also embedded within the Fractional PLL Verilog model: + * If DSMPD = 1 (DSM is disabled, "integer mode") + * FOUTVCO = FREF / REFDIV * FBDIV + * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 + * Where: + * FOUTVCO = Fractional PLL non-divided output frequency + * FOUTPOSTDIV = Fractional PLL divided output frequency + * (output of second post divider) + * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) + * REFDIV = Fractional PLL input reference clock divider + * FBDIV = Integer value programmed into feedback divide + */ + +static int rk_pll_clk_set_postdiv(rt_ubase_t fout_hz, rt_uint32_t *postdiv1, + rt_uint32_t *postdiv2, rt_uint32_t *foutvco) +{ + rt_ubase_t freq; + + if (fout_hz < MIN_FOUTVCO_FREQ) + { + for (*postdiv1 = 1; *postdiv1 <= 7; ++(*postdiv1)) + { + for (*postdiv2 = 1; *postdiv2 <= 7; ++(*postdiv2)) + { + freq = fout_hz * (*postdiv1) * (*postdiv2); + if (freq >= MIN_FOUTVCO_FREQ && freq <= MAX_FOUTVCO_FREQ) + { + *foutvco = freq; + return 0; + } + } + } + } + else + { + *postdiv1 = 1; + *postdiv2 = 1; + } + return 0; +} + +static struct rk_pll_rate_table *rk_pll_clk_set_by_auto(rt_ubase_t fin_hz, rt_ubase_t fout_hz) +{ + struct rk_pll_rate_table *rate_table = &auto_table; + rt_uint32_t foutvco = fout_hz; + rt_ubase_t fin_64, frac_64; + rt_uint32_t f_frac, postdiv1, postdiv2; + rt_ubase_t clk_gcd = 0; + + if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) + { + return RT_NULL; + } + + rk_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco); + rate_table->postdiv1 = postdiv1; + rate_table->postdiv2 = postdiv2; + rate_table->dsmpd = 1; + + if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) + { + fin_hz /= MHZ; + foutvco /= MHZ; + clk_gcd = gcd(fin_hz, foutvco); + rate_table->refdiv = fin_hz / clk_gcd; + rate_table->fbdiv = foutvco / clk_gcd; + + rate_table->frac = 0; + } + else + { + clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ); + rate_table->refdiv = fin_hz / MHZ / clk_gcd; + rate_table->fbdiv = foutvco / MHZ / clk_gcd; + + rate_table->frac = 0; + + f_frac = (foutvco % MHZ); + fin_64 = fin_hz; + fin_64 = fin_64 / rate_table->refdiv; + frac_64 = f_frac << 24; + frac_64 = frac_64 / fin_64; + rate_table->frac = frac_64; + + if (rate_table->frac > 0) + { + rate_table->dsmpd = 0; + } + } + return rate_table; +} + +static const struct rk_pll_rate_table *rk_get_pll_settings(struct rk_pll_clock *pll, rt_ubase_t rate) +{ + struct rk_pll_rate_table *rate_table = pll->rate_table; + + while (rate_table->rate) + { + if (rate_table->rate == rate) + { + break; + } + ++rate_table; + } + + if (rate_table->rate != rate) + { + return rk_pll_clk_set_by_auto(24 * MHZ, rate); + } + else + { + return rate_table; + } +} + +static rt_ubase_t rk_pll_get_rate(struct rk_pll_clock *pll, void *base); + +static int rk_pll_set_rate(struct rk_pll_clock *pll, void *base, rt_ubase_t drate) +{ + const struct rk_pll_rate_table *rate; + + if (rk_pll_get_rate(pll, base) == drate) + { + return 0; + } + + pll->mode_mask = PLL_MODE_MASK; + rate = rk_get_pll_settings(pll, drate); + + if (!rate) + { + return -RT_ERROR; + } + + /* + * When power on or changing PLL setting, we must force PLL into slow mode + * to ensure output stable clock. + */ + rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, RKCLK_PLL_MODE_SLOW << pll->mode_shift); + + /* Power down */ + rk_setreg(base + pll->con_offset + 0x4, 1 << PLLCON1_PWRDOWN_SHIT); + + rk_clrsetreg(base + pll->con_offset, (PLLCON0_POSTDIV1_MASK | PLLCON0_FBDIV_MASK), + (rate->postdiv1 << PLLCON0_POSTDIV1_SHIFT) |rate->fbdiv); + rk_clrsetreg(base + pll->con_offset + 0x4, (PLLCON1_POSTDIV2_MASK | PLLCON1_REFDIV_MASK), + (rate->postdiv2 << PLLCON1_POSTDIV2_SHIFT | rate->refdiv << PLLCON1_REFDIV_SHIFT)); + + if (!rate->dsmpd) + { + rt_uint32_t val; + + rk_clrsetreg(base + pll->con_offset + 0x4, PLLCON1_DSMPD_MASK, + rate->dsmpd << PLLCON1_DSMPD_SHIFT); + + val = HWREG32(base + pll->con_offset + 0x8) & (~PLLCON2_FRAC_MASK); + HWREG32(base + pll->con_offset + 0x8) = val | (rate->frac << PLLCON2_FRAC_SHIFT); + } + + /* Power Up */ + rk_clrreg(base + pll->con_offset + 0x4, 1 << PLLCON1_PWRDOWN_SHIT); + + /* Waiting for pll lock */ + while (!(HWREG32(base + pll->con_offset + 0x4) & (1 << pll->lock_shift))) + { + } + + rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, RKCLK_PLL_MODE_NORMAL << pll->mode_shift); + + return 0; +} + +static rt_ubase_t rk_pll_get_rate(struct rk_pll_clock *pll, void *base) +{ + rt_uint32_t refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac; + rt_uint32_t con = 0, shift, mask; + rt_ubase_t rate; + + pll->mode_mask = PLL_MODE_MASK; + + con = HWREG32(base + pll->mode_offset); + shift = pll->mode_shift; + mask = pll->mode_mask << shift; + + switch ((con & mask) >> shift) + { + case RKCLK_PLL_MODE_SLOW: + return OSC_HZ; + case RKCLK_PLL_MODE_NORMAL: + /* normal mode */ + con = HWREG32(base + pll->con_offset); + postdiv1 = (con & PLLCON0_POSTDIV1_MASK) >> PLLCON0_POSTDIV1_SHIFT; + fbdiv = (con & PLLCON0_FBDIV_MASK) >> PLLCON0_FBDIV_SHIFT; + con = HWREG32(base + pll->con_offset + 0x4); + postdiv2 = (con & PLLCON1_POSTDIV2_MASK) >> PLLCON1_POSTDIV2_SHIFT; + refdiv = (con & PLLCON1_REFDIV_MASK) >> PLLCON1_REFDIV_SHIFT; + dsmpd = (con & PLLCON1_DSMPD_MASK) >> PLLCON1_DSMPD_SHIFT; + con = HWREG32(base + pll->con_offset + 0x8); + frac = (con & PLLCON2_FRAC_MASK) >> PLLCON2_FRAC_SHIFT; + rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; + + if (dsmpd == 0) + { + rt_uint64_t frac_rate = OSC_HZ * (rt_uint64_t)frac; + + rt_do_div(frac_rate, refdiv); + frac_rate >>= 24; + rt_do_div(frac_rate, postdiv1); + rt_do_div(frac_rate, postdiv1); + rate += frac_rate; + } + return rate; + case RKCLK_PLL_MODE_DEEP: + default: + return 32768; + } +} + +static const struct rk_cpu_rate_table *rk_get_cpu_settings(struct rk_cpu_rate_table *cpu_table, rt_ubase_t rate) +{ + struct rk_cpu_rate_table *ps = cpu_table; + + while (ps->rate) + { + if (ps->rate == rate) + { + break; + } + ++ps; + } + if (ps->rate != rate) + { + return RT_NULL; + } + else + { + return ps; + } +} + +static rt_base_t rk_clk_pll_round_rate(const struct rk_pll_rate_table *pll_rates, + rt_size_t rate_count, rt_ubase_t drate, rt_ubase_t *prate) +{ + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i < rate_count; i++) + { + if (drate >= pll_rates[i].rate) + { + return pll_rates[i].rate; + } + } + + /* return minimum supported value */ + return pll_rates[i - 1].rate; +} + +static void rk_clk_set_default_rates(struct rt_clk *clk, + rt_err_t (*clk_set_rate)(struct rt_clk *, rt_ubase_t, rt_ubase_t), int id) +{ + rt_uint32_t rate; + struct rt_ofw_cell_args clk_args; + struct rt_ofw_node *np = clk->fw_node; + const char *rate_propname = "assigned-clock-rates"; + + if (!rt_ofw_prop_read_bool(np, rate_propname)) + { + return; + } + + for (int i = 0; ; ++i) + { + if (rt_ofw_parse_phandle_cells(np, "assigned-clocks", "#clock-cells", i, &clk_args)) + { + break; + } + + rt_ofw_node_put(clk_args.data); + + if (clk_args.args[0] != id) + { + continue; + } + + if (!rt_ofw_prop_read_u32_index(np, rate_propname, i, &rate)) + { + clk_set_rate(clk, rate, 0); + } + + break; + } +} diff --git a/components/drivers/clk/rockchip/clk-rk3308.c b/components/drivers/clk/rockchip/clk-rk3308.c new file mode 100644 index 000000000000..5533188e93b1 --- /dev/null +++ b/components/drivers/clk/rockchip/clk-rk3308.c @@ -0,0 +1,2089 @@ +/* + * 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 "clk.h" + +#define DBG_TAG "clk.rk3308" +#define DBG_LVL DBG_INFO +#include + +#include + +#define APLL_HZ (816 * MHZ) + +#define CORE_ACLK_HZ 408000000 +#define CORE_DBG_HZ 204000000 + +#define BUS_ACLK_HZ 200000000 +#define BUS_HCLK_HZ 100000000 +#define BUS_PCLK_HZ 100000000 + +#define PERI_ACLK_HZ 200000000 +#define PERI_HCLK_HZ 100000000 +#define PERI_PCLK_HZ 100000000 + +#define AUDIO_HCLK_HZ 100000000 +#define AUDIO_PCLK_HZ 100000000 + +struct rk_pll +{ + rt_uint32_t con0; + rt_uint32_t con1; + rt_uint32_t con2; + rt_uint32_t con3; + rt_uint32_t con4; + rt_uint32_t reserved0[3]; +}; + +struct rk_cru +{ + struct rk_pll pll[4]; + rt_uint32_t reserved1[8]; + rt_uint32_t mode; + rt_uint32_t misc; + rt_uint32_t reserved2[2]; + rt_uint32_t glb_cnt_th; + rt_uint32_t glb_rst_st; + rt_uint32_t glb_srst_fst; + rt_uint32_t glb_srst_snd; + rt_uint32_t glb_rst_con; + rt_uint32_t pll_lock; + rt_uint32_t reserved3[6]; + rt_uint32_t hwffc_con0; + rt_uint32_t reserved4; + rt_uint32_t hwffc_th; + rt_uint32_t hwffc_intst; + rt_uint32_t apll_con0_s; + rt_uint32_t apll_con1_s; + rt_uint32_t clksel_con0_s; + rt_uint32_t reserved5; + rt_uint32_t clksel_con[74]; + rt_uint32_t reserved6[54]; + rt_uint32_t clkgate_con[15]; + rt_uint32_t reserved7[(0x380 - 0x338) / 4 - 1]; + rt_uint32_t ssgtbl[32]; + rt_uint32_t softrst_con[10]; + rt_uint32_t reserved8[(0x480 - 0x424) / 4 - 1]; + rt_uint32_t sdmmc_con[2]; + rt_uint32_t sdio_con[2]; + rt_uint32_t emmc_con[2]; +}; + +/* Private data for the clock driver - used by rk_get_cru() */ +struct rk_clk_priv +{ + struct rk_cru *cru; + rt_ubase_t armclk_hz; + rt_ubase_t dpll_hz; + rt_ubase_t vpll0_hz; + rt_ubase_t vpll1_hz; +}; + +struct rk_clk_platform_data +{ + rt_uint32_t id; + void *base; +}; + +struct rk_clk +{ + struct rt_reset_controller_clk_node parent; + + void *base; + struct rk_clk_priv clk_info; + struct rk_clk_platform_data pdata[CLK_NR_CLKS]; +}; + +#define raw_to_rk_clk(raw) rt_container_of(raw, struct rk_clk, parent) + +#define PLL_CON(x) ((x) * 0x4) +#define MODE_CON 0xa0 + +enum plls +{ + apll, dpll, vpll0, vpll1, +}; + +enum +{ + /* PLLCON0*/ + PLL_BP_SHIFT = 15, + PLL_POSTDIV1_SHIFT = 12, + PLL_POSTDIV1_MASK = 7 << PLL_POSTDIV1_SHIFT, + PLL_FBDIV_SHIFT = 0, + PLL_FBDIV_MASK = 0xfff, + + /* PLLCON1 */ + PLL_PDSEL_SHIFT = 15, + PLL_PD1_SHIFT = 14, + PLL_PD_SHIFT = 13, + PLL_PD_MASK = 1 << PLL_PD_SHIFT, + PLL_DSMPD_SHIFT = 12, + PLL_DSMPD_MASK = 1 << PLL_DSMPD_SHIFT, + PLL_LOCK_STATUS_SHIFT = 10, + PLL_LOCK_STATUS_MASK = 1 << PLL_LOCK_STATUS_SHIFT, + PLL_POSTDIV2_SHIFT = 6, + PLL_POSTDIV2_MASK = 7 << PLL_POSTDIV2_SHIFT, + PLL_REFDIV_SHIFT = 0, + PLL_REFDIV_MASK = 0x3f, + + /* PLLCON2 */ + PLL_FOUT4PHASEPD_SHIFT = 27, + PLL_FOUTVCOPD_SHIFT = 26, + PLL_FOUTPOSTDIVPD_SHIFT = 25, + PLL_DACPD_SHIFT = 24, + PLL_FRAC_DIV = 0xffffff, + + /* CRU_MODE */ + PLLMUX_FROM_XIN24M = 0, + PLLMUX_FROM_PLL, + PLLMUX_FROM_RTC32K, + USBPHY480M_MODE_SHIFT = 8, + USBPHY480M_MODE_MASK = 3 << USBPHY480M_MODE_SHIFT, + VPLL1_MODE_SHIFT = 6, + VPLL1_MODE_MASK = 3 << VPLL1_MODE_SHIFT, + VPLL0_MODE_SHIFT = 4, + VPLL0_MODE_MASK = 3 << VPLL0_MODE_SHIFT, + DPLL_MODE_SHIFT = 2, + DPLL_MODE_MASK = 3 << DPLL_MODE_SHIFT, + APLL_MODE_SHIFT = 0, + APLL_MODE_MASK = 3 << APLL_MODE_SHIFT, + + /* CRU_CLK_SEL0_CON */ + CORE_ACLK_DIV_SHIFT = 12, + CORE_ACLK_DIV_MASK = 0x7 << CORE_ACLK_DIV_SHIFT, + CORE_DBG_DIV_SHIFT = 8, + CORE_DBG_DIV_MASK = 0xf << CORE_DBG_DIV_SHIFT, + CORE_CLK_PLL_SEL_SHIFT = 6, + CORE_CLK_PLL_SEL_MASK = 0x3 << CORE_CLK_PLL_SEL_SHIFT, + CORE_CLK_PLL_SEL_APLL = 0, + CORE_CLK_PLL_SEL_VPLL0, + CORE_CLK_PLL_SEL_VPLL1, + CORE_DIV_CON_SHIFT = 0, + CORE_DIV_CON_MASK = 0x0f << CORE_DIV_CON_SHIFT, + + /* CRU_CLK_SEL5_CON */ + BUS_PLL_SEL_SHIFT = 6, + BUS_PLL_SEL_MASK = 0x3 << BUS_PLL_SEL_SHIFT, + BUS_PLL_SEL_DPLL = 0, + BUS_PLL_SEL_VPLL0, + BUS_PLL_SEL_VPLL1, + BUS_ACLK_DIV_SHIFT = 0, + BUS_ACLK_DIV_MASK = 0x1f << BUS_ACLK_DIV_SHIFT, + + /* CRU_CLK_SEL6_CON */ + BUS_PCLK_DIV_SHIFT = 8, + BUS_PCLK_DIV_MASK = 0x1f << BUS_PCLK_DIV_SHIFT, + BUS_HCLK_DIV_SHIFT = 0, + BUS_HCLK_DIV_MASK = 0x1f << BUS_HCLK_DIV_SHIFT, + + /* CRU_CLK_SEL7_CON */ + CRYPTO_APK_SEL_SHIFT = 14, + CRYPTO_APK_PLL_SEL_MASK = 3 << CRYPTO_APK_SEL_SHIFT, + CRYPTO_PLL_SEL_DPLL = 0, + CRYPTO_PLL_SEL_VPLL0, + CRYPTO_PLL_SEL_VPLL1 = 0, + CRYPTO_APK_DIV_SHIFT = 8, + CRYPTO_APK_DIV_MASK = 0x1f << CRYPTO_APK_DIV_SHIFT, + CRYPTO_PLL_SEL_SHIFT = 6, + CRYPTO_PLL_SEL_MASK = 3 << CRYPTO_PLL_SEL_SHIFT, + CRYPTO_DIV_SHIFT = 0, + CRYPTO_DIV_MASK = 0x1f << CRYPTO_DIV_SHIFT, + + /* CRU_CLK_SEL8_CON */ + DCLK_VOP_SEL_SHIFT = 14, + DCLK_VOP_SEL_MASK = 0x3 << DCLK_VOP_SEL_SHIFT, + DCLK_VOP_SEL_DIVOUT = 0, + DCLK_VOP_SEL_FRACOUT, + DCLK_VOP_SEL_24M, + DCLK_VOP_PLL_SEL_SHIFT = 10, + DCLK_VOP_PLL_SEL_MASK = 0x3 << DCLK_VOP_PLL_SEL_SHIFT, + DCLK_VOP_PLL_SEL_DPLL = 0, + DCLK_VOP_PLL_SEL_VPLL0, + DCLK_VOP_PLL_SEL_VPLL1, + DCLK_VOP_DIV_SHIFT = 0, + DCLK_VOP_DIV_MASK = 0xff, + + /* CRU_CLK_SEL10_CON */ + CLK_UART_SRC_SEL_SHIFT = 13, + CLK_UART_SRC_SEL_MASK = 0x7 << CLK_UART_SRC_SEL_SHIFT, + CLK_UART_SRC_SEL_DPLL = 0, + CLK_UART_SRC_SEL_VPLL0, + CLK_UART_SRC_SEL_VPLL1, + CLK_UART_SRC_SEL_480M, + CLK_UART_SRC_SEL_XIN_OSC0, + CLK_UART_SRC_DIV_SHIFT = 0, + CLK_UART_SRC_DIV_MASK = 0x3f << CLK_UART_SRC_DIV_SHIFT, + + /* CRU_CLK_SEL11_CON */ + CLK_UART_SEL_SHIFT = 14, + CLK_UART_SEL_MASK = 0x3 << CLK_UART_SEL_SHIFT, + CLK_UART_SEL_SRC = 0, + CLK_UART_SEL_NP5, + CLK_UART_SEL_FRAC_OUT, + CLK_UART_NP5_DIV_SHIFT = 0, + CLK_UART_NP5_DIV_MASK = 0x3f << CLK_UART_NP5_DIV_SHIFT, + + /* CRU_CLKSEL12_CON */ + CLK_UART_FRAC_NUMERATOR_SHIFT = 16, + CLK_UART_FRAC_NUMERATOR_MASK = 0xffff << 16, + CLK_UART_FRAC_DENOMINATOR_SHIFT = 0, + CLK_UART_FRAC_DENOMINATOR_MASK = 0xffff, + + /* CRU_CLK_SEL25_CON */ + /* CRU_CLK_SEL26_CON */ + /* CRU_CLK_SEL27_CON */ + /* CRU_CLK_SEL28_CON */ + CLK_I2C_PLL_SEL_SHIFT = 14, + CLK_I2C_PLL_SEL_MASK = 0x3 << CLK_I2C_PLL_SEL_SHIFT, + CLK_I2C_PLL_SEL_DPLL = 0, + CLK_I2C_PLL_SEL_VPLL0, + CLK_I2C_PLL_SEL_24M, + CLK_I2C_DIV_CON_SHIFT = 0, + CLK_I2C_DIV_CON_MASK = 0x7f << CLK_I2C_DIV_CON_SHIFT, + + /* CRU_CLK_SEL29_CON */ + CLK_PWM_PLL_SEL_SHIFT = 14, + CLK_PWM_PLL_SEL_MASK = 0x3 << CLK_PWM_PLL_SEL_SHIFT, + CLK_PWM_PLL_SEL_DPLL = 0, + CLK_PWM_PLL_SEL_VPLL0, + CLK_PWM_PLL_SEL_24M, + CLK_PWM_DIV_CON_SHIFT = 0, + CLK_PWM_DIV_CON_MASK = 0x7f << CLK_PWM_DIV_CON_SHIFT, + + /* CRU_CLK_SEL30_CON */ + /* CRU_CLK_SEL31_CON */ + /* CRU_CLK_SEL32_CON */ + CLK_SPI_PLL_SEL_SHIFT = 14, + CLK_SPI_PLL_SEL_MASK = 0x3 << CLK_SPI_PLL_SEL_SHIFT, + CLK_SPI_PLL_SEL_DPLL = 0, + CLK_SPI_PLL_SEL_VPLL0, + CLK_SPI_PLL_SEL_24M, + CLK_SPI_DIV_CON_SHIFT = 0, + CLK_SPI_DIV_CON_MASK = 0x7f << CLK_SPI_DIV_CON_SHIFT, + + /* CRU_CLK_SEL34_CON */ + CLK_SARADC_DIV_CON_SHIFT = 0, + CLK_SARADC_DIV_CON_MASK = 0x7ff << CLK_SARADC_DIV_CON_SHIFT, + + /* CRU_CLK_SEL36_CON */ + PERI_PLL_SEL_SHIFT = 6, + PERI_PLL_SEL_MASK = 0x3 << PERI_PLL_SEL_SHIFT, + PERI_PLL_DPLL = 0, + PERI_PLL_VPLL0, + PERI_PLL_VPLL1, + PERI_ACLK_DIV_SHIFT = 0, + PERI_ACLK_DIV_MASK = 0x1f << PERI_ACLK_DIV_SHIFT, + + /* CRU_CLK_SEL37_CON */ + PERI_PCLK_DIV_SHIFT = 8, + PERI_PCLK_DIV_MASK = 0x1f << PERI_PCLK_DIV_SHIFT, + PERI_HCLK_DIV_SHIFT = 0, + PERI_HCLK_DIV_MASK = 0x1f << PERI_HCLK_DIV_SHIFT, + + /* CRU_CLKSEL41_CON */ + EMMC_CLK_SEL_SHIFT = 15, + EMMC_CLK_SEL_MASK = 1 << EMMC_CLK_SEL_SHIFT, + EMMC_CLK_SEL_EMMC = 0, + EMMC_CLK_SEL_EMMC_DIV50, + EMMC_PLL_SHIFT = 8, + EMMC_PLL_MASK = 0x3 << EMMC_PLL_SHIFT, + EMMC_SEL_DPLL = 0, + EMMC_SEL_VPLL0, + EMMC_SEL_VPLL1, + EMMC_SEL_24M, + EMMC_DIV_SHIFT = 0, + EMMC_DIV_MASK = 0xff << EMMC_DIV_SHIFT, + + /* CRU_CLKSEL43_CON */ + MAC_CLK_SPEED_SEL_SHIFT = 15, + MAC_CLK_SPEED_SEL_MASK = 1 << MAC_CLK_SPEED_SEL_SHIFT, + MAC_CLK_SPEED_SEL_10M = 0, + MAC_CLK_SPEED_SEL_100M, + MAC_CLK_SOURCE_SEL_SHIFT = 14, + MAC_CLK_SOURCE_SEL_MASK = 1 << MAC_CLK_SOURCE_SEL_SHIFT, + MAC_CLK_SOURCE_SEL_INTERNAL = 0, + MAC_CLK_SOURCE_SEL_EXTERNAL, + MAC_PLL_SHIFT = 6, + MAC_PLL_MASK = 0x3 << MAC_PLL_SHIFT, + MAC_SEL_DPLL = 0, + MAC_SEL_VPLL0, + MAC_SEL_VPLL1, + MAC_DIV_SHIFT = 0, + MAC_DIV_MASK = 0x1f << MAC_DIV_SHIFT, + + /* CRU_CLK_SEL45_CON */ + AUDIO_PCLK_DIV_SHIFT = 8, + AUDIO_PCLK_DIV_MASK = 0x1f << AUDIO_PCLK_DIV_SHIFT, + AUDIO_PLL_SEL_SHIFT = 6, + AUDIO_PLL_SEL_MASK = 0x3 << AUDIO_PLL_SEL_SHIFT, + AUDIO_PLL_VPLL0 = 0, + AUDIO_PLL_VPLL1, + AUDIO_PLL_24M, + AUDIO_HCLK_DIV_SHIFT = 0, + AUDIO_HCLK_DIV_MASK = 0x1f << AUDIO_HCLK_DIV_SHIFT, +}; + +enum +{ + VCO_MAX_HZ = 3200U * 1000000, + VCO_MIN_HZ = 800 * 1000000, + OUTPUT_MAX_HZ = 3200U * 1000000, + OUTPUT_MIN_HZ = 24 * 1000000, +}; + +static struct rk_pll_rate_table pll_rates[] = +{ + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), + PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), + PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), + PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0), + PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0), + PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0), + PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0), + PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0), + PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0), + PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0), + PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0), + PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0), + PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), + PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), + PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), + PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), + PLL_RATE(984000000, 1, 82, 2, 1, 1, 0), + PLL_RATE(960000000, 1, 80, 2, 1, 1, 0), + PLL_RATE(936000000, 1, 78, 2, 1, 1, 0), + PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), + PLL_RATE(900000000, 4, 300, 2, 1, 1, 0), + PLL_RATE(888000000, 1, 74, 2, 1, 1, 0), + PLL_RATE(864000000, 1, 72, 2, 1, 1, 0), + PLL_RATE(840000000, 1, 70, 2, 1, 1, 0), + PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), + PLL_RATE(800000000, 6, 400, 2, 1, 1, 0), + PLL_RATE(700000000, 6, 350, 2, 1, 1, 0), + PLL_RATE(696000000, 1, 58, 2, 1, 1, 0), + PLL_RATE(624000000, 1, 52, 2, 1, 1, 0), + PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), + PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), + PLL_RATE(504000000, 1, 63, 3, 1, 1, 0), + PLL_RATE(500000000, 6, 250, 2, 1, 1, 0), + PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + PLL_RATE(312000000, 1, 52, 2, 2, 1, 0), + PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + PLL_RATE(96000000, 1, 64, 4, 4, 1, 0), +}; + +static struct rk_cpu_rate_table cpu_rates[] = +{ + CPUCLK_RATE(1608000000, 1, 7), + CPUCLK_RATE(1512000000, 1, 7), + CPUCLK_RATE(1488000000, 1, 5), + CPUCLK_RATE(1416000000, 1, 5), + CPUCLK_RATE(1392000000, 1, 5), + CPUCLK_RATE(1296000000, 1, 5), + CPUCLK_RATE(1200000000, 1, 5), + CPUCLK_RATE(1104000000, 1, 5), + CPUCLK_RATE(1008000000, 1, 5), + CPUCLK_RATE(912000000, 1, 5), + CPUCLK_RATE(816000000, 1, 3), + CPUCLK_RATE(696000000, 1, 3), + CPUCLK_RATE(600000000, 1, 3), + CPUCLK_RATE(408000000, 1, 1), + CPUCLK_RATE(312000000, 1, 1), + CPUCLK_RATE(216000000, 1, 1), + CPUCLK_RATE(96000000, 1, 1), +}; + +static struct rk_pll_clock pll_clks[] = +{ + [apll] = PLL(PLL_APLL, PLL_CON(0), MODE_CON, 0, 10, 0, pll_rates), + [dpll] = PLL(PLL_DPLL, PLL_CON(8), MODE_CON, 2, 10, 0, RT_NULL), + [vpll0] = PLL(PLL_VPLL0, PLL_CON(16), MODE_CON, 4, 10, 0, RT_NULL), + [vpll1] = PLL(PLL_VPLL1, PLL_CON(24), MODE_CON, 6, 10, 0, RT_NULL), +}; + +static struct rk_clk_gate clk_gates[] = +{ + GATE(SCLK_PVTM_CORE, "clk_pvtm_core", "xin24m", 0, 4), + GATE(ACLK_BUS_SRC, "clk_bus_src", RT_NULL, 1, 0), + GATE(PCLK_BUS, "pclk_bus", "clk_bus_src", 1, 3), + GATE(PCLK_DDR, "pclk_ddr", "pclk_bus", 4, 15), + GATE(HCLK_BUS, "hclk_bus", "clk_bus_src", 1, 2), + GATE(ACLK_BUS, "aclk_bus", "clk_bus_src", 1, 1), + GATE(SCLK_UART0, "clk_uart0", "clk_uart0_mux", 1, 12), + GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", 2, 0), + GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", 2, 4), + GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", 2, 8), + GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", 2, 12), + GATE(SCLK_I2C0, "clk_i2c0", RT_NULL, 2, 13), + GATE(SCLK_I2C1, "clk_i2c1", RT_NULL, 2, 14), + GATE(SCLK_I2C2, "clk_i2c2", RT_NULL, 2, 15), + GATE(SCLK_I2C3, "clk_i2c3", RT_NULL, 3, 0), + GATE(SCLK_PWM0, "clk_pwm0", RT_NULL, 3, 1), + GATE(SCLK_PWM1, "clk_pwm1", RT_NULL, 15, 0), + GATE(SCLK_PWM2, "clk_pwm2", RT_NULL, 15, 1), + GATE(SCLK_SPI0, "clk_spi0", RT_NULL, 3, 2), + GATE(SCLK_SPI1, "clk_spi1", RT_NULL, 3, 3), + GATE(SCLK_SPI2, "clk_spi2", RT_NULL, 3, 4), + GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 3, 10), + GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 3, 11), + GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 3, 12), + GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 3, 13), + GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 3, 14), + GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 3, 15), + GATE(SCLK_TSADC, "clk_tsadc", "xin24m", 3, 5), + GATE(SCLK_SARADC, "clk_saradc", "xin24m", 3, 6), + GATE(SCLK_OTP, "clk_otp", "xin24m", 3, 7), + GATE(SCLK_OTP_USR, "clk_otp_usr", "clk_otp", 3, 8), + GATE(SCLK_CPU_BOOST, "clk_cpu_boost", "xin24m", 3, 9), + GATE(SCLK_CRYPTO, "clk_crypto", RT_NULL, 1, 4), + GATE(SCLK_CRYPTO_APK, "clk_crypto_apk", RT_NULL, 1, 5), + GATE(DCLK_VOP, "dclk_vop", "dclk_vop_mux", 1, 8), + GATE(ACLK_PERI_SRC, "clk_peri_src", RT_NULL, 8, 0), + GATE(ACLK_PERI, "aclk_peri", "clk_peri_src", 8, 1), + GATE(HCLK_PERI, "hclk_peri", "clk_peri_src", 8, 2), + GATE(PCLK_PERI, "pclk_peri", "clk_peri_src", 8, 3), + GATE(SCLK_NANDC_DIV, "clk_nandc_div", RT_NULL, 8, 4), + GATE(SCLK_NANDC_DIV50, "clk_nandc_div50", RT_NULL, 8, 4), + GATE(SCLK_NANDC, "clk_nandc", RT_NULL, 8, 5), + GATE(SCLK_SDMMC_DIV, "clk_sdmmc_div", RT_NULL, 8, 6), + GATE(SCLK_SDMMC_DIV50, "clk_sdmmc_div50", RT_NULL, 8, 6), + GATE(SCLK_SDMMC, "clk_sdmmc", RT_NULL, 8, 7), + GATE(SCLK_SDIO_DIV, "clk_sdio_div", RT_NULL, 8, 8), + GATE(SCLK_SDIO_DIV50, "clk_sdio_div50", RT_NULL, 8, 8), + GATE(SCLK_SDIO, "clk_sdio", RT_NULL, 8, 9), + GATE(SCLK_EMMC_DIV, "clk_emmc_div", RT_NULL, 8, 10), + GATE(SCLK_EMMC_DIV50, "clk_emmc_div50", RT_NULL, 8, 10), + GATE(SCLK_EMMC, "clk_emmc", RT_NULL, 8, 11), + GATE(SCLK_SFC, "clk_sfc", RT_NULL, 8, 12), + GATE(SCLK_OTG_ADP, "clk_otg_adp", "clk_rtc32k", 8, 13), + GATE(SCLK_MAC_SRC, "clk_mac_src", RT_NULL, 8, 14), + GATE(SCLK_MAC_REF, "clk_mac_ref", "clk_mac", 9, 1), + GATE(SCLK_MAC_RX_TX, "clk_mac_rx_tx", "clk_mac", 9, 0), + GATE(SCLK_OWIRE, "clk_owire", RT_NULL, 8, 15), + GATE(SCLK_DDRCLK, "clk_ddrphy4x_src", RT_NULL, 0, 10), + GATE(PCLK_PMU, "pclk_pmu", "pclk_bus", 4, 5), + GATE(SCLK_PMU, "clk_pmu", "pclk_bus", 4, 6), + GATE(SCLK_USBPHY_REF, "clk_usbphy_ref", RT_NULL, 4, 8), + GATE(SCLK_WIFI, "clk_wifi", RT_NULL, 4, 1), + GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", 4, 4), + GATE(HCLK_AUDIO, "hclk_audio", "clk_audio_src", 10, 1), + GATE(PCLK_AUDIO, "pclk_audio", "clk_audio_src", 10, 2), + GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", 10, 5), + GATE(SCLK_I2S0_8CH_TX_SRC, "clk_i2s0_8ch_tx_src", RT_NULL, 10, 12), + GATE(SCLK_I2S0_8CH_TX, "clk_i2s0_8ch_tx", RT_NULL, 10, 14), + GATE(SCLK_I2S0_8CH_TX_OUT, "clk_i2s0_8ch_tx_out", RT_NULL, 10, 15), + GATE(SCLK_I2S0_8CH_RX_SRC, "clk_i2s0_8ch_rx_src", RT_NULL, 11, 0), + GATE(SCLK_I2S0_8CH_RX, "clk_i2s0_8ch_rx", RT_NULL, 11, 2), + GATE(SCLK_I2S0_8CH_RX_OUT, "clk_i2s0_8ch_rx_out", "clk_i2s0_8ch_rx", 11, 3), + GATE(SCLK_I2S1_8CH_TX_SRC, "clk_i2s1_8ch_tx_src", RT_NULL, 11, 4), + GATE(SCLK_I2S1_8CH_TX, "clk_i2s1_8ch_tx", RT_NULL, 11, 6), + GATE(SCLK_I2S1_8CH_TX_OUT, "clk_i2s1_8ch_tx_out", RT_NULL, 11, 7), + GATE(SCLK_I2S1_8CH_RX_SRC, "clk_i2s1_8ch_rx_src", RT_NULL, 11, 8), + GATE(SCLK_I2S1_8CH_RX, "clk_i2s1_8ch_rx", RT_NULL, 11, 10), + GATE(SCLK_I2S1_8CH_RX_OUT, "clk_i2s1_8ch_rx_out", "clk_i2s1_8ch_rx", 11, 11), + GATE(SCLK_I2S2_8CH_TX_SRC, "clk_i2s2_8ch_tx_src", RT_NULL, 11, 12), + GATE(SCLK_I2S2_8CH_TX, "clk_i2s2_8ch_tx", RT_NULL, 11, 14), + GATE(SCLK_I2S2_8CH_TX_OUT, "clk_i2s2_8ch_tx_out", RT_NULL, 11, 15), + GATE(SCLK_I2S2_8CH_RX_SRC, "clk_i2s2_8ch_rx_src", RT_NULL, 12, 0), + GATE(SCLK_I2S2_8CH_RX, "clk_i2s2_8ch_rx", RT_NULL, 12, 2), + GATE(SCLK_I2S2_8CH_RX_OUT, "clk_i2s2_8ch_rx_out", "clk_i2s2_8ch_rx", 12, 3), + GATE(SCLK_I2S3_8CH_TX_SRC, "clk_i2s3_8ch_tx_src", RT_NULL, 12, 4), + GATE(SCLK_I2S3_8CH_TX, "clk_i2s3_8ch_tx", RT_NULL, 12, 6), + GATE(SCLK_I2S3_8CH_TX_OUT, "clk_i2s3_8ch_tx_out", RT_NULL, 12, 7), + GATE(SCLK_I2S3_8CH_RX_SRC, "clk_i2s3_8ch_rx_src", RT_NULL, 12, 8), + GATE(SCLK_I2S3_8CH_RX, "clk_i2s3_8ch_rx", RT_NULL, 12, 10), + GATE(SCLK_I2S3_8CH_RX_OUT, "clk_i2s3_8ch_rx_out", "clk_i2s3_8ch_rx", 12, 11), + GATE(SCLK_I2S0_2CH_SRC, "clk_i2s0_2ch_src", RT_NULL, 12, 12), + GATE(SCLK_I2S0_2CH, "clk_i2s0_2ch", "clk_i2s0_2ch_mux", 12, 14), + GATE(SCLK_I2S0_2CH_OUT, "clk_i2s0_2ch_out", RT_NULL, 12, 15), + GATE(SCLK_I2S1_2CH_SRC, "clk_i2s1_2ch_src", RT_NULL, 13, 0), + GATE(SCLK_I2S1_2CH, "clk_i2s1_2ch", "clk_i2s1_2ch_mux", 13, 2), + GATE(SCLK_I2S1_2CH_OUT, "clk_i2s1_2ch_out", RT_NULL, 13, 3), + GATE(SCLK_SPDIF_TX_DIV, "clk_spdif_tx_div", RT_NULL, 10, 6), + GATE(SCLK_SPDIF_TX_DIV50, "clk_spdif_tx_div50", RT_NULL, 10, 6), + GATE(SCLK_SPDIF_TX, "clk_spdif_tx", "clk_spdif_tx_mux", 10, 8), + GATE(SCLK_SPDIF_RX_DIV, "clk_spdif_rx_div", RT_NULL, 10, 9), + GATE(SCLK_SPDIF_RX_DIV50, "clk_spdif_rx_div50", RT_NULL, 10, 9), + GATE(SCLK_SPDIF_RX, "clk_spdif_rx", "clk_spdif_rx_mux", 10, 11), + GATE(ACLK_MAC, "aclk_mac", "aclk_peri", 9, 4), + GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 9, 6), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 9, 7), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 9, 8), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 9, 9), + GATE(HCLK_SFC, "hclk_sfc", "hclk_peri", 9, 10), + GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 9, 11), + GATE(HCLK_HOST, "hclk_host", "hclk_peri", 9, 12), + GATE(HCLK_HOST_ARB, "hclk_host_arb", "hclk_peri", 9, 13), + GATE(PCLK_MAC, "pclk_mac", "pclk_peri", 9, 15), + GATE(HCLK_PDM, "hclk_pdm", "hclk_audio", 14, 1), + GATE(HCLK_SPDIFTX, "hclk_spdiftx", "hclk_audio", 14, 2), + GATE(HCLK_SPDIFRX, "hclk_spdifrx", "hclk_audio", 14, 3), + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_audio", 14, 4), + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_audio", 14, 5), + GATE(HCLK_I2S2_8CH, "hclk_i2s2_8ch", "hclk_audio", 14, 6), + GATE(HCLK_I2S3_8CH, "hclk_i2s3_8ch", "hclk_audio", 14, 7), + GATE(HCLK_I2S0_2CH, "hclk_i2s0_2ch", "hclk_audio", 14, 8), + GATE(HCLK_I2S1_2CH, "hclk_i2s1_2ch", "hclk_audio", 14, 9), + GATE(HCLK_VAD, "hclk_vad", "hclk_audio", 14, 10), + GATE(PCLK_ACODEC, "pclk_acodec", "pclk_audio", 14, 12), + GATE(ACLK_CRYPTO, "aclk_crypto", "aclk_bus", 5, 2), + GATE(ACLK_VOP, "aclk_vop", "aclk_bus", 5, 3), + GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_bus", 5, 7), + GATE(HCLK_VOP, "hclk_vop", "hclk_bus", 5, 8), + GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 5, 10), + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 5, 11), + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 5, 12), + GATE(PCLK_UART3, "pclk_uart3", "pclk_bus", 5, 13), + GATE(PCLK_UART4, "pclk_uart4", "pclk_bus", 5, 14), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 5, 15), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 6, 0), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 6, 1), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 6, 2), + GATE(PCLK_PWM0, "pclk_pwm0", "pclk_bus", 6, 3), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_bus", 6, 4), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_bus", 6, 5), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_bus", 6, 6), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 6, 7), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 6, 8), + GATE(PCLK_TIMER, "pclk_timer", "pclk_bus", 6, 9), + GATE(PCLK_OTP_NS, "pclk_otp_ns", "pclk_bus", 6, 10), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 6, 12), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 6, 13), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 6, 14), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 6, 15), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_bus", 7, 0), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_bus", 7, 1), + GATE(PCLK_GRF, "pclk_grf", "pclk_bus", 7, 2), + GATE(PCLK_USBSD_DET, "pclk_usbsd_det", "pclk_bus", 7, 3), + GATE(PCLK_DDR_UPCTL, "pclk_ddr_upctl", "pclk_bus", 7, 4), + GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_bus", 7, 5), + GATE(PCLK_DDRPHY, "pclk_ddrphy", "pclk_bus", 7, 6), + GATE(PCLK_DDR_STDBY, "pclk_ddr_stdby", "pclk_bus", 7, 7), + GATE(PCLK_USB_GRF, "pclk_usb_grf", "pclk_bus", 7, 8), + GATE(PCLK_CRU, "pclk_cru", "pclk_bus", 7, 9), + GATE(PCLK_OTP_PHY, "pclk_otp_phy", "pclk_bus", 7, 10), + GATE(PCLK_CPU_BOOST, "pclk_cpu_boost", "pclk_bus", 7, 11), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 7, 12), + GATE(PCLK_PWM2, "pclk_pwm2", "pclk_bus", 7, 13), + GATE(PCLK_CAN, "pclk_can", "pclk_bus", 7, 14), + GATE(PCLK_OWIRE, "pclk_owire", "pclk_bus", 7, 15), +}; + +#define PLL_MODE_MASK 0x1 +#include "clk-pll.c" +#include "softrst.c" + +static rt_base_t armclk_set_clk(struct rk_clk_priv *priv, rt_ubase_t hz) +{ + struct rk_cru *cru = priv->cru; + const struct rk_cpu_rate_table *rate; + rt_ubase_t old_rate; + + rate = rk_get_cpu_settings(cpu_rates, hz); + if (!rate) + { + LOG_E("Unsupport rate %u", hz); + + return -RT_ENOSYS; + } + + /* + * select apll as cpu/core clock pll source and + * set up dependent divisors for PERI and ACLK clocks. + * core hz : apll = 1:1 + */ + old_rate = rk_pll_get_rate(&pll_clks[apll], priv->cru); + if (old_rate > hz) + { + if (rk_pll_set_rate(&pll_clks[apll], priv->cru, hz)) + { + return -RT_EINVAL; + } + + rk_clrsetreg(&cru->clksel_con[0], + CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | + CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, + rate->aclk_div << CORE_ACLK_DIV_SHIFT | + rate->pclk_div << CORE_DBG_DIV_SHIFT | + CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | + 0 << CORE_DIV_CON_SHIFT); + } + else if (old_rate < hz) + { + rk_clrsetreg(&cru->clksel_con[0], + CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | + CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, + rate->aclk_div << CORE_ACLK_DIV_SHIFT | + rate->pclk_div << CORE_DBG_DIV_SHIFT | + CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | + 0 << CORE_DIV_CON_SHIFT); + + if (rk_pll_set_rate(&pll_clks[apll], priv->cru, hz)) + { + return -RT_EINVAL; + } + } + + return rk_pll_get_rate(&pll_clks[apll], priv->cru); +} + +static void clk_get_pll_rate(struct rk_clk_priv *priv) +{ + if (!priv->dpll_hz) + { + priv->dpll_hz = rk_pll_get_rate(&pll_clks[dpll], priv->cru); + } + + if (!priv->vpll0_hz) + { + priv->vpll0_hz = rk_pll_get_rate(&pll_clks[vpll0], priv->cru); + } + + if (!priv->vpll1_hz) + { + priv->vpll1_hz = rk_pll_get_rate(&pll_clks[vpll1], priv->cru); + } +} + +static rt_base_t i2c_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, con_id; + + switch (clk_id) + { + case SCLK_I2C0: + con_id = 25; + break; + case SCLK_I2C1: + con_id = 26; + break; + case SCLK_I2C2: + con_id = 27; + break; + case SCLK_I2C3: + con_id = 28; + break; + default: + return -RT_EINVAL; + } + + con = HWREG32(&cru->clksel_con[con_id]); + div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; + + return DIV_TO_RATE(priv->dpll_hz, div); +} + +static rt_base_t i2c_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t src_clk_div, con_id; + + src_clk_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 127); + + switch (clk_id) + { + case SCLK_I2C0: + con_id = 25; + break; + case SCLK_I2C1: + con_id = 26; + break; + case SCLK_I2C2: + con_id = 27; + break; + case SCLK_I2C3: + con_id = 28; + break; + default: + return -RT_EINVAL; + } + + rk_clrsetreg(&cru->clksel_con[con_id], + CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK, + CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT | + (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT); + + return i2c_get_clk(priv, clk_id); +} + +static rt_base_t mac_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con = HWREG32(&cru->clksel_con[43]); + rt_ubase_t pll_rate; + rt_uint8_t div; + + if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0) + { + pll_rate = rk_pll_get_rate(&pll_clks[vpll0], priv->cru); + } + else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1) + { + pll_rate = rk_pll_get_rate(&pll_clks[vpll1], priv->cru); + } + else + { + pll_rate = rk_pll_get_rate(&pll_clks[dpll], priv->cru); + } + + /* default set 50MHZ for gmac */ + if (!rate) + { + rate = 50000000; + } + + div = RT_DIV_ROUND_UP(pll_rate, rate) - 1; + RT_ASSERT(div < 32); + + rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK, div << MAC_DIV_SHIFT); + + return DIV_TO_RATE(pll_rate, div); +} + +static rt_base_t mac_set_speed_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + + if (rate != 2500000 && rate != 25000000) + { + LOG_E("Unsupported mac speed: %u", rate); + + return -RT_EINVAL; + } + + rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK, + ((rate == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT); + + return 0; +} + +static rt_base_t mmc_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, con_id; + + switch (clk_id) + { + case HCLK_SDMMC: + case SCLK_SDMMC: + con_id = 39; + break; + case HCLK_EMMC: + case SCLK_EMMC: + case SCLK_EMMC_SAMPLE: + con_id = 41; + break; + default: + return -RT_EINVAL; + } + + con = HWREG32(&cru->clksel_con[con_id]); + div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; + + if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT == EMMC_SEL_24M) + { + return DIV_TO_RATE(OSC_HZ, div) / 2; + } + else + { + return DIV_TO_RATE(priv->vpll0_hz, div) / 2; + } +} + +static rt_base_t mmc_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + rt_uint32_t con_id; + + switch (clk_id) + { + case HCLK_SDMMC: + case SCLK_SDMMC: + con_id = 39; + break; + case HCLK_EMMC: + case SCLK_EMMC: + con_id = 41; + break; + default: + return -RT_EINVAL; + } + /* Select clk_sdmmc/emmc source from VPLL0 by default */ + /* mmc clock defaulg div 2 internal, need provide double in cru */ + src_clk_div = RT_DIV_ROUND_UP(priv->vpll0_hz / 2, rate); + + if (src_clk_div > 127) + { + /* use 24MHz source for 400KHz clock */ + src_clk_div = RT_DIV_ROUND_UP(OSC_HZ / 2, rate); + rk_clrsetreg(&cru->clksel_con[con_id], + EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK, + EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT | + EMMC_SEL_24M << EMMC_PLL_SHIFT | + (src_clk_div - 1) << EMMC_DIV_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[con_id], + EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK, + EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT | + EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT | + (src_clk_div - 1) << EMMC_DIV_SHIFT); + } + + return mmc_get_clk(priv, clk_id); +} + +static rt_base_t saradc_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con; + + con = HWREG32(&cru->clksel_con[34]); + div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK; + + return DIV_TO_RATE(OSC_HZ, div); +} + +static rt_base_t saradc_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(OSC_HZ, rate); + RT_ASSERT(src_clk_div - 1 <= 2047); + + rk_clrsetreg(&cru->clksel_con[34], CLK_SARADC_DIV_CON_MASK, + (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); + + return saradc_get_clk(priv, clk_id); +} + +static rt_base_t tsadc_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con; + + con = HWREG32(&cru->clksel_con[33]); + div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK; + + return DIV_TO_RATE(OSC_HZ, div); +} + +static rt_base_t tsadc_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(OSC_HZ, rate); + RT_ASSERT(src_clk_div - 1 <= 2047); + + rk_clrsetreg(&cru->clksel_con[33], CLK_SARADC_DIV_CON_MASK, + (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); + + return tsadc_get_clk(priv, clk_id); +} + +static rt_base_t spi_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, con_id; + + switch (clk_id) + { + case SCLK_SPI0: + con_id = 30; + break; + case SCLK_SPI1: + con_id = 31; + break; + case SCLK_SPI2: + con_id = 32; + break; + default: + return -RT_EINVAL; + } + + con = HWREG32(&cru->clksel_con[con_id]); + div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK; + + return DIV_TO_RATE(priv->dpll_hz, div); +} + +static rt_base_t spi_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t src_clk_div, con_id; + + src_clk_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 127); + + switch (clk_id) + { + case SCLK_SPI0: + con_id = 30; + break; + case SCLK_SPI1: + con_id = 31; + break; + case SCLK_SPI2: + con_id = 32; + break; + default: + return -RT_EINVAL; + } + + rk_clrsetreg(&cru->clksel_con[con_id], + CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK, + CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT | + (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT); + + return spi_get_clk(priv, clk_id); +} + +static rt_base_t pwm_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con; + + con = HWREG32(&cru->clksel_con[29]); + div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK; + + return DIV_TO_RATE(priv->dpll_hz, div); +} + +static rt_base_t pwm_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 127); + + rk_clrsetreg(&cru->clksel_con[29], + CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK, + CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT | + (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT); + + return pwm_get_clk(priv, clk_id); +} + +static rt_base_t vop_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, pll_sel, vol_sel, con, parent; + + con = HWREG32(&cru->clksel_con[8]); + vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT; + pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT; + div = con & DCLK_VOP_DIV_MASK; + + if (vol_sel == DCLK_VOP_SEL_24M) + { + parent = OSC_HZ; + } + else if (vol_sel == DCLK_VOP_SEL_DIVOUT) + { + switch (pll_sel) + { + case DCLK_VOP_PLL_SEL_DPLL: + parent = priv->dpll_hz; + break; + case DCLK_VOP_PLL_SEL_VPLL0: + parent = priv->vpll0_hz; + break; + case DCLK_VOP_PLL_SEL_VPLL1: + parent = priv->vpll0_hz; + break; + default: + return -RT_EINVAL; + } + } else { + return -RT_EINVAL; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_base_t vop_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_ubase_t pll_rate, now, best_rate = 0; + rt_uint32_t div, best_div = 0, best_sel = 0; + + for (int i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) + { + switch (i) + { + case DCLK_VOP_PLL_SEL_DPLL: + pll_rate = priv->dpll_hz; + break; + case DCLK_VOP_PLL_SEL_VPLL0: + pll_rate = priv->vpll0_hz; + break; + case DCLK_VOP_PLL_SEL_VPLL1: + pll_rate = priv->vpll1_hz; + break; + default: + return -RT_EINVAL; + } + + div = RT_DIV_ROUND_UP(pll_rate, rate); + + if (div > 255) + { + continue; + } + now = pll_rate / div; + + if (rt_abs(rate - now) < rt_abs(rate - best_rate)) + { + best_rate = now; + best_div = div; + best_sel = i; + } + } + + if (best_rate != rate && rate == OSC_HZ) + { + rk_clrsetreg(&cru->clksel_con[8], + DCLK_VOP_SEL_MASK, + DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT); + } + else if (best_rate) + { + rk_clrsetreg(&cru->clksel_con[8], + DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK | + DCLK_VOP_DIV_MASK, + DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT | + best_sel << DCLK_VOP_PLL_SEL_SHIFT | + (best_div - 1) << DCLK_VOP_DIV_SHIFT); + } + else + { + return -RT_EINVAL; + } + + return vop_get_clk(priv, clk_id); +} + +static rt_base_t bus_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, parent = priv->dpll_hz; + + switch (clk_id) + { + case ACLK_BUS: + con = HWREG32(&cru->clksel_con[5]); + div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; + break; + case HCLK_BUS: + con = HWREG32(&cru->clksel_con[6]); + div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; + break; + case PCLK_BUS: + case PCLK_WDT: + con = HWREG32(&cru->clksel_con[6]); + div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; + break; + default: + return -RT_EINVAL; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_base_t bus_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + + /* + * select dpll as pd_bus bus clock source and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + switch (clk_id) + { + case ACLK_BUS: + rk_clrsetreg(&cru->clksel_con[5], BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, + BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT | + (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); + break; + case HCLK_BUS: + rk_clrsetreg(&cru->clksel_con[6], BUS_HCLK_DIV_MASK, + (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); + break; + case PCLK_BUS: + rk_clrsetreg(&cru->clksel_con[6], BUS_PCLK_DIV_MASK, + (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); + break; + default: + return -RT_EINVAL; + } + + return bus_get_clk(priv, clk_id); +} + +static rt_base_t peri_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, parent = priv->dpll_hz; + + switch (clk_id) + { + case ACLK_PERI: + con = HWREG32(&cru->clksel_con[36]); + div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; + break; + case HCLK_PERI: + con = HWREG32(&cru->clksel_con[37]); + div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; + break; + case PCLK_PERI: + con = HWREG32(&cru->clksel_con[37]); + div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT; + break; + default: + return -RT_EINVAL; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_base_t peri_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + + /* + * select dpll as pd_peri bus clock source and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + switch (clk_id) + { + case ACLK_PERI: + rk_clrsetreg(&cru->clksel_con[36], PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, + PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT | + (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); + break; + case HCLK_PERI: + rk_clrsetreg(&cru->clksel_con[37], PERI_HCLK_DIV_MASK, + (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); + break; + case PCLK_PERI: + rk_clrsetreg(&cru->clksel_con[37], PERI_PCLK_DIV_MASK, + (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT); + break; + default: + return -RT_EINVAL; + } + + return peri_get_clk(priv, clk_id); +} + +static rt_base_t audio_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, parent = priv->vpll0_hz; + + switch (clk_id) + { + case HCLK_AUDIO: + con = HWREG32(&cru->clksel_con[45]); + div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT; + break; + case PCLK_AUDIO: + con = HWREG32(&cru->clksel_con[45]); + div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT; + break; + default: + return -RT_EINVAL; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_base_t audio_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->vpll0_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + + /* + * select vpll0 as audio bus clock source and + * set up dependent divisors for HCLK and PCLK clocks. + */ + switch (clk_id) + { + case HCLK_AUDIO: + rk_clrsetreg(&cru->clksel_con[45], AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK, + AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT | + (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT); + break; + case PCLK_AUDIO: + rk_clrsetreg(&cru->clksel_con[45], AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK, + AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT | + (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT); + break; + default: + return -RT_EINVAL; + } + + return peri_get_clk(priv, clk_id); +} + +static rt_base_t crypto_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, con, parent; + + switch (clk_id) + { + case SCLK_CRYPTO: + con = HWREG32(&cru->clksel_con[7]); + div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT; + parent = priv->vpll0_hz; + break; + case SCLK_CRYPTO_APK: + con = HWREG32(&cru->clksel_con[7]); + div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT; + parent = priv->vpll0_hz; + break; + default: + return -RT_EINVAL; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_base_t crypto_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->vpll0_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + + /* + * select gpll as crypto clock source and + * set up dependent divisors for crypto clocks. + */ + switch (clk_id) + { + case SCLK_CRYPTO: + rk_clrsetreg(&cru->clksel_con[7], CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK, + CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT | + (src_clk_div - 1) << CRYPTO_DIV_SHIFT); + break; + case SCLK_CRYPTO_APK: + rk_clrsetreg(&cru->clksel_con[7], CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK, + CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT | + (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT); + break; + default: + return -RT_EINVAL; + } + + return crypto_get_clk(priv, clk_id); +} + +static rt_ubase_t uart_get_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t reg, con, fracdiv, div, src, p_src, p_rate; + rt_ubase_t m, n; + + switch (clk_id) + { + case SCLK_UART0: + reg = 10; + break; + case SCLK_UART1: + reg = 13; + break; + case SCLK_UART2: + reg = 16; + break; + case SCLK_UART3: + reg = 19; + break; + case SCLK_UART4: + reg = 22; + break; + default: + return -RT_ERROR; + } + + con = HWREG32(&cru->clksel_con[reg]); + p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT; + div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT; + + if (p_src == CLK_UART_SRC_SEL_DPLL) + { + p_rate = priv->dpll_hz; + } + else if (p_src == CLK_UART_SRC_SEL_VPLL0) + { + p_rate = priv->vpll0_hz; + } + else if (p_src == CLK_UART_SRC_SEL_VPLL1) + { + p_rate = priv->vpll1_hz; + } + else if (p_src == CLK_UART_SRC_SEL_480M) + { + p_rate = 480000000; + } + else + { + p_rate = OSC_HZ; + } + + con = HWREG32(&cru->clksel_con[reg + 1]); + src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT; + + if (src == CLK_UART_SEL_SRC) + { + return DIV_TO_RATE(p_rate, div); + } + else if (src == CLK_UART_SEL_NP5) + { + div = (con & CLK_UART_NP5_DIV_MASK) >> CLK_UART_NP5_DIV_SHIFT; + return DIV_TO_RATE(p_rate, div); + } + else if (src == CLK_UART_SEL_FRAC_OUT) + { + fracdiv = HWREG32(&cru->clksel_con[reg + 2]); + n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK; + n >>= CLK_UART_FRAC_NUMERATOR_SHIFT; + m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK; + m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT; + return DIV_TO_RATE(p_rate, div) * n / m; + } + else + { + return OSC_HZ; + } +} + +static rt_ubase_t uart_set_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t reg, clk_src, uart_src, src_div, np5_div; + rt_ubase_t m = 0, n = 0, val; + + if (priv->dpll_hz % rate == 0) + { + clk_src = CLK_UART_SRC_SEL_DPLL; + uart_src = CLK_UART_SEL_SRC; + src_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + np5_div = 2; + } + else if (priv->vpll0_hz % rate == 0) + { + clk_src = CLK_UART_SRC_SEL_VPLL0; + uart_src = CLK_UART_SEL_SRC; + src_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + np5_div = 2; + } + else if (priv->vpll1_hz % rate == 0) + { + clk_src = CLK_UART_SRC_SEL_VPLL1; + uart_src = CLK_UART_SEL_SRC; + src_div = RT_DIV_ROUND_UP(priv->dpll_hz, rate); + np5_div = 2; + } + else if (rate == OSC_HZ) + { + clk_src = CLK_UART_SRC_SEL_DPLL; + uart_src = CLK_UART_SRC_SEL_XIN_OSC0; + np5_div = 2; + src_div = 2; + } + else + { + clk_src = CLK_UART_SRC_SEL_DPLL; + uart_src = CLK_UART_SEL_FRAC_OUT; + src_div = 2; + np5_div = 2; + rational_best_approximation(rate, priv->dpll_hz / src_div, RT_GENMASK(16 - 1, 0), RT_GENMASK(16 - 1, 0), &m, &n); + } + + switch (clk_id) + { + case SCLK_UART0: + reg = 10; + break; + case SCLK_UART1: + reg = 13; + break; + case SCLK_UART2: + reg = 16; + break; + case SCLK_UART3: + reg = 19; + break; + case SCLK_UART4: + reg = 22; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[reg], CLK_UART_SRC_SEL_MASK | CLK_UART_SRC_DIV_MASK, + (clk_src << CLK_UART_SRC_SEL_SHIFT) | ((src_div - 1) << CLK_UART_SRC_DIV_SHIFT)); + rk_clrsetreg(&cru->clksel_con[reg + 1], CLK_UART_SEL_MASK | CLK_UART_NP5_DIV_MASK, + (uart_src << CLK_UART_SEL_SHIFT) | ((np5_div - 1) << CLK_UART_NP5_DIV_SHIFT)); + + if (m && n) + { + val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; + HWREG32(&cru->clksel_con[reg + 2]) = val; + } + + return uart_get_rate(priv, clk_id); +} + +static rt_base_t rk_clk_get_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + rt_ubase_t rate = 0; + + switch (pdata->id) + { + case PLL_APLL: + case ARMCLK: + rate = rk_pll_get_rate(&pll_clks[apll], priv->cru); + break; + case PLL_DPLL: + rate = rk_pll_get_rate(&pll_clks[dpll], priv->cru); + break; + case PLL_VPLL0: + rate = rk_pll_get_rate(&pll_clks[vpll0], priv->cru); + break; + case PLL_VPLL1: + rate = rk_pll_get_rate(&pll_clks[vpll1], priv->cru); + break; + case HCLK_SDMMC: + case HCLK_EMMC: + case SCLK_SDMMC: + case SCLK_EMMC: + case SCLK_EMMC_SAMPLE: + rate = mmc_get_clk(priv, pdata->id); + break; + case SCLK_I2C0: + case SCLK_I2C1: + case SCLK_I2C2: + case SCLK_I2C3: + rate = i2c_get_clk(priv, pdata->id); + break; + case SCLK_SARADC: + rate = saradc_get_clk(priv, pdata->id); + break; + case SCLK_TSADC: + rate = tsadc_get_clk(priv, pdata->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + rate = spi_get_clk(priv, pdata->id); + break; + case SCLK_PWM0: + rate = pwm_get_clk(priv, pdata->id); + break; + case DCLK_VOP: + rate = vop_get_clk(priv, pdata->id); + break; + case ACLK_BUS: + case HCLK_BUS: + case PCLK_BUS: + case PCLK_WDT: + rate = bus_get_clk(priv, pdata->id); + break; + case ACLK_PERI: + case HCLK_PERI: + case PCLK_PERI: + rate = peri_get_clk(priv, pdata->id); + break; + case HCLK_AUDIO: + case PCLK_AUDIO: + rate = audio_get_clk(priv, pdata->id); + break; + case SCLK_CRYPTO: + case SCLK_CRYPTO_APK: + rate = crypto_get_clk(priv, pdata->id); + break; + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + rate = uart_get_rate(priv, pdata->id); + break; + case SCLK_TIMER0: + case SCLK_TIMER1: + case SCLK_TIMER2: + case SCLK_TIMER3: + case SCLK_TIMER4: + case SCLK_TIMER5: + rate = OSC_HZ; + break; + default: + return -RT_EINVAL; + } + + return rate; +} + +static rt_base_t rk_clk_set_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk, rt_ubase_t rate) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + rt_ubase_t res = 0; + + switch (pdata->id) + { + case PLL_DPLL: + res = rk_pll_set_rate(&pll_clks[dpll], priv->cru, rate); + priv->dpll_hz = rk_pll_get_rate(&pll_clks[dpll], priv->cru); + break; + case ARMCLK: + if (priv->armclk_hz) + { + armclk_set_clk(priv, rate); + } + priv->armclk_hz = rate; + break; + case HCLK_SDMMC: + case HCLK_EMMC: + case SCLK_SDMMC: + case SCLK_EMMC: + res = mmc_set_clk(priv, pdata->id, rate); + break; + case SCLK_I2C0: + case SCLK_I2C1: + case SCLK_I2C2: + case SCLK_I2C3: + res = i2c_set_clk(priv, pdata->id, rate); + break; + case SCLK_MAC: + res = mac_set_clk(priv, pdata->id, rate); + break; + case SCLK_MAC_RMII: + res = mac_set_speed_clk(priv, pdata->id, rate); + break; + case SCLK_SARADC: + res = saradc_set_clk(priv, pdata->id, rate); + break; + case SCLK_TSADC: + res = tsadc_set_clk(priv, pdata->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + res = spi_set_clk(priv, pdata->id, rate); + break; + case SCLK_PWM0: + res = pwm_set_clk(priv, pdata->id, rate); + break; + case DCLK_VOP: + res = vop_set_clk(priv, pdata->id, rate); + break; + case ACLK_BUS: + case HCLK_BUS: + case PCLK_BUS: + res = bus_set_clk(priv, pdata->id, rate); + break; + case ACLK_PERI: + case HCLK_PERI: + case PCLK_PERI: + res = peri_set_clk(priv, pdata->id, rate); + break; + case HCLK_AUDIO: + case PCLK_AUDIO: + res = audio_set_clk(priv, pdata->id, rate); + break; + case SCLK_CRYPTO: + case SCLK_CRYPTO_APK: + res = crypto_set_clk(priv, pdata->id, rate); + break; + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + rate = uart_set_rate(priv, pdata->id, rate); + default: + return -RT_EINVAL; + } + + return res; +} + +static rt_err_t rk_clk_wait_lock(struct rk_clk_platform_data *pdata) +{ + rt_err_t err = RT_EOK; + rt_uint32_t count = 0, pllcon; + + /* + * Lock time typical 250, max 500 input clock cycles @24MHz, So define a + * very safe maximum of 1000us, meaning 24000 cycles. + */ + do { + pllcon = HWREG32(pdata->base + PLL_CON(1)); + rt_hw_us_delay(100); + ++count; + } while (pllcon & PLLCON1_LOCK_STATUS && count < 10); + + if (count >= 10) + { + err = -RT_ETIMEOUT; + } + + return err; +} + +static rt_err_t mac_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + /* + * If the requested parent is in the same clock-controller and + * the id is SCLK_MAC_SRC, switch to the internal clock. + */ + if (ppdata->id == SCLK_MAC_SRC) + { + LOG_D("MAC switching RMII to %s", "SCLK_MAC"); + rk_clrreg(&cru->clksel_con[43], RT_BIT(14)); + } + else + { + LOG_D("MAC switching RMII to %s", "CLKIN"); + rk_setreg(&cru->clksel_con[43], RT_BIT(14)); + } + + return 0; +} + +#define ROCKCHIP_MMC_DELAY_SEL RT_BIT(11) +#define ROCKCHIP_MMC_DEGREE_OFFSET 1 +#define ROCKCHIP_MMC_DEGREE_MASK (0x3 << ROCKCHIP_MMC_DEGREE_OFFSET) +#define ROCKCHIP_MMC_DELAYNUM_OFFSET 3 +#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) +/* + * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. + */ +#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 + +static rt_err_t mmc_set_phase(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk, rt_uint32_t degrees) +{ + rt_ubase_t rate; + rt_uint32_t raw_value, delay; + rt_uint8_t nineties, remainder, delay_num; + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + rate = rk_clk_get_rate(pdata, rk_clk); + + if (rate < 0) + { + return rate; + } + + nineties = degrees / 90; + remainder = (degrees % 90); + + /* + * Convert to delay; do a little extra work to make sure we + * don't overflow 32-bit / 64-bit numbers. + */ + delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ + delay *= remainder; + delay = RT_DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * + (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); + + delay_num = (rt_uint8_t)rt_min_t(rt_uint32_t, delay, 255); + + raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; + raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; + raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET; + + if (pdata->id == SCLK_EMMC_SAMPLE) + { + HWREG32(&cru->emmc_con[1]) = raw_value | 0xffff0000; + } + else + { + HWREG32(&cru->sdmmc_con[1]) = raw_value | 0xffff0000; + } + + return RT_EOK; +} + +static rt_base_t mmc_get_phase(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + rt_ubase_t rate; + rt_uint16_t degrees = 0; + rt_uint32_t raw_value, delay_num; + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + rate = rk_clk_get_rate(pdata, rk_clk); + + if (rate < 0) + { + return rate; + } + + if (pdata->id == SCLK_EMMC_SAMPLE) + { + raw_value = HWREG32(&cru->emmc_con[1]); + } + else + { + raw_value = HWREG32(&cru->sdmmc_con[1]); + } + + raw_value &= ROCKCHIP_MMC_DEGREE_MASK; + degrees = (raw_value >> ROCKCHIP_MMC_DEGREE_OFFSET) * 90; + + if (raw_value & ROCKCHIP_MMC_DELAY_SEL) + { + /* degrees/delaynum * 10000 */ + rt_ubase_t factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * + 36 * (rate / 1000000); + + delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); + delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; + degrees += RT_DIV_ROUND_CLOSEST(delay_num * factor, 10000); + } + + return degrees % 360; +} + +static rt_err_t rk3308_clk_init(struct rt_clk *clk, void *fw_data) +{ + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rt_ofw_cell_args *args = fw_data; + struct rk_clk_platform_data *pdata; + rt_uint32_t clk_id = args->args[0]; + rt_ubase_t reg_base; + + pdata = &rk_clk->pdata[clk_id]; + reg_base = (rt_ubase_t)rk_clk->clk_info.cru; + + switch (clk_id) + { + case PLL_APLL: + case ARMCLK: + reg_base += pll_clks[apll].con_offset; + break; + case PLL_DPLL: + reg_base += pll_clks[dpll].con_offset; + break; + case PLL_VPLL0: + reg_base += pll_clks[vpll0].con_offset; + break; + case PLL_VPLL1: + reg_base += pll_clks[vpll1].con_offset; + break; + default: + reg_base = RT_NULL; + break; + } + + pdata->id = clk_id; + pdata->base = (void *)reg_base; + + clk->rate = rk_clk_get_rate(pdata, rk_clk); + clk->priv = pdata; + + rk_clk_set_default_rates(clk, clk->clk_np->ops->set_rate, clk_id); + + return RT_EOK; +} + +static rt_err_t rk3308_clk_enable(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rk_cru *cru = rk_clk->clk_info.cru; + + if (pdata->base) + { + HWREG32(pdata->base + PLL_CON(1)) = HIWORD_UPDATE(0, PLLCON1_PWRDOWN, 0); + + rk_clk_wait_lock(pdata); + } + else + { + struct rk_clk_gate *gate = &clk_gates[pdata->id]; + + rk_clrreg(&cru->clkgate_con[gate->con_idx], RT_BIT(gate->con_bit)); + } + + return RT_EOK; +} + +static void rk3308_clk_disable(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rk_cru *cru = rk_clk->clk_info.cru; + + if (pdata->base) + { + HWREG32(pdata->base + PLL_CON(1)) = HIWORD_UPDATE(PLLCON1_PWRDOWN, PLLCON1_PWRDOWN, 0); + } + else + { + struct rk_clk_gate *gate = &clk_gates[pdata->id]; + + rk_setreg(&cru->clkgate_con[gate->con_idx], RT_BIT(gate->con_bit)); + } +} + +static rt_bool_t rk3308_clk_is_enabled(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + + if (pdata->base) + { + rt_uint32_t pllcon = HWREG32(pdata->base + PLL_CON(1)); + + return !(pllcon & PLLCON1_PWRDOWN); + } + + return RT_TRUE; +} + +static rt_err_t rk3308_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_ubase_t res_rate; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + res_rate = rk_clk_set_rate(pdata, rk_clk, rate); + + if ((rt_base_t)res_rate > 0) + { + clk->rate = res_rate; + } + + return (rt_ubase_t)res_rate > 0 ? RT_EOK : (rt_err_t)res_rate; +} + +static rt_err_t rk3308_clk_set_parent(struct rt_clk *clk, struct rt_clk *parent) +{ + struct rk_clk_platform_data *pdata = clk->priv, *ppdata = parent->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + switch (pdata->id) + { + case SCLK_MAC: + return mac_set_parent(pdata, ppdata, rk_clk); + + default: + break; + } + + return -RT_EINVAL; +} + +static rt_err_t rk3308_clk_set_phase(struct rt_clk *clk, int degrees) +{ + rt_err_t res; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + switch (pdata->id) + { + case SCLK_EMMC_SAMPLE: + case SCLK_SDMMC_SAMPLE: + res = mmc_set_phase(pdata, rk_clk, degrees); + break; + + default: + return -RT_EINVAL; + } + + return res; +} + +static rt_base_t rk3308_clk_get_phase(struct rt_clk *clk) +{ + rt_base_t res; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + switch (pdata->id) + { + case SCLK_EMMC_SAMPLE: + case SCLK_SDMMC_SAMPLE: + res = mmc_get_phase(pdata, rk_clk); + break; + + default: + return -RT_EINVAL; + } + + return res; +} + +static rt_base_t rk3308_clk_round_rate(struct rt_clk *clk, rt_ubase_t drate, + rt_ubase_t *prate) +{ + return rk_clk_pll_round_rate(pll_rates, RT_ARRAY_SIZE(pll_rates), drate, prate); +} + +static const struct rt_clk_ops rk3308_clk_ops = +{ + .init = rk3308_clk_init, + .enable = rk3308_clk_enable, + .disable = rk3308_clk_disable, + .is_enabled = rk3308_clk_is_enabled, + .set_rate = rk3308_clk_set_rate, + .set_parent = rk3308_clk_set_parent, + .set_phase = rk3308_clk_set_phase, + .get_phase = rk3308_clk_get_phase, + .round_rate = rk3308_clk_round_rate, +}; + +static void rk3308_clk_type_init(struct rk_clk *rk_clk, struct rt_ofw_node *np) +{ + rt_ubase_t cpu_freq = APLL_HZ; + struct rk_clk_priv *priv = &rk_clk->clk_info; + const char *rockchip_cpu_freq = rt_ofw_bootargs_select("rockchip.cpu_freq=", 0); + + priv->cru = (struct rk_cru *)rk_clk->base; + + if (rockchip_cpu_freq) + { + cpu_freq = atol(rockchip_cpu_freq); + } + + if (rk_pll_get_rate(&pll_clks[apll], priv->cru) != cpu_freq) + { + if (armclk_set_clk(priv, cpu_freq) < 0) + { + LOG_E("Failed to set armclk rate to %u, error = %s", cpu_freq); + } + } + + clk_get_pll_rate(priv); + + bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ); + bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ); + bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ); + + peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ); + peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ); + peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ); + + audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ); + audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ); +} + +static rt_err_t clk_rk3308_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + void *softrst_regs; + struct rt_ofw_node *np = pdev->parent.ofw_node; + struct rk_clk *rk_clk = rt_calloc(1, sizeof(*rk_clk)); + + if (!rk_clk) + { + return -RT_ENOMEM; + } + + rk_clk->base = rt_ofw_iomap(np, 0); + + if (!rk_clk->base) + { + err = -RT_EIO; + goto _fail; + } + + rk3308_clk_type_init(rk_clk, np); + softrst_regs = &rk_clk->clk_info.cru->softrst_con; + + rk_clk->parent.parent.ops = &rk3308_clk_ops; + + if ((err = rt_clk_register(&rk_clk->parent.parent, RT_NULL))) + { + goto _fail; + } + + if ((err = rk_register_softrst(&rk_clk->parent.rstcer, np, + softrst_regs, ROCKCHIP_SOFTRST_HIWORD_MASK))) + { + goto _fail; + } + + rt_ofw_data(np) = &rk_clk->parent; + + return RT_EOK; + +_fail: + if (rk_clk->base) + { + rt_iounmap(rk_clk->base); + } + + rt_free(rk_clk); + + return err; +} + +static const struct rt_ofw_node_id clk_rk3308_ofw_ids[] = +{ + { .compatible = "rockchip,rk3308-cru", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver clk_rk3308_driver = +{ + .name = "clk-rk3308", + .ids = clk_rk3308_ofw_ids, + + .probe = clk_rk3308_probe, +}; + +static int clk_rk3308_register(void) +{ + rt_platform_driver_register(&clk_rk3308_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(clk_rk3308_register); diff --git a/components/drivers/clk/rockchip/clk-rk3568.c b/components/drivers/clk/rockchip/clk-rk3568.c new file mode 100644 index 000000000000..1cf60f2d7ee4 --- /dev/null +++ b/components/drivers/clk/rockchip/clk-rk3568.c @@ -0,0 +1,4787 @@ +/* + * 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 "clk.h" + +#define DBG_TAG "clk.rk3568" +#define DBG_LVL DBG_INFO +#include + +#include + +#define APLL_HZ (816 * MHZ) +#define GPLL_HZ (1188 * MHZ) +#define CPLL_HZ (1000 * MHZ) +#define PPLL_HZ (100 * MHZ) + +struct rk_pll +{ + rt_uint32_t con0; + rt_uint32_t con1; + rt_uint32_t con2; + rt_uint32_t con3; + rt_uint32_t con4; + rt_uint32_t reserved0[3]; +}; + +struct rk_pmucru +{ + struct rk_pll pll[2]; + rt_uint32_t reserved0[16]; + rt_uint32_t mode_con00; + rt_uint32_t reserved1[31]; + rt_uint32_t pmu_clksel_con[10]; + rt_uint32_t reserved2[22]; + rt_uint32_t pmu_clkgate_con[3]; + rt_uint32_t reserved3[29]; + rt_uint32_t pmu_softrst_con[1]; +}; + +struct rk_cru +{ + struct rk_pll pll[6]; + rt_uint32_t mode_con00; + rt_uint32_t misc_con[3]; + rt_uint32_t glb_cnt_th; + rt_uint32_t glb_srst_fst; + rt_uint32_t glb_srsr_snd; + rt_uint32_t glb_rst_con; + rt_uint32_t glb_rst_st; + rt_uint32_t reserved0[7]; + rt_uint32_t clksel_con[85]; + rt_uint32_t reserved1[43]; + rt_uint32_t clkgate_con[36]; + rt_uint32_t reserved2[28]; + rt_uint32_t softrst_con[30]; + rt_uint32_t reserved3[2]; + rt_uint32_t ssgtbl[32]; + rt_uint32_t reserved4[32]; + rt_uint32_t sdmmc0_con[2]; + rt_uint32_t sdmmc1_con[2]; + rt_uint32_t sdmmc2_con[2]; + rt_uint32_t emmc_con[2]; +}; + +struct rk_pmuclk_priv +{ + struct rk_pmucru *pmucru; + rt_ubase_t ppll_hz; + rt_ubase_t hpll_hz; +}; + +struct rk_clk_priv +{ + struct rk_cru *cru; + rt_ubase_t ppll_hz; + rt_ubase_t hpll_hz; + rt_ubase_t gpll_hz; + rt_ubase_t cpll_hz; + rt_ubase_t npll_hz; + rt_ubase_t vpll_hz; + rt_ubase_t armclk_hz; + rt_ubase_t armclk_enter_hz; + rt_ubase_t armclk_init_hz; + rt_bool_t sync_kernel; + rt_bool_t set_armclk_rate; +}; + +struct rk_clk_platform_data +{ + rt_uint32_t id; + void *base; +}; + +enum rk_clk_type +{ + rk_clk_type_clk, + rk_clk_type_pmuclk, +}; + +struct rk_clk +{ + struct rt_reset_controller_clk_node parent; + + void *base; + enum rk_clk_type type; + + union + { + struct rk_clk_priv clk_info; + struct rk_pmuclk_priv pmuclk_info; + }; + + struct rk_clk_platform_data pdata[]; +}; + +#define raw_to_rk_clk(raw) rt_container_of(raw, struct rk_clk, parent) + +#define PMU_MODE 0x80 +#define PMU_PLL_CON(x) ((x) * 0x4) +#define PLL_CON(x) ((x) * 0x4) +#define MODE_CON 0xc0 + +enum pmu_plls +{ + ppll, hpll, +}; + +enum plls +{ + apll, dpll, gpll, cpll, npll, vpll, +}; + +enum +{ + /* CRU_PMU_CLK_SEL0_CON */ + RTC32K_SEL_SHIFT = 6, + RTC32K_SEL_MASK = 0x3 << RTC32K_SEL_SHIFT, + RTC32K_SEL_PMUPVTM = 0, + RTC32K_SEL_OSC1_32K, + RTC32K_SEL_OSC0_DIV32K, + + /* CRU_PMU_CLK_SEL1_CON */ + RTC32K_FRAC_NUMERATOR_SHIFT = 16, + RTC32K_FRAC_NUMERATOR_MASK = 0xffff << 16, + RTC32K_FRAC_DENOMINATOR_SHIFT = 0, + RTC32K_FRAC_DENOMINATOR_MASK = 0xffff, + + /* CRU_PMU_CLK_SEL2_CON */ + PCLK_PDPMU_SEL_SHIFT = 15, + PCLK_PDPMU_SEL_MASK = 1 << PCLK_PDPMU_SEL_SHIFT, + PCLK_PDPMU_SEL_PPLL = 0, + PCLK_PDPMU_SEL_GPLL, + PCLK_PDPMU_DIV_SHIFT = 0, + PCLK_PDPMU_DIV_MASK = 0x1f, + + /* CRU_PMU_CLK_SEL3_CON */ + CLK_I2C0_DIV_SHIFT = 0, + CLK_I2C0_DIV_MASK = 0x7f, + + /* PMUCRU_PMUCLKSEL_CON04 */ + CLK_UART0_SEL_SHIFT = 10, + CLK_UART0_SEL_MASK = 0x3 << CLK_UART0_SEL_SHIFT, + CLK_UART0_SEL_DIV = 0, + CLK_UART0_SEL_FRACDIV, + CLK_UART0_SEL_XIN24M, + CLK_UART0_DIV_SEL_SHIFT = 8, + CLK_UART0_DIV_SEL_MASK = 0x3 << CLK_UART0_DIV_SEL_SHIFT, + CLK_UART0_SRC_SEL_PPLL = 0, + CLK_UART0_SRC_SEL_480M, + CLK_UART0_SRC_SEL_CPLL, + CLK_UART0_SRC_SEL_GPLL, + CLK_UART0_DIV_DIV_SHIFT = 0, + CLK_UART0_DIV_DIV_MASK = 0x3f << CLK_UART0_DIV_DIV_SHIFT, + + /* PMUCRU_PMUCLKSEL_CON05 */ + CLK_UART0_FRAC_NUMERATOR_SHIFT = 16, + CLK_UART0_FRAC_NUMERATOR_MASK = 0xffff << 16, + CLK_UART0_FRAC_DENOMINATOR_SHIFT= 0, + CLK_UART0_FRAC_DENOMINATOR_MASK = 0xffff, + + /* PMUCRU_PMUCLKSEL_CON09 */ + CLK_PCIE_PHY2_REF_SEL_SHIFT = 11, + CLK_PCIE_PHY2_REF_SEL_MASK = 1 << CLK_PCIE_PHY2_REF_SEL_SHIFT, + CLK_PCIE_PHY1_REF_SEL_SHIFT = 7, + CLK_PCIE_PHY1_REF_SEL_MASK = 1 << CLK_PCIE_PHY1_REF_SEL_SHIFT, + CLK_PCIE_PHY0_REF_SEL_SHIFT = 3, + CLK_PCIE_PHY0_REF_SEL_MASK = 1 << CLK_PCIE_PHY0_REF_SEL_SHIFT, + CLK_PCIE_PHY_REF_SEL_24M = 0, + CLK_PCIE_PHY_REF_SEL_PPLL, + CLK_PCIE_PHY2_PLL_DIV_SHIFT = 8, + CLK_PCIE_PHY2_PLL_DIV_MASK = 7 << CLK_PCIE_PHY2_PLL_DIV_SHIFT, + CLK_PCIE_PHY1_PLL_DIV_SHIFT = 4, + CLK_PCIE_PHY1_PLL_DIV_MASK = 7 << CLK_PCIE_PHY1_PLL_DIV_SHIFT, + CLK_PCIE_PHY0_PLL_DIV_SHIFT = 0, + CLK_PCIE_PHY0_PLL_DIV_MASK = 7 << CLK_PCIE_PHY0_PLL_DIV_SHIFT, + + /* CRU_PMU_CLK_SEL6_CON */ + CLK_PWM0_SEL_SHIFT = 7, + CLK_PWM0_SEL_MASK = 1 << CLK_PWM0_SEL_SHIFT, + CLK_PWM0_SEL_XIN24M = 0, + CLK_PWM0_SEL_PPLL, + CLK_PWM0_DIV_SHIFT = 0, + CLK_PWM0_DIV_MASK = 0x7f, + + /* CRU_CLK_SEL0_CON */ + CLK_CORE_PRE_SEL_SHIFT = 7, + CLK_CORE_PRE_SEL_MASK = 1 << CLK_CORE_PRE_SEL_SHIFT, + CLK_CORE_PRE_SEL_SRC = 0, + CLK_CORE_PRE_SEL_APLL, + + /* CRU_CLK_SEL2_CON */ + SCLK_CORE_PRE_SEL_SHIFT = 15, + SCLK_CORE_PRE_SEL_MASK = 1 << SCLK_CORE_PRE_SEL_SHIFT, + SCLK_CORE_PRE_SEL_SRC = 0, + SCLK_CORE_PRE_SEL_NPLL, + SCLK_CORE_SRC_SEL_SHIFT = 8, + SCLK_CORE_SRC_SEL_MASK = 3 << SCLK_CORE_SRC_SEL_SHIFT, + SCLK_CORE_SRC_SEL_APLL = 0, + SCLK_CORE_SRC_SEL_GPLL, + SCLK_CORE_SRC_SEL_NPLL, + SCLK_CORE_SRC_DIV_SHIFT = 0, + SCLK_CORE_SRC_DIV_MASK = 0x1f << SCLK_CORE_SRC_DIV_SHIFT, + + /* CRU_CLK_SEL3_CON */ + GICCLK_CORE_DIV_SHIFT = 8, + GICCLK_CORE_DIV_MASK = 0x1f << GICCLK_CORE_DIV_SHIFT, + ATCLK_CORE_DIV_SHIFT = 0, + ATCLK_CORE_DIV_MASK = 0x1f << ATCLK_CORE_DIV_SHIFT, + + /* CRU_CLK_SEL4_CON */ + PERIPHCLK_CORE_PRE_DIV_SHIFT = 8, + PERIPHCLK_CORE_PRE_DIV_MASK = 0x1f << PERIPHCLK_CORE_PRE_DIV_SHIFT, + PCLK_CORE_PRE_DIV_SHIFT = 0, + PCLK_CORE_PRE_DIV_MASK = 0x1f << PCLK_CORE_PRE_DIV_SHIFT, + + /* CRU_CLK_SEL5_CON */ + ACLK_CORE_NIU2BUS_SEL_SHIFT = 14, + ACLK_CORE_NIU2BUS_SEL_MASK = 0x3 << ACLK_CORE_NIU2BUS_SEL_SHIFT, + ACLK_CORE_NDFT_DIV_SHIFT = 8, + ACLK_CORE_NDFT_DIV_MASK = 0x1f << ACLK_CORE_NDFT_DIV_SHIFT, + + /* CRU_CLK_SEL10_CON */ + HCLK_PERIMID_SEL_SHIFT = 6, + HCLK_PERIMID_SEL_MASK = 3 << HCLK_PERIMID_SEL_SHIFT, + HCLK_PERIMID_SEL_150M = 0, + HCLK_PERIMID_SEL_100M, + HCLK_PERIMID_SEL_75M, + HCLK_PERIMID_SEL_24M, + ACLK_PERIMID_SEL_SHIFT = 4, + ACLK_PERIMID_SEL_MASK = 3 << ACLK_PERIMID_SEL_SHIFT, + ACLK_PERIMID_SEL_300M = 0, + ACLK_PERIMID_SEL_200M, + ACLK_PERIMID_SEL_100M, + ACLK_PERIMID_SEL_24M, + + /* CRU_CLK_SEL27_CON */ + CLK_CRYPTO_PKA_SEL_SHIFT = 6, + CLK_CRYPTO_PKA_SEL_MASK = 3 << CLK_CRYPTO_PKA_SEL_SHIFT, + CLK_CRYPTO_PKA_SEL_300M = 0, + CLK_CRYPTO_PKA_SEL_200M, + CLK_CRYPTO_PKA_SEL_100M, + CLK_CRYPTO_CORE_SEL_SHIFT = 4, + CLK_CRYPTO_CORE_SEL_MASK = 3 << CLK_CRYPTO_CORE_SEL_SHIFT, + CLK_CRYPTO_CORE_SEL_200M = 0, + CLK_CRYPTO_CORE_SEL_150M, + CLK_CRYPTO_CORE_SEL_100M, + HCLK_SECURE_FLASH_SEL_SHIFT = 2, + HCLK_SECURE_FLASH_SEL_MASK = 3 << HCLK_SECURE_FLASH_SEL_SHIFT, + HCLK_SECURE_FLASH_SEL_150M = 0, + HCLK_SECURE_FLASH_SEL_100M, + HCLK_SECURE_FLASH_SEL_75M, + HCLK_SECURE_FLASH_SEL_24M, + ACLK_SECURE_FLASH_SEL_SHIFT = 0, + ACLK_SECURE_FLASH_SEL_MASK = 3 << ACLK_SECURE_FLASH_SEL_SHIFT, + ACLK_SECURE_FLASH_SEL_200M = 0, + ACLK_SECURE_FLASH_SEL_150M, + ACLK_SECURE_FLASH_SEL_100M, + ACLK_SECURE_FLASH_SEL_24M, + + /* CRU_CLK_SEL28_CON */ + CCLK_EMMC_SEL_SHIFT = 12, + CCLK_EMMC_SEL_MASK = 7 << CCLK_EMMC_SEL_SHIFT, + CCLK_EMMC_SEL_24M = 0, + CCLK_EMMC_SEL_200M, + CCLK_EMMC_SEL_150M, + CCLK_EMMC_SEL_100M, + CCLK_EMMC_SEL_50M, + CCLK_EMMC_SEL_375K, + BCLK_EMMC_SEL_SHIFT = 8, + BCLK_EMMC_SEL_MASK = 3 << BCLK_EMMC_SEL_SHIFT, + BCLK_EMMC_SEL_200M = 0, + BCLK_EMMC_SEL_150M, + BCLK_EMMC_SEL_125M, + SCLK_SFC_SEL_SHIFT = 4, + SCLK_SFC_SEL_MASK = 7 << SCLK_SFC_SEL_SHIFT, + SCLK_SFC_SEL_24M = 0, + SCLK_SFC_SEL_50M, + SCLK_SFC_SEL_75M, + SCLK_SFC_SEL_100M, + SCLK_SFC_SEL_125M, + SCLK_SFC_SEL_150M, + NCLK_NANDC_SEL_SHIFT = 0, + NCLK_NANDC_SEL_MASK = 3 << NCLK_NANDC_SEL_SHIFT, + NCLK_NANDC_SEL_200M = 0, + NCLK_NANDC_SEL_150M, + NCLK_NANDC_SEL_100M, + NCLK_NANDC_SEL_24M, + + /* CRU_CLK_SEL30_CON */ + CLK_SDMMC1_SEL_SHIFT = 12, + CLK_SDMMC1_SEL_MASK = 7 << CLK_SDMMC1_SEL_SHIFT, + CLK_SDMMC0_SEL_SHIFT = 8, + CLK_SDMMC0_SEL_MASK = 7 << CLK_SDMMC0_SEL_SHIFT, + CLK_SDMMC_SEL_24M = 0, + CLK_SDMMC_SEL_400M, + CLK_SDMMC_SEL_300M, + CLK_SDMMC_SEL_100M, + CLK_SDMMC_SEL_50M, + CLK_SDMMC_SEL_750K, + + /* CRU_CLK_SEL31_CON */ + CLK_MAC0_OUT_SEL_SHIFT = 14, + CLK_MAC0_OUT_SEL_MASK = 3 << CLK_MAC0_OUT_SEL_SHIFT, + CLK_MAC0_OUT_SEL_125M = 0, + CLK_MAC0_OUT_SEL_50M, + CLK_MAC0_OUT_SEL_25M, + CLK_MAC0_OUT_SEL_24M, + CLK_GMAC0_PTP_REF_SEL_SHIFT = 12, + CLK_GMAC0_PTP_REF_SEL_MASK = 3 << CLK_GMAC0_PTP_REF_SEL_SHIFT, + CLK_GMAC0_PTP_REF_SEL_62_5M = 0, + CLK_GMAC0_PTP_REF_SEL_100M, + CLK_GMAC0_PTP_REF_SEL_50M, + CLK_GMAC0_PTP_REF_SEL_24M, + CLK_MAC0_2TOP_SEL_SHIFT = 8, + CLK_MAC0_2TOP_SEL_MASK = 3 << CLK_MAC0_2TOP_SEL_SHIFT, + CLK_MAC0_2TOP_SEL_125M = 0, + CLK_MAC0_2TOP_SEL_50M, + CLK_MAC0_2TOP_SEL_25M, + CLK_MAC0_2TOP_SEL_PPLL, + RGMII0_CLK_SEL_SHIFT = 4, + RGMII0_CLK_SEL_MASK = 3 << RGMII0_CLK_SEL_SHIFT, + RGMII0_CLK_SEL_125M = 0, + RGMII0_CLK_SEL_125M_1, + RGMII0_CLK_SEL_2_5M, + RGMII0_CLK_SEL_25M, + RMII0_CLK_SEL_SHIFT = 3, + RMII0_CLK_SEL_MASK = 1 << RMII0_CLK_SEL_SHIFT, + RMII0_CLK_SEL_2_5M = 0, + RMII0_CLK_SEL_25M, + RMII0_EXTCLK_SEL_SHIFT = 2, + RMII0_EXTCLK_SEL_MASK = 1 << RMII0_EXTCLK_SEL_SHIFT, + RMII0_EXTCLK_SEL_MAC0_TOP = 0, + RMII0_EXTCLK_SEL_IO, + RMII0_MODE_SHIFT = 0, + RMII0_MODE_MASK = 3 << RMII0_MODE_SHIFT, + RMII0_MODE_SEL_RGMII = 0, + RMII0_MODE_SEL_RMII, + RMII0_MODE_SEL_GMII, + + /* CRU_CLK_SEL32_CON */ + CLK_SDMMC2_SEL_SHIFT = 8, + CLK_SDMMC2_SEL_MASK = 7 << CLK_SDMMC2_SEL_SHIFT, + + /* CRU_CLK_SEL38_CON */ + ACLK_VOP_PRE_SEL_SHIFT = 6, + ACLK_VOP_PRE_SEL_MASK = 3 << ACLK_VOP_PRE_SEL_SHIFT, + ACLK_VOP_PRE_SEL_CPLL = 0, + ACLK_VOP_PRE_SEL_GPLL, + ACLK_VOP_PRE_SEL_HPLL, + ACLK_VOP_PRE_SEL_VPLL, + ACLK_VOP_PRE_DIV_SHIFT = 0, + ACLK_VOP_PRE_DIV_MASK = 0x1f << ACLK_VOP_PRE_DIV_SHIFT, + + /* CRU_CLK_SEL39_CON */ + DCLK0_VOP_SEL_SHIFT = 10, + DCLK0_VOP_SEL_MASK = 3 << DCLK0_VOP_SEL_SHIFT, + DCLK_VOP_SEL_HPLL = 0, + DCLK_VOP_SEL_VPLL, + DCLK_VOP_SEL_GPLL, + DCLK_VOP_SEL_CPLL, + DCLK0_VOP_DIV_SHIFT = 0, + DCLK0_VOP_DIV_MASK = 0xff << DCLK0_VOP_DIV_SHIFT, + + /* CRU_CLK_SEL40_CON */ + DCLK1_VOP_SEL_SHIFT = 10, + DCLK1_VOP_SEL_MASK = 3 << DCLK1_VOP_SEL_SHIFT, + DCLK1_VOP_DIV_SHIFT = 0, + DCLK1_VOP_DIV_MASK = 0xff << DCLK1_VOP_DIV_SHIFT, + + /* CRU_CLK_SEL41_CON */ + DCLK2_VOP_SEL_SHIFT = 10, + DCLK2_VOP_SEL_MASK = 3 << DCLK2_VOP_SEL_SHIFT, + DCLK2_VOP_DIV_SHIFT = 0, + DCLK2_VOP_DIV_MASK = 0xff << DCLK2_VOP_DIV_SHIFT, + + /* CRU_CLK_SEL43_CON */ + DCLK_EBC_SEL_SHIFT = 6, + DCLK_EBC_SEL_MASK = 3 << DCLK_EBC_SEL_SHIFT, + DCLK_EBC_SEL_GPLL_400M = 0, + DCLK_EBC_SEL_CPLL_333M, + DCLK_EBC_SEL_GPLL_200M, + + /* CRU_CLK_SEL47_CON */ + ACLK_RKVDEC_SEL_SHIFT = 7, + ACLK_RKVDEC_SEL_MASK = 1 << ACLK_RKVDEC_SEL_SHIFT, + ACLK_RKVDEC_SEL_GPLL = 0, + ACLK_RKVDEC_SEL_CPLL, + ACLK_RKVDEC_DIV_SHIFT = 0, + ACLK_RKVDEC_DIV_MASK = 0x1f << ACLK_RKVDEC_DIV_SHIFT, + + /* CRU_CLK_SEL49_CON */ + CLK_RKVDEC_CORE_SEL_SHIFT = 14, + CLK_RKVDEC_CORE_SEL_MASK = 0x3 << CLK_RKVDEC_CORE_SEL_SHIFT, + CLK_RKVDEC_CORE_SEL_GPLL = 0, + CLK_RKVDEC_CORE_SEL_CPLL, + CLK_RKVDEC_CORE_SEL_NPLL, + CLK_RKVDEC_CORE_SEL_VPLL, + CLK_RKVDEC_CORE_DIV_SHIFT = 8, + CLK_RKVDEC_CORE_DIV_MASK = 0x1f << CLK_RKVDEC_CORE_DIV_SHIFT, + + /* CRU_CLK_SEL50_CON */ + PCLK_BUS_SEL_SHIFT = 4, + PCLK_BUS_SEL_MASK = 3 << PCLK_BUS_SEL_SHIFT, + PCLK_BUS_SEL_100M = 0, + PCLK_BUS_SEL_75M, + PCLK_BUS_SEL_50M, + PCLK_BUS_SEL_24M, + ACLK_BUS_SEL_SHIFT = 0, + ACLK_BUS_SEL_MASK = 3 << ACLK_BUS_SEL_SHIFT, + ACLK_BUS_SEL_200M = 0, + ACLK_BUS_SEL_150M, + ACLK_BUS_SEL_100M, + ACLK_BUS_SEL_24M, + + /* CRU_CLK_SEL51_CON */ + CLK_TSADC_DIV_SHIFT = 8, + CLK_TSADC_DIV_MASK = 0x7f << CLK_TSADC_DIV_SHIFT, + CLK_TSADC_TSEN_SEL_SHIFT = 4, + CLK_TSADC_TSEN_SEL_MASK = 0x3 << CLK_TSADC_TSEN_SEL_SHIFT, + CLK_TSADC_TSEN_SEL_24M = 0, + CLK_TSADC_TSEN_SEL_100M, + CLK_TSADC_TSEN_SEL_CPLL_100M, + CLK_TSADC_TSEN_DIV_SHIFT = 0, + CLK_TSADC_TSEN_DIV_MASK = 0x7 << CLK_TSADC_TSEN_DIV_SHIFT, + + /* CRU_CLK_SEL52_CON */ + CLK_UART_SEL_SHIFT = 12, + CLK_UART_SEL_MASK = 0x3 << CLK_UART_SEL_SHIFT, + CLK_UART_SEL_SRC = 0, + CLK_UART_SEL_FRAC, + CLK_UART_SEL_XIN24M, + CLK_UART_SRC_SEL_SHIFT = 8, + CLK_UART_SRC_SEL_MASK = 0x3 << CLK_UART_SRC_SEL_SHIFT, + CLK_UART_SRC_SEL_GPLL = 0, + CLK_UART_SRC_SEL_CPLL, + CLK_UART_SRC_SEL_480M, + CLK_UART_SRC_DIV_SHIFT = 0, + CLK_UART_SRC_DIV_MASK = 0x3f << CLK_UART_SRC_DIV_SHIFT, + + /* CRU_CLK_SEL53_CON */ + CLK_UART_FRAC_NUMERATOR_SHIFT = 16, + CLK_UART_FRAC_NUMERATOR_MASK = 0xffff << 16, + CLK_UART_FRAC_DENOMINATOR_SHIFT = 0, + CLK_UART_FRAC_DENOMINATOR_MASK = 0xffff, + + /* CRU_CLK_SEL71_CON */ + CLK_I2C_SEL_SHIFT = 8, + CLK_I2C_SEL_MASK = 3 << CLK_I2C_SEL_SHIFT, + CLK_I2C_SEL_200M = 0, + CLK_I2C_SEL_100M, + CLK_I2C_SEL_24M, + CLK_I2C_SEL_CPLL_100M, + + /* CRU_CLK_SEL72_CON */ + CLK_PWM3_SEL_SHIFT = 12, + CLK_PWM3_SEL_MASK = 3 << CLK_PWM3_SEL_SHIFT, + CLK_PWM2_SEL_SHIFT = 10, + CLK_PWM2_SEL_MASK = 3 << CLK_PWM2_SEL_SHIFT, + CLK_PWM1_SEL_SHIFT = 8, + CLK_PWM1_SEL_MASK = 3 << CLK_PWM1_SEL_SHIFT, + CLK_PWM_SEL_100M = 0, + CLK_PWM_SEL_24M, + CLK_PWM_SEL_CPLL_100M, + CLK_SPI3_SEL_SHIFT = 6, + CLK_SPI3_SEL_MASK = 3 << CLK_SPI3_SEL_SHIFT, + CLK_SPI2_SEL_SHIFT = 4, + CLK_SPI2_SEL_MASK = 3 << CLK_SPI2_SEL_SHIFT, + CLK_SPI1_SEL_SHIFT = 2, + CLK_SPI1_SEL_MASK = 3 << CLK_SPI1_SEL_SHIFT, + CLK_SPI0_SEL_SHIFT = 0, + CLK_SPI0_SEL_MASK = 3 << CLK_SPI0_SEL_SHIFT, + CLK_SPI_SEL_200M = 0, + CLK_SPI_SEL_24M, + CLK_SPI_SEL_CPLL_100M, + + /* CRU_CLK_SEL73_CON */ + PCLK_TOP_SEL_SHIFT = 12, + PCLK_TOP_SEL_MASK = 3 << PCLK_TOP_SEL_SHIFT, + PCLK_TOP_SEL_100M = 0, + PCLK_TOP_SEL_75M, + PCLK_TOP_SEL_50M, + PCLK_TOP_SEL_24M, + HCLK_TOP_SEL_SHIFT = 8, + HCLK_TOP_SEL_MASK = 3 << HCLK_TOP_SEL_SHIFT, + HCLK_TOP_SEL_150M = 0, + HCLK_TOP_SEL_100M, + HCLK_TOP_SEL_75M, + HCLK_TOP_SEL_24M, + ACLK_TOP_LOW_SEL_SHIFT = 4, + ACLK_TOP_LOW_SEL_MASK = 3 << ACLK_TOP_LOW_SEL_SHIFT, + ACLK_TOP_LOW_SEL_400M = 0, + ACLK_TOP_LOW_SEL_300M, + ACLK_TOP_LOW_SEL_200M, + ACLK_TOP_LOW_SEL_24M, + ACLK_TOP_HIGH_SEL_SHIFT = 0, + ACLK_TOP_HIGH_SEL_MASK = 3 << ACLK_TOP_HIGH_SEL_SHIFT, + ACLK_TOP_HIGH_SEL_500M = 0, + ACLK_TOP_HIGH_SEL_400M, + ACLK_TOP_HIGH_SEL_300M, + ACLK_TOP_HIGH_SEL_24M, + + /* CRU_CLK_SEL78_CON */ + CPLL_500M_DIV_SHIFT = 8, + CPLL_500M_DIV_MASK = 0x1f << CPLL_500M_DIV_SHIFT, + + /* CRU_CLK_SEL79_CON */ + CPLL_250M_DIV_SHIFT = 8, + CPLL_250M_DIV_MASK = 0x1f << CPLL_250M_DIV_SHIFT, + CPLL_333M_DIV_SHIFT = 0, + CPLL_333M_DIV_MASK = 0x1f << CPLL_333M_DIV_SHIFT, + + /* CRU_CLK_SEL80_CON */ + CPLL_62P5M_DIV_SHIFT = 8, + CPLL_62P5M_DIV_MASK = 0x1f << CPLL_62P5M_DIV_SHIFT, + CPLL_125M_DIV_SHIFT = 0, + CPLL_125M_DIV_MASK = 0x1f << CPLL_125M_DIV_SHIFT, + + /* CRU_CLK_SEL81_CON */ + CPLL_25M_DIV_SHIFT = 8, + CPLL_25M_DIV_MASK = 0x1f << CPLL_25M_DIV_SHIFT, + CPLL_50M_DIV_SHIFT = 0, + CPLL_50M_DIV_MASK = 0x1f << CPLL_50M_DIV_SHIFT, + + /* CRU_CLK_SEL82_CON */ + CPLL_100M_DIV_SHIFT = 0, + CPLL_100M_DIV_MASK = 0x1f << CPLL_100M_DIV_SHIFT, +}; + +static struct rk_cpu_rate_table cpu_rates[] = +{ + CPUCLK_RATE(1800000000, 1, 7), + CPUCLK_RATE(1704000000, 1, 7), + CPUCLK_RATE(1608000000, 1, 5), + CPUCLK_RATE(1584000000, 1, 5), + CPUCLK_RATE(1560000000, 1, 5), + CPUCLK_RATE(1536000000, 1, 5), + CPUCLK_RATE(1512000000, 1, 5), + CPUCLK_RATE(1488000000, 1, 5), + CPUCLK_RATE(1464000000, 1, 5), + CPUCLK_RATE(1440000000, 1, 5), + CPUCLK_RATE(1416000000, 1, 5), + CPUCLK_RATE(1392000000, 1, 5), + CPUCLK_RATE(1368000000, 1, 5), + CPUCLK_RATE(1344000000, 1, 5), + CPUCLK_RATE(1320000000, 1, 5), + CPUCLK_RATE(1296000000, 1, 5), + CPUCLK_RATE(1272000000, 1, 5), + CPUCLK_RATE(1248000000, 1, 5), + CPUCLK_RATE(1224000000, 1, 5), + CPUCLK_RATE(1200000000, 1, 3), + CPUCLK_RATE(1104000000, 1, 3), + CPUCLK_RATE(1008000000, 1, 3), + CPUCLK_RATE(912000000, 1, 3), + CPUCLK_RATE(816000000, 1, 3), + CPUCLK_RATE(696000000, 1, 3), + CPUCLK_RATE(600000000, 1, 3), + CPUCLK_RATE(408000000, 1, 3), + CPUCLK_RATE(312000000, 1, 3), + CPUCLK_RATE(216000000, 1, 3), + CPUCLK_RATE(96000000, 1, 3), + { /* sentinel */ }, +}; + +static struct rk_pll_rate_table pll_rates[] = +{ + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + PLL_RATE(2208000000, 1, 92, 1, 1, 1, 0), + PLL_RATE(2184000000, 1, 91, 1, 1, 1, 0), + PLL_RATE(2160000000, 1, 90, 1, 1, 1, 0), + PLL_RATE(2088000000, 1, 87, 1, 1, 1, 0), + PLL_RATE(2064000000, 1, 86, 1, 1, 1, 0), + PLL_RATE(2040000000, 1, 85, 1, 1, 1, 0), + PLL_RATE(2016000000, 1, 84, 1, 1, 1, 0), + PLL_RATE(1992000000, 1, 83, 1, 1, 1, 0), + PLL_RATE(1920000000, 1, 80, 1, 1, 1, 0), + PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), + PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), + PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), + PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0), + PLL_RATE(1584000000, 1, 132, 2, 1, 1, 0), + PLL_RATE(1560000000, 1, 130, 2, 1, 1, 0), + PLL_RATE(1536000000, 1, 128, 2, 1, 1, 0), + PLL_RATE(1512000000, 1, 126, 2, 1, 1, 0), + PLL_RATE(1488000000, 1, 124, 2, 1, 1, 0), + PLL_RATE(1464000000, 1, 122, 2, 1, 1, 0), + PLL_RATE(1440000000, 1, 120, 2, 1, 1, 0), + PLL_RATE(1416000000, 1, 118, 2, 1, 1, 0), + PLL_RATE(1400000000, 3, 350, 2, 1, 1, 0), + PLL_RATE(1392000000, 1, 116, 2, 1, 1, 0), + PLL_RATE(1368000000, 1, 114, 2, 1, 1, 0), + PLL_RATE(1344000000, 1, 112, 2, 1, 1, 0), + PLL_RATE(1320000000, 1, 110, 2, 1, 1, 0), + PLL_RATE(1296000000, 1, 108, 2, 1, 1, 0), + PLL_RATE(1272000000, 1, 106, 2, 1, 1, 0), + PLL_RATE(1248000000, 1, 104, 2, 1, 1, 0), + PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0), + PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), + PLL_RATE(1104000000, 1, 92, 2, 1, 1, 0), + PLL_RATE(1100000000, 3, 275, 2, 1, 1, 0), + PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0), + PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), + PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), + PLL_RATE(800000000, 3, 200, 2, 1, 1, 0), + PLL_RATE(700000000, 3, 350, 4, 1, 1, 0), + PLL_RATE(696000000, 1, 116, 4, 1, 1, 0), + PLL_RATE(600000000, 1, 100, 4, 1, 1, 0), + PLL_RATE(594000000, 1, 99, 4, 1, 1, 0), + PLL_RATE(500000000, 1, 125, 6, 1, 1, 0), + PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), + PLL_RATE(297000000, 2, 99, 4, 1, 1, 0), + PLL_RATE(241500000, 2, 161, 4, 2, 1, 0), + PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + PLL_RATE(200000000, 1, 100, 3, 4, 1, 0), + PLL_RATE(148500000, 1, 99, 4, 4, 1, 0), + PLL_RATE(135000000, 2, 45, 4, 1, 1, 0), + PLL_RATE(119000000, 3, 119, 4, 2, 1, 0), + PLL_RATE(108000000, 2, 45, 5, 1, 1, 0), + PLL_RATE(100000000, 1, 150, 6, 6, 1, 0), + PLL_RATE(96000000, 1, 96, 6, 4, 1, 0), + PLL_RATE(78750000, 1, 96, 6, 4, 1, 0), + PLL_RATE(74250000, 2, 99, 4, 4, 1, 0), + { /* sentinel */ }, +}; + +static struct rk_pll_clock pmu_pll_clks[] = +{ + [ppll] = PLL(PLL_PPLL, PMU_PLL_CON(0), PMU_MODE, 0, 10, 0, pll_rates), + [hpll] = PLL(PLL_HPLL, PMU_PLL_CON(16), PMU_MODE, 2, 10, 0, pll_rates), +}; + +static struct rk_pll_clock pll_clks[] = +{ + [apll] = PLL(PLL_APLL, PLL_CON(0), MODE_CON, 0, 10, 0, pll_rates), + [dpll] = PLL(PLL_DPLL, PLL_CON(8), MODE_CON, 2, 10, 0, RT_NULL), + [gpll] = PLL(PLL_HPLL, PLL_CON(16), MODE_CON, 6, 10, 0, pll_rates), + [cpll] = PLL(PLL_CPLL, PLL_CON(24), MODE_CON, 4, 10, 0, pll_rates), + [npll] = PLL(PLL_NPLL, PLL_CON(32), MODE_CON, 10, 10, 0, pll_rates), + [vpll] = PLL(PLL_VPLL, PLL_CON(40), MODE_CON, 12, 10, 0, pll_rates), +}; + +static struct rk_clk_gate clk_gates[] = +{ + /* CRU_GATE_CON00 */ + /* CRU_GATE_CON01 */ + GATE(PCLK_CORE_PVTM, "pclk_core_pvtm", "pclk_core_pre", 1, 9), + GATE(CLK_CORE_PVTM, "clk_core_pvtm", "xin24m", 1, 10), + GATE(CLK_CORE_PVTM_CORE, "clk_core_pvtm_core", "armclk", 1, 11), + GATE(CLK_CORE_PVTPLL, "clk_core_pvtpll", "armclk", 1, 12), + /* CRU_GATE_CON02 */ + GATE(CLK_GPU_SRC, "clk_gpu_src", "clk_gpu_pre_c", 2, 0), + GATE(PCLK_GPU_PRE, "pclk_gpu_pre", "pclk_gpu_pre_div", 2, 2), + GATE(CLK_GPU, "clk_gpu", "clk_gpu_pre_c", 2, 3), + GATE(PCLK_GPU_PVTM, "pclk_gpu_pvtm", "pclk_gpu_pre", 2, 6), + GATE(CLK_GPU_PVTM, "clk_gpu_pvtm", "xin24m", 2, 7), + GATE(CLK_GPU_PVTM_CORE, "clk_gpu_pvtm_core", "clk_gpu_src", 2, 8), + GATE(CLK_GPU_PVTPLL, "clk_gpu_pvtpll", "clk_gpu_src", 2, 9), + GATE(ACLK_GPU_PRE, "aclk_gpu_pre", "aclk_gpu_pre_div", 2, 11), + /* CRU_GATE_CON03 */ + GATE(CLK_NPU_SRC, "clk_npu_src", "clk_npu_src_c", 3, 0), + GATE(CLK_NPU_NP5, "clk_npu_np5", "clk_npu_np5_c", 3, 1), + GATE(HCLK_NPU_PRE, "hclk_npu_pre", "hclk_npu_pre_div", 3, 2), + GATE(PCLK_NPU_PRE, "pclk_npu_pre", "pclk_npu_pre_div", 3, 3), + GATE(ACLK_NPU_PRE, "aclk_npu_pre", "clk_npu", 3, 4), + GATE(ACLK_NPU, "aclk_npu", "aclk_npu_pre", 3, 7), + GATE(HCLK_NPU, "hclk_npu", "hclk_npu_pre", 3, 8), + GATE(PCLK_NPU_PVTM, "pclk_npu_pvtm", "pclk_npu_pre", 3, 9), + GATE(CLK_NPU_PVTM, "clk_npu_pvtm", "xin24m", 3, 10), + GATE(CLK_NPU_PVTM_CORE, "clk_npu_pvtm_core", "clk_npu_pre_ndft", 3, 11), + GATE(CLK_NPU_PVTPLL, "clk_npu_pvtpll", "clk_npu_pre_ndft", 3, 12), + /* CRU_GATE_CON04 */ + GATE(CLK_DDRPHY1X_SRC, "clk_ddrphy1x_src", "clk_ddrphy1x_src_c", 4, 0), + GATE(CLK_MSCH, "clk_msch", "clk_msch_div", 4, 2), + GATE(CLK24_DDRMON, "clk24_ddrmon", "xin24m", 4, 15), + /* CRU_GATE_CON05 */ + GATE(ACLK_GIC_AUDIO, "aclk_gic_audio", "aclk_gic_audio_sel", 5, 0), + GATE(HCLK_GIC_AUDIO, "hclk_gic_audio", "hclk_gic_audio_sel", 5, 1), + GATE(ACLK_GIC600, "aclk_gic600", "aclk_gic_audio", 5, 4), + GATE(ACLK_SPINLOCK, "aclk_spinlock", "aclk_gic_audio", 5, 7), + GATE(HCLK_SDMMC_BUFFER, "hclk_sdmmc_buffer", "hclk_gic_audio", 5, 8), + GATE(DCLK_SDMMC_BUFFER, "dclk_sdmmc_buffer", "dclk_sdmmc_buffer_sel", 5, 9), + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_gic_audio", 5, 10), + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_gic_audio", 5, 11), + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_gic_audio", 5, 12), + GATE(HCLK_I2S3_2CH, "hclk_i2s3_2ch", "hclk_gic_audio", 5, 13), + GATE(HCLK_PDM, "hclk_pdm", "hclk_gic_audio", 5, 14), + GATE(MCLK_PDM, "mclk_pdm", "mclk_pdm_sel", 5, 15), + /* CRU_GATE_CON06 */ + GATE(CLK_I2S0_8CH_TX_SRC, "clk_i2s0_8ch_tx_src", "clk_i2s0_8ch_tx_src_c", 6, 0), + GATE(CLK_I2S0_8CH_TX_FRAC, "clk_i2s0_8ch_tx_frac", "clk_i2s0_8ch_tx_frac_div", 6, 1), + GATE(MCLK_I2S0_8CH_TX, "mclk_i2s0_8ch_tx", "clk_i2s0_8ch_tx", 6, 2), + GATE(I2S0_MCLKOUT_TX, "i2s0_mclkout_tx", "i2s0_mclkout_tx_sel", 6, 3), + GATE(CLK_I2S0_8CH_RX_SRC, "clk_i2s0_8ch_rx_src", "clk_i2s0_8ch_rx_src_c", 6, 4), + GATE(CLK_I2S0_8CH_RX_FRAC, "clk_i2s0_8ch_rx_frac", "clk_i2s0_8ch_rx_frac_div", 6, 5), + GATE(MCLK_I2S0_8CH_RX, "mclk_i2s0_8ch_rx", "clk_i2s0_8ch_rx", 6, 6), + GATE(I2S0_MCLKOUT_RX, "i2s0_mclkout_rx", "i2s0_mclkout_rx_sel", 6, 7), + GATE(CLK_I2S1_8CH_TX_SRC, "clk_i2s1_8ch_tx_src", "clk_i2s1_8ch_tx_src_c", 6, 8), + GATE(CLK_I2S1_8CH_TX_FRAC, "clk_i2s1_8ch_tx_frac", "clk_i2s1_8ch_tx_frac_div", 6, 9), + GATE(MCLK_I2S1_8CH_TX, "mclk_i2s1_8ch_tx", "clk_i2s1_8ch_tx", 6, 10), + GATE(I2S1_MCLKOUT_TX, "i2s1_mclkout_tx", "i2s1_mclkout_tx_sel", 6, 11), + GATE(CLK_I2S1_8CH_RX_SRC, "clk_i2s1_8ch_rx_src", "clk_i2s1_8ch_rx_src_c", 6, 12), + GATE(CLK_I2S1_8CH_RX_FRAC, "clk_i2s1_8ch_rx_frac", "clk_i2s1_8ch_rx_frac_div", 6, 13), + GATE(MCLK_I2S1_8CH_RX, "mclk_i2s1_8ch_rx", "clk_i2s1_8ch_rx", 6, 14), + GATE(I2S1_MCLKOUT_RX, "i2s1_mclkout_rx", "i2s1_mclkout_rx_sel", 6, 15), + /* CRU_GATE_CON07 */ + GATE(CLK_I2S2_2CH_SRC, "clk_i2s2_2ch_src", "clk_i2s2_2ch_src_c", 7, 0), + GATE(CLK_I2S2_2CH_FRAC, "clk_i2s2_2ch_frac", "clk_i2s2_2ch_frac_div", 7, 1), + GATE(MCLK_I2S2_2CH, "mclk_i2s2_2ch", "clk_i2s2_2ch", 7, 2), + GATE(I2S2_MCLKOUT, "i2s2_mclkout", "i2s2_mclkout_sel", 7, 3), + GATE(CLK_I2S3_2CH_TX, "clk_i2s3_2ch_tx_src", "clk_i2s3_2ch_tx_src_c", 7, 4), + GATE(CLK_I2S3_2CH_TX_FRAC, "clk_i2s3_2ch_tx_frac", "clk_i2s3_2ch_tx_frac_div", 7, 5), + GATE(MCLK_I2S3_2CH_TX, "mclk_i2s3_2ch_tx", "clk_i2s3_2ch_tx", 7, 6), + GATE(I2S3_MCLKOUT_TX, "i2s3_mclkout_tx", "i2s3_mclkout_tx_sel", 7, 7), + GATE(CLK_I2S3_2CH_RX, "clk_i2s3_2ch_rx_src", "clk_i2s3_2ch_rx_src_div", 7, 8), + GATE(CLK_I2S3_2CH_RX_FRAC, "clk_i2s3_2ch_rx_frac", "clk_i2s3_2ch_rx_frac_div", 7, 9), + GATE(MCLK_I2S3_2CH_RX, "mclk_i2s3_2ch_rx", "clk_i2s3_2ch_rx", 7, 10), + GATE(I2S3_MCLKOUT_RX, "i2s3_mclkout_rx", "i2s3_mclkout_rx_sel", 7, 11), + GATE(HCLK_VAD, "hclk_vad", "hclk_gic_audio", 7, 12), + GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_gic_audio", 7, 13), + GATE(MCLK_SPDIF_8CH_SRC, "mclk_spdif_8ch_src", "mclk_spdif_8ch_src_c", 7, 14), + GATE(MCLK_SPDIF_8CH_FRAC, "mclk_spdif_8ch_frac", "mclk_spdif_8ch_frac_div", 7, 15), + /* CRU_GATE_CON08 */ + GATE(HCLK_AUDPWM, "hclk_audpwm", "hclk_gic_audio", 8, 0), + GATE(SCLK_AUDPWM_SRC, "sclk_audpwm_src", "sclk_audpwm_src_c", 8, 1), + GATE(SCLK_AUDPWM_FRAC, "sclk_audpwm_frac", "sclk_audpwm_frac_frac", 8, 2), + GATE(HCLK_ACDCDIG, "hclk_acdcdig", "hclk_gic_audio", 8, 3), + GATE(CLK_ACDCDIG_I2C, "clk_acdcdig_i2c", "clk_acdcdig_i2c_sel", 8, 4), + GATE(CLK_ACDCDIG_DAC, "clk_acdcdig_dac", "mclk_i2s3_2ch_tx", 8, 5), + GATE(CLK_ACDCDIG_ADC, "clk_acdcdig_adc", "mclk_i2s3_2ch_rx", 8, 6), + GATE(ACLK_SECURE_FLASH, "aclk_secure_flash", "aclk_secure_flash_sel", 8, 7), + GATE(HCLK_SECURE_FLASH, "hclk_secure_flash", "hclk_secure_flash_sel", 8, 8), + GATE(ACLK_CRYPTO_NS, "aclk_crypto_ns", "aclk_secure_flash", 8, 11), + GATE(HCLK_CRYPTO_NS, "hclk_crypto_ns", "hclk_secure_flash", 8, 12), + GATE(CLK_CRYPTO_NS_CORE, "clk_crypto_ns_core", "clk_crypto_ns_core_sel", 8, 13), + GATE(CLK_CRYPTO_NS_PKA, "clk_crypto_ns_pka", "clk_crypto_ns_pka_sel", 8, 14), + GATE(CLK_CRYPTO_NS_RNG, "clk_crypto_ns_rng", "hclk_secure_flash", 8, 15), + /* CRU_GATE_CON09 */ + GATE(HCLK_NANDC, "hclk_nandc", "hclk_secure_flash", 9, 0), + GATE(NCLK_NANDC, "nclk_nandc", "nclk_nandc_sel", 9, 1), + GATE(HCLK_SFC, "hclk_sfc", "hclk_secure_flash", 9, 2), + GATE(HCLK_SFC_XIP, "hclk_sfc_xip", "hclk_secure_flash", 9, 3), + GATE(SCLK_SFC, "sclk_sfc", "sclk_sfc_sel", 9, 4), + GATE(ACLK_EMMC, "aclk_emmc", "aclk_secure_flash", 9, 5), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_secure_flash", 9, 6), + GATE(BCLK_EMMC, "bclk_emmc", "bclk_emmc_sel", 9, 7), + GATE(CCLK_EMMC, "cclk_emmc", "cclk_emmc_sel", 9, 8), + GATE(TCLK_EMMC, "tclk_emmc", "xin24m", 9, 9), + GATE(HCLK_TRNG_NS, "hclk_trng_ns", "hclk_secure_flash", 9, 10), + GATE(CLK_TRNG_NS, "clk_trng_ns", "hclk_secure_flash", 9, 11), + /* CRU_GATE_CON10 */ + GATE(ACLK_PIPE, "aclk_pipe", "aclk_pipe_sel", 10, 0), + GATE(PCLK_PIPE, "pclk_pipe", "pclk_pipe_div", 10, 1), + GATE(CLK_XPCS_EEE, "clk_xpcs_eee", "clk_xpcs_eee_sel", 10, 4), + GATE(ACLK_USB3OTG0, "aclk_usb3otg0", "aclk_pipe", 10, 8), + GATE(CLK_USB3OTG0_REF, "clk_usb3otg0_ref", "xin24m", 10, 9), + GATE(CLK_USB3OTG0_SUSPEND, "clk_usb3otg0_suspend", "clk_usb3otg0_suspend_sel", 10, 10), + GATE(ACLK_USB3OTG1, "aclk_usb3otg1", "aclk_pipe", 10, 12), + GATE(CLK_USB3OTG1_REF, "clk_usb3otg1_ref", "xin24m", 10, 13), + GATE(CLK_USB3OTG1_SUSPEND, "clk_usb3otg1_suspend", "clk_usb3otg1_suspend_sel", 10, 14), + /* CRU_GATE_CON11 */ + GATE(ACLK_SATA0, "aclk_sata0", "aclk_pipe", 11, 0), + GATE(CLK_SATA0_PMALIVE, "clk_sata0_pmalive", "clk_gpll_div_20m", 11, 1), + GATE(CLK_SATA0_RXOOB, "clk_sata0_rxoob", "clk_cpll_div_50m", 11, 2), + GATE(ACLK_SATA1, "aclk_sata1", "aclk_pipe", 11, 4), + GATE(CLK_SATA1_PMALIVE, "clk_sata1_pmalive", "clk_gpll_div_20m", 11, 5), + GATE(CLK_SATA1_RXOOB, "clk_sata1_rxoob", "clk_cpll_div_50m", 11, 6), + GATE(ACLK_SATA2, "aclk_sata2", "aclk_pipe", 11, 8), + GATE(CLK_SATA2_PMALIVE, "clk_sata2_pmalive", "clk_gpll_div_20m", 11, 9), + GATE(CLK_SATA2_RXOOB, "clk_sata2_rxoob", "clk_cpll_div_50m", 11, 10), + /* CRU_GATE_CON12 */ + GATE(ACLK_PCIE20_MST, "aclk_pcie20_mst", "aclk_pipe", 12, 0), + GATE(ACLK_PCIE20_SLV, "aclk_pcie20_slv", "aclk_pipe", 12, 1), + GATE(ACLK_PCIE20_DBI, "aclk_pcie20_dbi", "aclk_pipe", 12, 2), + GATE(PCLK_PCIE20, "pclk_pcie20", "pclk_pipe", 12, 3), + GATE(CLK_PCIE20_AUX_NDFT, "clk_pcie20_aux_ndft", "xin24m", 12, 4), + GATE(ACLK_PCIE30X1_MST, "aclk_pcie30x1_mst", "aclk_pipe", 12, 8), + GATE(ACLK_PCIE30X1_SLV, "aclk_pcie30x1_slv", "aclk_pipe", 12, 9), + GATE(ACLK_PCIE30X1_DBI, "aclk_pcie30x1_dbi", "aclk_pipe", 12, 10), + GATE(PCLK_PCIE30X1, "pclk_pcie30x1", "pclk_pipe", 12, 11), + GATE(CLK_PCIE30X1_AUX_NDFT, "clk_pcie30x1_aux_ndft", "xin24m", 12, 12), + /* CRU_GATE_CON13 */ + GATE(ACLK_PCIE30X2_MST, "aclk_pcie30x2_mst", "aclk_pipe", 13, 0), + GATE(ACLK_PCIE30X2_SLV, "aclk_pcie30x2_slv", "aclk_pipe", 13, 1), + GATE(ACLK_PCIE30X2_DBI, "aclk_pcie30x2_dbi", "aclk_pipe", 13, 2), + GATE(PCLK_PCIE30X2, "pclk_pcie30x2", "pclk_pipe", 13, 3), + GATE(CLK_PCIE30X2_AUX_NDFT, "clk_pcie30x2_aux_ndft", "xin24m", 13, 4), + GATE(PCLK_XPCS, "pclk_xpcs", "pclk_pipe", 13, 6), + /* CRU_GATE_CON14 */ + GATE(ACLK_PERIMID, "aclk_perimid", "aclk_perimid_sel", 14, 0), + GATE(HCLK_PERIMID, "hclk_perimid", "hclk_perimid_sel", 14, 1), + GATE(ACLK_PHP, "aclk_php", "aclk_php_sel", 14, 8), + GATE(HCLK_PHP, "hclk_php", "hclk_php_sel", 14, 9), + GATE(PCLK_PHP, "pclk_php", "pclk_php_div", 14, 10), + /* CRU_GATE_CON15 */ + GATE(HCLK_SDMMC0, "hclk_sdmmc0", "hclk_php", 15, 0), + GATE(CLK_SDMMC0, "clk_sdmmc0", "clk_sdmmc0_sel", 15, 1), + GATE(HCLK_SDMMC1, "hclk_sdmmc1", "hclk_php", 15, 2), + GATE(CLK_SDMMC1, "clk_sdmmc1", "clk_sdmmc1_sel", 15, 3), + GATE(CLK_GMAC0_PTP_REF, "clk_gmac0_ptp_ref", "clk_gmac0_ptp_ref_sel", 15, 4), + GATE(ACLK_GMAC0, "aclk_gmac0", "aclk_php", 15, 5), + GATE(PCLK_GMAC0, "pclk_gmac0", "pclk_php", 15, 6), + GATE(CLK_MAC0_2TOP, "clk_mac0_2top", "clk_mac0_2top_sel", 15, 7), + GATE(CLK_MAC0_OUT, "clk_mac0_out", "clk_mac0_out_sel", 15, 8), + GATE(CLK_MAC0_REFOUT, "clk_mac0_refout", "clk_mac0_2top", 15, 12), + /* CRU_GATE_CON16 */ + GATE(ACLK_USB, "aclk_usb", "aclk_usb_sel", 16, 0), + GATE(HCLK_USB, "hclk_usb", "hclk_usb_sel", 16, 1), + GATE(PCLK_USB, "pclk_usb", "pclk_usb_div", 16, 2), + GATE(HCLK_USB2HOST0, "hclk_usb2host0", "hclk_usb", 16, 12), + GATE(HCLK_USB2HOST0_ARB, "hclk_usb2host0_arb", "hclk_usb", 16, 13), + GATE(HCLK_USB2HOST1, "hclk_usb2host1", "hclk_usb", 16, 14), + GATE(HCLK_USB2HOST1_ARB, "hclk_usb2host1_arb", "hclk_usb", 16, 15), + /* CRU_GATE_CON17 */ + GATE(HCLK_SDMMC2, "hclk_sdmmc2", "hclk_usb", 17, 0), + GATE(CLK_SDMMC2, "clk_sdmmc2", "clk_sdmmc2_sel", 17, 1), + GATE(CLK_GMAC1_PTP_REF, "clK_gmac1_ptp_ref", "clk_gmac1_ptp_ref_sel", 17, 2), + GATE(ACLK_GMAC1, "aclk_gmac1", "aclk_usb", 17, 3), + GATE(PCLK_GMAC1, "pclk_gmac1", "pclk_usb", 17, 4), + GATE(CLK_MAC1_2TOP, "clk_mac1_2top", "clk_mac1_2top_sel", 17, 5), + GATE(CLK_MAC1_OUT, "clk_mac1_out", "clk_mac1_out_sel", 17, 6), + GATE(CLK_MAC1_REFOUT, "clk_mac1_refout", "clk_mac1_2top", 17, 10), + /* CRU_GATE_CON18 */ + GATE(ACLK_VI, "aclk_vi", "aclk_vi_sel", 18, 0), + GATE(HCLK_VI, "hclk_vi", "hclk_vi_div", 18, 1), + GATE(PCLK_VI, "pclk_vi", "pclk_vi_div", 18, 2), + GATE(ACLK_VICAP, "aclk_vicap", "aclk_vi", 18, 9), + GATE(HCLK_VICAP, "hclk_vicap", "hclk_vi", 18, 10), + GATE(DCLK_VICAP, "dclk_vicap", "dclk_vicap1_sel", 18, 11), + /* CRU_GATE_CON19 */ + GATE(ACLK_ISP, "aclk_isp", "aclk_vi", 19, 0), + GATE(HCLK_ISP, "hclk_isp", "hclk_vi", 19, 1), + GATE(CLK_ISP, "clk_isp", "clk_isp_c", 19, 2), + GATE(PCLK_CSI2HOST1, "pclk_csi2host1", "pclk_vi", 19, 4), + GATE(CLK_CIF_OUT, "clk_cif_out", "clk_cif_out_c", 19, 8), + GATE(CLK_CAM0_OUT, "clk_cam0_out", "clk_cam0_out_c", 19, 9), + GATE(CLK_CAM1_OUT, "clk_cam1_out", "clk_cam1_out_c", 19, 9), + /* CRU_GATE_CON20 */ + GATE(ACLK_VO, "aclk_vo", "aclk_vo_sel", 20, 0), + GATE(HCLK_VO, "hclk_vo", "hclk_vo_div", 20, 1), + GATE(PCLK_VO, "pclk_vo", "pclk_vo_div", 20, 2), + GATE(ACLK_VOP_PRE, "aclk_vop_pre", "aclk_vop_pre_c", 20, 6), + GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 20, 8), + GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 20, 9), + GATE(DCLK_VOP0, "dclk_vop0", "dclk_vop0_c", 20, 10), + GATE(DCLK_VOP1, "dclk_vop1", "dclk_vop1_c", 20, 11), + GATE(DCLK_VOP2, "dclk_vop2", "dclk_vop2_c", 20, 12), + GATE(CLK_VOP_PWM, "clk_vop_pwm", "xin24m", 20, 13), + /* CRU_GATE_CON21 */ + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vo", 21, 0), + GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vo", 21, 1), + GATE(PCLK_HDCP, "pclk_hdcp", "pclk_vo", 21, 2), + GATE(PCLK_HDMI_HOST, "pclk_hdmi_host", "pclk_vo", 21, 3), + GATE(CLK_HDMI_SFR, "clk_hdmi_sfr", "xin24m", 21, 4), + GATE(CLK_HDMI_CEC, "clk_hdmi_cec", "clk_rtc_32k", 21, 5), + GATE(PCLK_DSITX_0, "pclk_dsitx_0", "pclk_vo", 21, 6), + GATE(PCLK_DSITX_1, "pclk_dsitx_1", "pclk_vo", 21, 7), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "pclk_vo", 21, 8), + GATE(CLK_EDP_200M, "clk_edp_200m", "clk_edp_200m_sel", 21, 9), + /* CRU_GATE_CON22 */ + GATE(ACLK_VPU_PRE, "aclk_vpu_pre", "aclk_vpu_pre_c", 22, 0), + GATE(HCLK_VPU_PRE, "hclk_vpu_pre", "aclk_vpu_pre_c", 22, 1), + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 22, 4), + GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 22, 5), + GATE(PCLK_RGA_PRE, "pclk_rga_pre", "pclk_rga_pre_div", 22, 12), + GATE(PCLK_EINK, "pclk_eink", "pclk_rga_pre", 22, 14), + GATE(HCLK_EINK, "hclk_eink", "hclk_rga_pre", 22, 15), + /* CRU_GATE_CON23 */ + GATE(ACLK_RGA_PRE, "aclk_rga_pre", "aclk_rga_pre_sel", 23, 0), + GATE(HCLK_RGA_PRE, "hclk_rga_pre", "hclk_rga_pre_div", 23, 1), + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 23, 4), + GATE(HCLK_RGA, "hclk_rga", "hclk_rga_pre", 23, 5), + GATE(CLK_RGA_CORE, "clk_rga_core", "clk_rga_core_sel", 23, 6), + GATE(ACLK_IEP, "aclk_iep", "aclk_rga_pre", 23, 7), + GATE(HCLK_IEP, "hclk_iep", "hclk_rga_pre", 23, 8), + GATE(CLK_IEP_CORE, "clk_iep_core", "clk_iep_core_sel", 23, 9), + GATE(HCLK_EBC, "hclk_ebc", "hclk_rga_pre", 23, 10), + GATE(DCLK_EBC, "dclk_ebc", "dclk_ebc_sel", 23, 11), + GATE(ACLK_JDEC, "aclk_jdec", "aclk_rga_pre", 23, 12), + GATE(HCLK_JDEC, "hclk_jdec", "hclk_rga_pre", 23, 13), + GATE(ACLK_JENC, "aclk_jenc", "aclk_rga_pre", 23, 14), + GATE(HCLK_JENC, "hclk_jenc", "hclk_rga_pre", 23, 15), + /* CRU_GATE_CON24 */ + GATE(ACLK_RKVENC_PRE, "aclk_rkvenc_pre", "aclk_rkvenc_pre_c", 24, 0), + GATE(HCLK_RKVENC_PRE, "hclk_rkvenc_pre", "hclk_rkvenc_pre_div", 24, 1), + GATE(ACLK_RKVENC, "aclk_rkvenc", "aclk_rkvenc_pre", 24, 6), + GATE(HCLK_RKVENC, "hclk_rkvenc", "hclk_rkvenc_pre", 24, 7), + GATE(CLK_RKVENC_CORE, "clk_rkvenc_core", "clk_rkvenc_core_c", 24, 8), + GATE(ACLK_RKVDEC_PRE, "aclk_rkvdec_pre", "aclk_rkvdec_pre_c", 25, 0), + /* CRU_GATE_CON25 */ + GATE(HCLK_RKVDEC_PRE, "hclk_rkvdec_pre", "hclk_rkvdec_pre_div", 25, 1), + GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 25, 4), + GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 25, 5), + GATE(CLK_RKVDEC_CA, "clk_rkvdec_ca", "clk_rkvdec_ca_c", 25, 6), + GATE(CLK_RKVDEC_CORE, "clk_rkvdec_core", "clk_rkvdec_core_c", 25, 7), + GATE(CLK_RKVDEC_HEVC_CA, "clk_rkvdec_hevc_ca", "clk_rkvdec_hevc_ca_c", 25, 8), + /* CRU_GATE_CON26 */ + GATE(ACLK_BUS, "aclk_bus", "aclk_bus_sel", 26, 0), + GATE(PCLK_BUS, "pclk_bus", "pclk_bus_sel", 26, 1), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 26, 4), + GATE(CLK_TSADC_TSEN, "clk_tsadc_tsen", "clk_tsadc_tsen_c", 26, 5), + GATE(CLK_TSADC, "clk_tsadc", "clk_tsadc_div", 26, 6), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 26, 7), + GATE(CLK_SARADC, "clk_saradc", "xin24m", 26, 8), + GATE(PCLK_OTPC_NS, "pclk_otpc_ns", "hclk_secure_flash", 26, 9), + GATE(CLK_OTPC_NS_SBPI, "clk_otpc_ns_sbpi", "xin24m", 26, 10), + GATE(CLK_OTPC_NS_USR, "clk_otpc_ns_usr", "xin_osc0_half", 26, 11), + GATE(PCLK_SCR, "pclk_scr", "pclk_bus", 26, 12), + GATE(PCLK_WDT_NS, "pclk_wdt_ns", "pclk_bus", 26, 13), + GATE(TCLK_WDT_NS, "tclk_wdt_ns", "xin24m", 26, 14), + /* CRU_GATE_CON27 */ + GATE(PCLK_CAN0, "pclk_can0", "pclk_bus", 27, 5), + GATE(CLK_CAN0, "clk_can0", "clk_can0_c", 27, 6), + GATE(PCLK_CAN1, "pclk_can1", "pclk_bus", 27, 7), + GATE(CLK_CAN1, "clk_can1", "clk_can1_c", 27, 8), + GATE(PCLK_CAN2, "pclk_can2", "pclk_bus", 27, 9), + GATE(CLK_CAN2, "clk_can2", "clk_can2_c", 27, 10), + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 27, 12), + GATE(CLK_UART1_SRC, "clk_uart1_src", "clk_uart1_src_c", 27, 13), + GATE(CLK_UART1_FRAC, "clk_uart1_frac", "clk_uart1_frac_frac", 27, 14), + GATE(SCLK_UART1, "sclk_uart1", "sclk_uart1_sel", 27, 15), + /* CRU_GATE_CON28 */ + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 28, 0), + GATE(CLK_UART2_SRC, "clk_uart2_src", "clk_uart2_src_c", 28, 1), + GATE(CLK_UART2_FRAC, "clk_uart2_frac", "clk_uart2_frac_frac", 28, 2), + GATE(SCLK_UART2, "sclk_uart2", "sclk_uart2_sel", 28, 3), + GATE(PCLK_UART3, "pclk_uart3", "pclk_bus", 28, 4), + GATE(CLK_UART3_SRC, "clk_uart3_src", "clk_uart3_src_c", 28, 5), + GATE(CLK_UART3_FRAC, "clk_uart3_frac", "clk_uart3_frac_frac", 28, 6), + GATE(SCLK_UART3, "sclk_uart3", "sclk_uart3_sel", 28, 7), + GATE(PCLK_UART4, "pclk_uart4", "pclk_bus", 28, 8), + GATE(CLK_UART4_SRC, "clk_uart4_src", "clk_uart4_src_c", 28, 9), + GATE(CLK_UART4_FRAC, "clk_uart4_frac", "clk_uart4_frac_frac", 28, 10), + GATE(SCLK_UART4, "sclk_uart4", "sclk_uart4_sel", 28, 11), + GATE(PCLK_UART5, "pclk_uart5", "pclk_bus", 28, 12), + GATE(CLK_UART5_SRC, "clk_uart5_src", "clk_uart5_src_c", 28, 13), + GATE(CLK_UART5_FRAC, "clk_uart5_frac", "clk_uart5_frac_frac", 28, 14), + GATE(SCLK_UART5, "sclk_uart5", "sclk_uart5_sel", 28, 15), + /* CRU_GATE_CON29 */ + GATE(PCLK_UART6, "pclk_uart6", "pclk_bus", 29, 0), + GATE(CLK_UART6_SRC, "clk_uart6_src", "clk_uart6_src_c", 29, 1), + GATE(CLK_UART6_FRAC, "clk_uart6_frac", "clk_uart6_frac_frac", 29, 2), + GATE(SCLK_UART6, "sclk_uart6", "sclk_uart6_sel", 29, 3), + GATE(PCLK_UART7, "pclk_uart7", "pclk_bus", 29, 4), + GATE(CLK_UART7_SRC, "clk_uart7_src", "clk_uart7_src_c", 29, 5), + GATE(CLK_UART7_FRAC, "clk_uart7_frac", "clk_uart7_frac_frac", 29, 6), + GATE(SCLK_UART7, "sclk_uart7", "sclk_uart7_sel", 29, 7), + GATE(PCLK_UART8, "pclk_uart8", "pclk_bus", 29, 8), + GATE(CLK_UART8_SRC, "clk_uart8_src", "clk_uart8_src_c", 29, 9), + GATE(CLK_UART8_FRAC, "clk_uart8_frac", "clk_uart8_frac_frac", 29, 10), + GATE(SCLK_UART8, "sclk_uart8", "sclk_uart8_sel", 29, 11), + GATE(PCLK_UART9, "pclk_uart9", "pclk_bus", 29, 12), + GATE(CLK_UART9_SRC, "clk_uart9_src", "clk_uart9_src_c", 29, 13), + GATE(CLK_UART9_FRAC, "clk_uart9_frac", "clk_uart9_frac_frac", 29, 14), + GATE(SCLK_UART9, "sclk_uart9", "sclk_uart9_sel", 29, 15), + /* CRU_GATE_CON30 */ + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 30, 0), + GATE(CLK_I2C1, "clk_i2c1", "clk_i2c", 30, 1), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 30, 2), + GATE(CLK_I2C2, "clk_i2c2", "clk_i2c", 30, 3), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 30, 4), + GATE(CLK_I2C3, "clk_i2c3", "clk_i2c", 30, 5), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_bus", 30, 6), + GATE(CLK_I2C4, "clk_i2c4", "clk_i2c", 30, 7), + GATE(PCLK_I2C5, "pclk_i2c5", "pclk_bus", 30, 8), + GATE(CLK_I2C5, "clk_i2c5", "clk_i2c", 30, 9), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_bus", 30, 10), + GATE(CLK_SPI0, "clk_spi0", "clk_spi0_sel", 30, 11), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_bus", 30, 12), + GATE(CLK_SPI1, "clk_spi1", "clk_spi1_sel", 30, 13), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_bus", 30, 14), + GATE(CLK_SPI2, "clk_spi2", "clk_spi2_sel", 30, 15), + /* CRU_GATE_CON31 */ + GATE(PCLK_SPI3, "pclk_spi3", "pclk_bus", 31, 0), + GATE(CLK_SPI3, "clk_spi3", "clk_spi3_sel", 31, 1), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 31, 2), + GATE(DBCLK_GPIO1, "dbclk_gpio1", "dbclk_gpio", 31, 3), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 31, 4), + GATE(DBCLK_GPIO2, "dbclk_gpio2", "dbclk_gpio", 31, 5), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 31, 6), + GATE(DBCLK_GPIO3, "dbclk_gpio3", "dbclk_gpio", 31, 7), + GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_bus", 31, 8), + GATE(DBCLK_GPIO4, "dbclk_gpio4", "dbclk_gpio", 31, 9), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 31, 10), + GATE(CLK_PWM1, "clk_pwm1", "clk_pwm1_sel", 31, 11), + GATE(CLK_PWM1_CAPTURE, "clk_pwm1_capture", "xin24m", 31, 12), + GATE(PCLK_PWM2, "pclk_pwm2", "pclk_bus", 31, 13), + GATE(CLK_PWM2, "clk_pwm2", "clk_pwm2_sel", 31, 14), + GATE(CLK_PWM2_CAPTURE, "clk_pwm2_capture", "xin24m", 31, 15), + /* CRU_GATE_CON32 */ + GATE(PCLK_PWM3, "pclk_pwm3", "pclk_bus", 32, 0), + GATE(CLK_PWM3, "clk_pwm3", "clk_pwm3_sel", 32, 1), + GATE(CLK_PWM3_CAPTURE, "clk_pwm3_capture", "xin24m", 32, 2), + GATE(PCLK_TIMER, "pclk_timer", "pclk_bus", 32, 3), + GATE(CLK_TIMER0, "clk_timer0", "xin24m", 32, 4), + GATE(CLK_TIMER1, "clk_timer1", "xin24m", 32, 5), + GATE(CLK_TIMER2, "clk_timer2", "xin24m", 32, 6), + GATE(CLK_TIMER3, "clk_timer3", "xin24m", 32, 7), + GATE(CLK_TIMER4, "clk_timer4", "xin24m", 32, 8), + GATE(CLK_TIMER5, "clk_timer5", "xin24m", 32, 9), + GATE(CLK_I2C, "clk_i2c", "clk_i2c_sel", 32, 10), + GATE(DBCLK_GPIO, "dbclk_gpio", "dbclk_gpio_sel", 32, 11), + GATE(ACLK_MCU, "aclk_mcu", "aclk_bus", 32, 13), + GATE(PCLK_INTMUX, "pclk_intmux", "pclk_bus", 32, 14), + GATE(PCLK_MAILBOX, "pclk_mailbox", "pclk_bus", 32, 15), + /* CRU_GATE_CON33 */ + GATE(ACLK_TOP_HIGH, "aclk_top_high", "aclk_top_high_sel", 33, 0), + GATE(ACLK_TOP_LOW, "aclk_top_low", "aclk_top_low_sel", 33, 1), + GATE(HCLK_TOP, "hclk_top", "hclk_top_sel", 33, 2), + GATE(PCLK_TOP, "pclk_top", "pclk_top_sel", 33, 3), + GATE(PCLK_PCIE30PHY, "pclk_pcie30phy", "pclk_top", 33, 8), + GATE(CLK_OPTC_ARB, "clk_optc_arb", "clk_optc_arb_sel", 33, 9), + GATE(PCLK_MIPICSIPHY, "pclk_mipicsiphy", "pclk_top", 33, 13), + GATE(PCLK_MIPIDSIPHY0, "pclk_mipidsiphy0", "pclk_top", 33, 14), + GATE(PCLK_MIPIDSIPHY1, "pclk_mipidsiphy1", "pclk_top", 33, 15), + /* CRU_GATE_CON34 */ + GATE(PCLK_PIPEPHY0, "pclk_pipephy0", "pclk_top", 34, 4), + GATE(PCLK_PIPEPHY1, "pclk_pipephy1", "pclk_top", 34, 5), + GATE(PCLK_PIPEPHY2, "pclk_pipephy2", "pclk_top", 34, 6), + GATE(PCLK_CPU_BOOST, "pclk_cpu_boost", "pclk_top", 34, 11), + GATE(CLK_CPU_BOOST, "clk_cpu_boost", "xin24m", 34, 12), + GATE(PCLK_OTPPHY, "pclk_otpphy", "pclk_top", 34, 13), + GATE(PCLK_EDPPHY_GRF, "pclk_edpphy_grf", "pclk_top", 34, 14), + /* CRU_GATE_CON35 */ + GATE(CPLL_500M, "clk_cpll_div_500m", "clk_cpll_div_500m_div", 35, 7), + GATE(CPLL_333M, "clk_cpll_div_333m", "clk_cpll_div_333m_div", 35, 8), + GATE(CPLL_250M, "clk_cpll_div_250m", "clk_cpll_div_250m_div", 35, 9), + GATE(CPLL_125M, "clk_cpll_div_125m", "clk_cpll_div_125m_div", 35, 10), + GATE(CPLL_100M, "clk_cpll_div_100m", "clk_cpll_div_100m_div", 35, 11), + GATE(CPLL_62P5M, "clk_cpll_div_62P5m", "clk_cpll_div_62P5m_div", 35, 12), + GATE(CPLL_50M, "clk_cpll_div_50m", "clk_cpll_div_50m_div", 35, 13), + GATE(CPLL_25M, "clk_cpll_div_25m", "clk_cpll_div_25m_div", 35, 14), +}; + +static struct rk_clk_gate pmu_clk_gates[] = +{ + /* PMUCRU_PMUGATE_CON00 */ + GATE(XIN_OSC0_DIV, "xin_osc0_div", "xin_osc0_div_div", 0, 0), + GATE(CLK_RTC_32K, "clk_rtc_32k", "clk_rtc_32k_mux", 0, 1), + GATE(PCLK_PDPMU, "pclk_pdpmu", "pclk_pdpmu_pre", 0, 2), + GATE(PCLK_PMU, "pclk_pmu", "pclk_pdpmu", 0, 6), + GATE(CLK_PMU, "clk_pmu", "xin24m", 0, 7), + /* PMUCRU_PMUGATE_CON01 */ + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_pdpmu", 1, 0), + GATE(CLK_I2C0, "clk_i2c0", "clk_i2c0_div", 1, 1), + GATE(PCLK_UART0, "pclk_uart0", "pclk_pdpmu", 1, 2), + GATE(CLK_UART0_DIV, "sclk_uart0_div", "sclk_uart0_div_div", 1, 3), + GATE(CLK_UART0_FRAC, "sclk_uart0_frac", "sclk_uart0_frac_div", 1, 4), + GATE(SCLK_UART0, "sclk_uart0", "sclk_uart0_mux", 1, 5), + GATE(PCLK_PWM0, "pclk_pwm0", "pclk_pdpmu", 1, 6), + GATE(CLK_PWM0, "clk_pwm0", "clk_pwm0_div", 1, 7), + GATE(CLK_CAPTURE_PWM0_NDFT, "clk_capture_pwm0_ndft", "xin24m", 1, 8), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pdpmu", 1, 9), + GATE(DBCLK_GPIO0, "dbclk_gpio0", "dbclk_gpio0_sel", 1, 10), + GATE(PCLK_PMUPVTM, "pclk_pmupvtm", "pclk_pdpmu", 1, 11), + GATE(CLK_PMUPVTM, "clk_pmupvtm", "xin24m", 1, 12), + GATE(CLK_CORE_PMUPVTM, "clk_core_pmupvtm", "xin24m", 1, 13), + /* PMUCRU_PMUGATE_CON02 */ + GATE(CLK_REF24M, "clk_ref24m", "clk_ref24m_div", 2, 0), + GATE(XIN_OSC0_USBPHY0_G, "xin_osc0_usbphy0_g", "xin24m", 2, 1), + GATE(XIN_OSC0_USBPHY1_G, "xin_osc0_usbphy1_g", "xin24m", 2, 2), + GATE(XIN_OSC0_MIPIDSIPHY0_G, "xin_osc0_mipidsiphy0_g", "xin24m", 2, 3), + GATE(XIN_OSC0_MIPIDSIPHY1_G, "xin_osc0_mipidsiphy1_g", "xin24m", 2, 4), + GATE(CLK_WIFI_DIV, "clk_wifi_div", "clk_wifi_div_div", 2, 5), + GATE(CLK_WIFI_OSC0, "clk_wifi_osc0", "xin24m", 2, 6), + GATE(CLK_PCIEPHY0_DIV, "clk_pciephy0_div", "clk_pciephy0_div_div", 2, 7), + GATE(CLK_PCIEPHY0_OSC0, "clk_pciephy0_osc0", "xin24m", 2, 8), + GATE(CLK_PCIEPHY1_DIV, "clk_pciephy1_div", "clk_pciephy1_div_div", 2, 9), + GATE(CLK_PCIEPHY1_OSC0, "clk_pciephy1_osc0", "xin24m", 2, 10), + GATE(CLK_PCIEPHY2_DIV, "clk_pciephy2_div", "clk_pciephy2_div_div", 2, 11), + GATE(CLK_PCIEPHY2_OSC0, "clk_pciephy2_osc0", "xin24m", 2, 12), + GATE(CLK_PCIE30PHY_REF_M, "clk_pcie30phy_ref_m", "ppll_ph0", 2, 13), + GATE(CLK_PCIE30PHY_REF_N, "clk_pcie30phy_ref_n", "ppll_ph180", 2, 14), + GATE(XIN_OSC0_EDPPHY_G, "xin_osc0_edpphy_g", "xin24m", 2, 15), +}; + +#define PLL_MODE_MASK 0x1 +#include "clk-pll.c" +#include "softrst.c" + +static struct rk_pmuclk_priv *find_pmu(void) +{ + struct rk_pmuclk_priv *pmu_priv = RT_NULL; + const char *compatible = "rockchip,rk3568-pmucru"; + struct rt_ofw_node *np = rt_ofw_find_node_by_compatible(RT_NULL, compatible); + + if (np) + { + struct rk_clk *rk_clk = rt_ofw_data(np); + + pmu_priv = &rk_clk->pmuclk_info; + rt_ofw_node_put(np); + } + else + { + LOG_E("Find pmucru %s fail", compatible); + } + + return pmu_priv; +} + +static rt_ubase_t pmu_pll_set_rate(rt_ubase_t pll_id, rt_ubase_t rate) +{ + struct rk_pmuclk_priv *pmu_priv = find_pmu(); + + if (pmu_priv) + { + rk_pll_set_rate(&pmu_pll_clks[pll_id], pmu_priv->pmucru, rate); + } + + return 0; +} + +static rt_ubase_t pmu_pll_get_rate(rt_ubase_t pll_id) +{ + struct rk_pmuclk_priv *pmu_priv = find_pmu(); + + if (pmu_priv) + { + return rk_pll_get_rate(&pmu_pll_clks[pll_id], &pmu_priv->pmucru); + } + + return 0; +} + +static rt_ubase_t rtc32k_get_pmuclk(struct rk_pmuclk_priv *priv) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_ubase_t m, n; + rt_uint32_t fracdiv; + + fracdiv = HWREG32(&pmucru->pmu_clksel_con[1]); + m = fracdiv & RTC32K_FRAC_NUMERATOR_MASK; + m >>= RTC32K_FRAC_NUMERATOR_SHIFT; + n = fracdiv & RTC32K_FRAC_DENOMINATOR_MASK; + n >>= RTC32K_FRAC_DENOMINATOR_SHIFT; + + return OSC_HZ * m / n; +} + +static rt_ubase_t rtc32k_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t rate) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_ubase_t m, n, val; + + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT); + + rational_best_approximation(rate, OSC_HZ, RT_GENMASK(16 - 1, 0), RT_GENMASK(16 - 1, 0), &m, &n); + val = m << RTC32K_FRAC_NUMERATOR_SHIFT | n; + HWREG32(&pmucru->pmu_clksel_con[1]) = val; + + return rtc32k_get_pmuclk(priv); +} + +static rt_ubase_t uart_get_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_uint32_t reg, con, fracdiv, div, src, p_src, p_rate; + rt_ubase_t m, n; + + switch (clk_id) + { + case SCLK_UART0: + reg = 4; + break; + default: + return -RT_ERROR; + } + + con = HWREG32(&pmucru->pmu_clksel_con[reg]); + src = (con & CLK_UART0_SEL_MASK) >> CLK_UART0_SEL_SHIFT; + div = (con & CLK_UART0_DIV_DIV_MASK) >> CLK_UART0_DIV_DIV_SHIFT; + p_src = (con & CLK_UART0_DIV_SEL_MASK) >> CLK_UART0_DIV_SEL_SHIFT; + + if (p_src == CLK_UART0_SRC_SEL_PPLL) + { + p_rate = priv->ppll_hz; + } + else if (p_src == CLK_UART0_SRC_SEL_GPLL) + { + p_rate = priv->hpll_hz; + } + else + { + p_rate = 480000000; + } + if (src == CLK_UART0_SEL_DIV) + { + return DIV_TO_RATE(p_rate, div); + } + else if (src == CLK_UART0_SEL_FRACDIV) + { + fracdiv = HWREG32(&pmucru->pmu_clksel_con[reg + 1]); + n = fracdiv & CLK_UART0_FRAC_NUMERATOR_MASK; + n >>= CLK_UART0_FRAC_NUMERATOR_SHIFT; + m = fracdiv & CLK_UART0_FRAC_DENOMINATOR_MASK; + m >>= CLK_UART0_FRAC_DENOMINATOR_SHIFT; + return DIV_TO_RATE(p_rate, div) * n / m; + } + else + { + return OSC_HZ; + } +} + +static rt_ubase_t uart_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_uint32_t reg, clk_src, uart_src, div; + rt_ubase_t m = 0, n = 0, val; + + if (priv->ppll_hz % rate == 0) + { + clk_src = CLK_UART0_SRC_SEL_PPLL; + uart_src = CLK_UART0_SEL_DIV; + div = RT_DIV_ROUND_UP(priv->ppll_hz, rate); + } + else if (priv->hpll_hz % rate == 0) + { + clk_src = CLK_UART0_SRC_SEL_GPLL; + uart_src = CLK_UART0_SEL_DIV; + div = RT_DIV_ROUND_UP(priv->hpll_hz, rate); + } + else if (rate == OSC_HZ) + { + clk_src = CLK_UART0_SRC_SEL_GPLL; + uart_src = CLK_UART0_SEL_XIN24M; + div = 2; + } + + switch (clk_id) + { + case SCLK_UART0: + reg = 4; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&pmucru->pmu_clksel_con[reg], CLK_UART0_SEL_MASK | CLK_UART0_DIV_SEL_MASK | CLK_UART0_DIV_DIV_MASK, + (clk_src << CLK_UART0_DIV_SEL_SHIFT) | (uart_src << CLK_UART0_SEL_SHIFT) | + ((div - 1) << CLK_UART0_DIV_DIV_SHIFT)); + if (m && n) + { + val = m << CLK_UART0_FRAC_NUMERATOR_SHIFT | n; + HWREG32(&pmucru->pmu_clksel_con[reg + 1]) = val; + } + + return uart_get_pmuclk(priv, clk_id); +} + +static rt_ubase_t i2c_get_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_uint32_t div, con; + + switch (clk_id) + { + case CLK_I2C0: + con = HWREG32(&pmucru->pmu_clksel_con[3]); + div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT; + break; + default: + return -RT_ERROR; + } + + return DIV_TO_RATE(priv->ppll_hz, div); +} + +static rt_ubase_t i2c_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_pmucru *pmucru = priv->pmucru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->ppll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 127); + + switch (clk_id) + { + case CLK_I2C0: + rk_clrsetreg(&pmucru->pmu_clksel_con[3], CLK_I2C0_DIV_MASK, (src_clk_div - 1) << CLK_I2C0_DIV_SHIFT); + break; + default: + return -RT_ERROR; + } + + return i2c_get_pmuclk(priv, clk_id); +} + +static rt_ubase_t pwm_get_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_uint32_t div, sel, con, parent; + + switch (clk_id) + { + case CLK_PWM0: + con = HWREG32(&pmucru->pmu_clksel_con[6]); + sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT; + div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT; + if (sel == CLK_PWM0_SEL_XIN24M) + { + parent = OSC_HZ; + } + else + { + parent = priv->ppll_hz; + } + break; + default: + return -RT_ERROR; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_ubase_t pwm_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_pmucru *pmucru = priv->pmucru; + int src_clk_div; + + switch (clk_id) + { + case CLK_PWM0: + if (rate == OSC_HZ) + { + rk_clrsetreg(&pmucru->pmu_clksel_con[6], CLK_PWM0_SEL_MASK | CLK_PWM0_DIV_MASK, + (CLK_PWM0_SEL_XIN24M << CLK_PWM0_SEL_SHIFT) | 0 << CLK_PWM0_SEL_SHIFT); + } + else + { + src_clk_div = RT_DIV_ROUND_UP(priv->ppll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 127); + rk_clrsetreg(&pmucru->pmu_clksel_con[6], CLK_PWM0_DIV_MASK | CLK_PWM0_DIV_MASK, + (CLK_PWM0_SEL_PPLL << CLK_PWM0_SEL_SHIFT) | (src_clk_div - 1) << CLK_PWM0_DIV_SHIFT); + } + break; + default: + return -RT_ERROR; + } + + return pwm_get_pmuclk(priv, clk_id); +} + +static int armclk_set_clk(struct rk_clk_priv *priv, rt_ubase_t hz) +{ + struct rk_cru *cru = priv->cru; + const struct rk_cpu_rate_table *rate; + rt_ubase_t old_rate; + + rate = rk_get_cpu_settings(cpu_rates, hz); + if (!rate) + { + LOG_E("Unsupport rate %u", hz); + + return -RT_ENOSYS; + } + + rk_clrsetreg(&cru->clksel_con[0], CLK_CORE_PRE_SEL_MASK, (CLK_CORE_PRE_SEL_SRC << CLK_CORE_PRE_SEL_SHIFT)); + rk_clrsetreg(&cru->clksel_con[2], + SCLK_CORE_PRE_SEL_MASK | SCLK_CORE_SRC_SEL_MASK | SCLK_CORE_SRC_DIV_MASK, + (SCLK_CORE_PRE_SEL_SRC << SCLK_CORE_PRE_SEL_SHIFT) | + (SCLK_CORE_SRC_SEL_APLL <cru); + if (old_rate > hz) + { + if (rk_pll_set_rate(&pll_clks[apll], priv->cru, hz)) + { + return -RT_ENOSYS; + } + rk_clrsetreg(&cru->clksel_con[3], GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK, + rate->pclk_div << GICCLK_CORE_DIV_SHIFT | rate->pclk_div << ATCLK_CORE_DIV_SHIFT); + rk_clrsetreg(&cru->clksel_con[4], PERIPHCLK_CORE_PRE_DIV_MASK | PCLK_CORE_PRE_DIV_MASK, + rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT | rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT); + rk_clrsetreg(&cru->clksel_con[5], ACLK_CORE_NDFT_DIV_MASK, rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT); + } + else if (old_rate < hz) + { + rk_clrsetreg(&cru->clksel_con[3], GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK, + rate->pclk_div << GICCLK_CORE_DIV_SHIFT | rate->pclk_div << ATCLK_CORE_DIV_SHIFT); + rk_clrsetreg(&cru->clksel_con[4], PERIPHCLK_CORE_PRE_DIV_MASK | PCLK_CORE_PRE_DIV_MASK, + rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT | rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT); + rk_clrsetreg(&cru->clksel_con[5], ACLK_CORE_NDFT_DIV_MASK, rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT); + + if (rk_pll_set_rate(&pll_clks[apll], priv->cru, hz)) + { + return -RT_ENOSYS; + } + } + + return 0; +} + +static rt_ubase_t cpll_div_get_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + int div, mask, shift, con; + + switch (clk_id) + { + case CPLL_500M: + con = 78; + mask = CPLL_500M_DIV_MASK; + shift = CPLL_500M_DIV_SHIFT; + break; + case CPLL_333M: + con = 79; + mask = CPLL_333M_DIV_MASK; + shift = CPLL_333M_DIV_SHIFT; + break; + case CPLL_250M: + con = 79; + mask = CPLL_250M_DIV_MASK; + shift = CPLL_250M_DIV_SHIFT; + break; + case CPLL_125M: + con = 80; + mask = CPLL_125M_DIV_MASK; + shift = CPLL_125M_DIV_SHIFT; + break; + case CPLL_100M: + con = 82; + mask = CPLL_100M_DIV_MASK; + shift = CPLL_100M_DIV_SHIFT; + break; + case CPLL_62P5M: + con = 80; + mask = CPLL_62P5M_DIV_MASK; + shift = CPLL_62P5M_DIV_SHIFT; + break; + case CPLL_50M: + con = 81; + mask = CPLL_50M_DIV_MASK; + shift = CPLL_50M_DIV_SHIFT; + break; + case CPLL_25M: + con = 81; + mask = CPLL_25M_DIV_MASK; + shift = CPLL_25M_DIV_SHIFT; + break; + default: + return -RT_ERROR; + } + + div = (HWREG32(&cru->clksel_con[con]) & mask) >> shift; + return DIV_TO_RATE(priv->cpll_hz, div); +} + +static rt_ubase_t cpll_div_set_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int div, mask, shift, con; + + switch (clk_id) + { + case CPLL_500M: + con = 78; + mask = CPLL_500M_DIV_MASK; + shift = CPLL_500M_DIV_SHIFT; + break; + case CPLL_333M: + con = 79; + mask = CPLL_333M_DIV_MASK; + shift = CPLL_333M_DIV_SHIFT; + break; + case CPLL_250M: + con = 79; + mask = CPLL_250M_DIV_MASK; + shift = CPLL_250M_DIV_SHIFT; + break; + case CPLL_125M: + con = 80; + mask = CPLL_125M_DIV_MASK; + shift = CPLL_125M_DIV_SHIFT; + break; + case CPLL_100M: + con = 82; + mask = CPLL_100M_DIV_MASK; + shift = CPLL_100M_DIV_SHIFT; + break; + case CPLL_62P5M: + con = 80; + mask = CPLL_62P5M_DIV_MASK; + shift = CPLL_62P5M_DIV_SHIFT; + break; + case CPLL_50M: + con = 81; + mask = CPLL_50M_DIV_MASK; + shift = CPLL_50M_DIV_SHIFT; + break; + case CPLL_25M: + con = 81; + mask = CPLL_25M_DIV_MASK; + shift = CPLL_25M_DIV_SHIFT; + break; + default: + return -RT_ERROR; + } + + div = RT_DIV_ROUND_UP(priv->cpll_hz, rate); + RT_ASSERT(div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift); + + return cpll_div_get_rate(priv, clk_id); +} + +static rt_ubase_t bus_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, sel, rate; + + switch (clk_id) + { + case ACLK_BUS: + con = HWREG32(&cru->clksel_con[50]); + sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT; + + if (sel == ACLK_BUS_SEL_200M) + { + rate = 200 * MHZ; + } + else if (sel == ACLK_BUS_SEL_150M) + { + rate = 150 * MHZ; + } + else if (sel == ACLK_BUS_SEL_100M) + { + rate = 100 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + case PCLK_BUS: + case PCLK_WDT_NS: + con = HWREG32(&cru->clksel_con[50]); + sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT; + if (sel == PCLK_BUS_SEL_100M) + { + rate = 100 * MHZ; + } + else if (sel == PCLK_BUS_SEL_75M) + { + rate = 75 * MHZ; + } + else if (sel == PCLK_BUS_SEL_50M) + { + rate = 50 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + default: + return -RT_ERROR; + } + + return rate; +} + +static rt_ubase_t bus_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (clk_id) + { + case ACLK_BUS: + if (rate == 200 * MHZ) + { + src_clk = ACLK_BUS_SEL_200M; + } + else if (rate == 150 * MHZ) + { + src_clk = ACLK_BUS_SEL_150M; + } + else if (rate == 100 * MHZ) + { + src_clk = ACLK_BUS_SEL_100M; + } + else + { + src_clk = ACLK_BUS_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[50], ACLK_BUS_SEL_MASK, src_clk << ACLK_BUS_SEL_SHIFT); + break; + case PCLK_BUS: + case PCLK_WDT_NS: + if (rate == 100 * MHZ) + { + src_clk = PCLK_BUS_SEL_100M; + } + else if (rate == 75 * MHZ) + { + src_clk = PCLK_BUS_SEL_75M; + } + else if (rate == 50 * MHZ) + { + src_clk = PCLK_BUS_SEL_50M; + } + else + { + src_clk = PCLK_BUS_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[50], PCLK_BUS_SEL_MASK, src_clk << PCLK_BUS_SEL_SHIFT); + break; + + default: + return -RT_ENOSYS; + } + + return bus_get_clk(priv, clk_id); +} + +static rt_ubase_t perimid_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, sel, rate; + + switch (clk_id) + { + case ACLK_PERIMID: + con = HWREG32(&cru->clksel_con[10]); + sel = (con & ACLK_PERIMID_SEL_MASK) >> ACLK_PERIMID_SEL_SHIFT; + if (sel == ACLK_PERIMID_SEL_300M) + { + rate = 300 * MHZ; + } + else if (sel == ACLK_PERIMID_SEL_200M) + { + rate = 200 * MHZ; + } + else if (sel == ACLK_PERIMID_SEL_100M) + { + rate = 100 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + case HCLK_PERIMID: + con = HWREG32(&cru->clksel_con[10]); + sel = (con & HCLK_PERIMID_SEL_MASK) >> HCLK_PERIMID_SEL_SHIFT; + if (sel == HCLK_PERIMID_SEL_150M) + { + rate = 150 * MHZ; + } + else if (sel == HCLK_PERIMID_SEL_100M) + { + rate = 100 * MHZ; + } + else if (sel == HCLK_PERIMID_SEL_75M) + { + rate = 75 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + default: + return -RT_ERROR; + } + + return rate; +} + +static rt_ubase_t perimid_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (clk_id) + { + case ACLK_PERIMID: + if (rate == 300 * MHZ) + { + src_clk = ACLK_PERIMID_SEL_300M; + } + else if (rate == 200 * MHZ) + { + src_clk = ACLK_PERIMID_SEL_200M; + } + else if (rate == 100 * MHZ) + { + src_clk = ACLK_PERIMID_SEL_100M; + } + else + { + src_clk = ACLK_PERIMID_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[10], ACLK_PERIMID_SEL_MASK, src_clk << ACLK_PERIMID_SEL_SHIFT); + break; + case HCLK_PERIMID: + if (rate == 150 * MHZ) + { + src_clk = HCLK_PERIMID_SEL_150M; + } + else if (rate == 100 * MHZ) + { + src_clk = HCLK_PERIMID_SEL_100M; + } + else if (rate == 75 * MHZ) + { + src_clk = HCLK_PERIMID_SEL_75M; + } + else + { + src_clk = HCLK_PERIMID_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[10], HCLK_PERIMID_SEL_MASK, src_clk << HCLK_PERIMID_SEL_SHIFT); + break; + + default: + return -RT_ENOSYS; + } + + return perimid_get_clk(priv, clk_id); +} + +static rt_ubase_t top_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, sel, rate; + + switch (clk_id) + { + case ACLK_TOP_HIGH: + con = HWREG32(&cru->clksel_con[73]); + sel = (con & ACLK_TOP_HIGH_SEL_MASK) >> ACLK_TOP_HIGH_SEL_SHIFT; + if (sel == ACLK_TOP_HIGH_SEL_500M) + { + rate = 500 * MHZ; + } + else if (sel == ACLK_TOP_HIGH_SEL_400M) + { + rate = 400 * MHZ; + } + else if (sel == ACLK_TOP_HIGH_SEL_300M) + { + rate = 300 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + case ACLK_TOP_LOW: + con = HWREG32(&cru->clksel_con[73]); + sel = (con & ACLK_TOP_LOW_SEL_MASK) >> ACLK_TOP_LOW_SEL_SHIFT; + if (sel == ACLK_TOP_LOW_SEL_400M) + { + rate = 400 * MHZ; + } + else if (sel == ACLK_TOP_LOW_SEL_300M) + { + rate = 300 * MHZ; + } + else if (sel == ACLK_TOP_LOW_SEL_200M) + { + rate = 200 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + case HCLK_TOP: + con = HWREG32(&cru->clksel_con[73]); + sel = (con & HCLK_TOP_SEL_MASK) >> HCLK_TOP_SEL_SHIFT; + if (sel == HCLK_TOP_SEL_150M) + { + rate = 150 * MHZ; + } + else if (sel == HCLK_TOP_SEL_100M) + { + rate = 100 * MHZ; + } + else if (sel == HCLK_TOP_SEL_75M) + { + rate = 75 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + case PCLK_TOP: + con = HWREG32(&cru->clksel_con[73]); + sel = (con & PCLK_TOP_SEL_MASK) >> PCLK_TOP_SEL_SHIFT; + if (sel == PCLK_TOP_SEL_100M) + { + rate = 100 * MHZ; + } + else if (sel == PCLK_TOP_SEL_75M) + { + rate = 75 * MHZ; + } + else if (sel == PCLK_TOP_SEL_50M) + { + rate = 50 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + default: + return -RT_ERROR; + } + + return rate; +} + +static rt_ubase_t top_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (clk_id) + { + case ACLK_TOP_HIGH: + if (rate == 500 * MHZ) + { + src_clk = ACLK_TOP_HIGH_SEL_500M; + } + else if (rate == 400 * MHZ) + { + src_clk = ACLK_TOP_HIGH_SEL_400M; + } + else if (rate == 300 * MHZ) + { + src_clk = ACLK_TOP_HIGH_SEL_300M; + } + else + { + src_clk = ACLK_TOP_HIGH_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[73], ACLK_TOP_HIGH_SEL_MASK, src_clk << ACLK_TOP_HIGH_SEL_SHIFT); + break; + case ACLK_TOP_LOW: + if (rate == 400 * MHZ) + { + src_clk = ACLK_TOP_LOW_SEL_400M; + } + else if (rate == 300 * MHZ) + { + src_clk = ACLK_TOP_LOW_SEL_300M; + } + else if (rate == 200 * MHZ) + { + src_clk = ACLK_TOP_LOW_SEL_200M; + } + else + { + src_clk = ACLK_TOP_LOW_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[73], ACLK_TOP_LOW_SEL_MASK, src_clk << ACLK_TOP_LOW_SEL_SHIFT); + break; + case HCLK_TOP: + if (rate == 150 * MHZ) + { + src_clk = HCLK_TOP_SEL_150M; + } + else if (rate == 100 * MHZ) + { + src_clk = HCLK_TOP_SEL_100M; + } + else if (rate == 75 * MHZ) + { + src_clk = HCLK_TOP_SEL_75M; + } + else + { + src_clk = HCLK_TOP_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[73], HCLK_TOP_SEL_MASK, src_clk << HCLK_TOP_SEL_SHIFT); + break; + case PCLK_TOP: + if (rate == 100 * MHZ) + { + src_clk = PCLK_TOP_SEL_100M; + } + else if (rate == 75 * MHZ) + { + src_clk = PCLK_TOP_SEL_75M; + } + else if (rate == 50 * MHZ) + { + src_clk = PCLK_TOP_SEL_50M; + } + else + { + src_clk = PCLK_TOP_SEL_24M; + } + rk_clrsetreg(&cru->clksel_con[73], PCLK_TOP_SEL_MASK, src_clk << PCLK_TOP_SEL_SHIFT); + break; + + default: + return -RT_ENOSYS; + } + + return top_get_clk(priv, clk_id); +} + +static rt_ubase_t i2c_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + rt_ubase_t rate; + + switch (clk_id) + { + case CLK_I2C1: + case CLK_I2C2: + case CLK_I2C3: + case CLK_I2C4: + case CLK_I2C5: + con = HWREG32(&cru->clksel_con[71]); + sel = (con & CLK_I2C_SEL_MASK) >> CLK_I2C_SEL_SHIFT; + if (sel == CLK_I2C_SEL_200M) + { + rate = 200 * MHZ; + } + else if (sel == CLK_I2C_SEL_100M) + { + rate = 100 * MHZ; + } + else if (sel == CLK_I2C_SEL_CPLL_100M) + { + rate = 100 * MHZ; + } + else + { + rate = OSC_HZ; + } + break; + default: + return -RT_ERROR; + } + + return rate; +} + +static rt_ubase_t i2c_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + if (rate == 200 * MHZ) + { + src_clk = CLK_I2C_SEL_200M; + } + else if (rate == 100 * MHZ) + { + src_clk = CLK_I2C_SEL_100M; + } + else + { + src_clk = CLK_I2C_SEL_24M; + } + + switch (clk_id) + { + case CLK_I2C1: + case CLK_I2C2: + case CLK_I2C3: + case CLK_I2C4: + case CLK_I2C5: + rk_clrsetreg(&cru->clksel_con[71], CLK_I2C_SEL_MASK, src_clk << CLK_I2C_SEL_SHIFT); + break; + default: + return -RT_ERROR; + } + + return i2c_get_clk(priv, clk_id); +} + +static rt_ubase_t spi_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[72]); + + switch (clk_id) + { + case CLK_SPI0: + sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT; + break; + case CLK_SPI1: + sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT; + break; + case CLK_SPI2: + sel = (con & CLK_SPI2_SEL_MASK) >> CLK_SPI2_SEL_SHIFT; + break; + case CLK_SPI3: + sel = (con & CLK_SPI3_SEL_MASK) >> CLK_SPI3_SEL_SHIFT; + break; + default: + return -RT_ERROR; + } + + switch (sel) + { + case CLK_SPI_SEL_200M: + return 200 * MHZ; + case CLK_SPI_SEL_24M: + return OSC_HZ; + case CLK_SPI_SEL_CPLL_100M: + return 100 * MHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t spi_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + if (rate == 200 * MHZ) + { + src_clk = CLK_SPI_SEL_200M; + } + else if (rate == 100 * MHZ) + { + src_clk = CLK_SPI_SEL_CPLL_100M; + } + else + { + src_clk = CLK_SPI_SEL_24M; + } + + switch (clk_id) + { + case CLK_SPI0: + rk_clrsetreg(&cru->clksel_con[72], CLK_SPI0_SEL_MASK, src_clk << CLK_SPI0_SEL_SHIFT); + break; + case CLK_SPI1: + rk_clrsetreg(&cru->clksel_con[72], CLK_SPI1_SEL_MASK, src_clk << CLK_SPI1_SEL_SHIFT); + break; + case CLK_SPI2: + rk_clrsetreg(&cru->clksel_con[72], CLK_SPI2_SEL_MASK, src_clk << CLK_SPI2_SEL_SHIFT); + break; + case CLK_SPI3: + rk_clrsetreg(&cru->clksel_con[72], CLK_SPI3_SEL_MASK, src_clk << CLK_SPI3_SEL_SHIFT); + break; + default: + return -RT_ERROR; + } + + return spi_get_clk(priv, clk_id); +} + +static rt_ubase_t pwm_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[72]); + + switch (clk_id) + { + case CLK_PWM1: + sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM3_SEL_SHIFT; + break; + case CLK_PWM2: + sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT; + break; + case CLK_PWM3: + sel = (con & CLK_PWM3_SEL_MASK) >> CLK_PWM3_SEL_SHIFT; + break; + default: + return -RT_ERROR; + } + + switch (sel) + { + case CLK_PWM_SEL_100M: + return 100 * MHZ; + case CLK_PWM_SEL_24M: + return OSC_HZ; + case CLK_PWM_SEL_CPLL_100M: + return 100 * MHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t pwm_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + if (rate == 100 * MHZ) + { + src_clk = CLK_PWM_SEL_100M; + } + else + { + src_clk = CLK_PWM_SEL_24M; + } + + switch (clk_id) + { + case CLK_PWM1: + rk_clrsetreg(&cru->clksel_con[72], CLK_PWM1_SEL_MASK, src_clk << CLK_PWM1_SEL_SHIFT); + break; + case CLK_PWM2: + rk_clrsetreg(&cru->clksel_con[72], CLK_PWM2_SEL_MASK, src_clk << CLK_PWM2_SEL_SHIFT); + break; + case CLK_PWM3: + rk_clrsetreg(&cru->clksel_con[72], CLK_PWM3_SEL_MASK, src_clk << CLK_PWM3_SEL_SHIFT); + break; + default: + return -RT_ERROR; + } + + return pwm_get_clk(priv, clk_id); +} + +static rt_ubase_t adc_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, sel, con, prate; + + switch (clk_id) + { + case CLK_SARADC: + return OSC_HZ; + case CLK_TSADC_TSEN: + con = HWREG32(&cru->clksel_con[51]); + div = (con & CLK_TSADC_TSEN_DIV_MASK) >> CLK_TSADC_TSEN_DIV_SHIFT; + sel = (con & CLK_TSADC_TSEN_SEL_MASK) >> CLK_TSADC_TSEN_SEL_SHIFT; + if (sel == CLK_TSADC_TSEN_SEL_24M) + { + prate = OSC_HZ; + } + else + { + prate = 100 * MHZ; + } + return DIV_TO_RATE(prate, div); + case CLK_TSADC: + con = HWREG32(&cru->clksel_con[51]); + div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT; + prate = adc_get_clk(priv, CLK_TSADC_TSEN); + return DIV_TO_RATE(prate, div); + default: + return -RT_ERROR; + } +} + +static rt_ubase_t adc_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + rt_ubase_t prate = 0; + + switch (clk_id) + { + case CLK_SARADC: + return OSC_HZ; + case CLK_TSADC_TSEN: + if (!(OSC_HZ % rate)) + { + src_clk_div = RT_DIV_ROUND_UP(OSC_HZ, rate); + RT_ASSERT(src_clk_div - 1 <= 7); + rk_clrsetreg(&cru->clksel_con[51], CLK_TSADC_TSEN_SEL_MASK | CLK_TSADC_TSEN_DIV_MASK, + (CLK_TSADC_TSEN_SEL_24M << CLK_TSADC_TSEN_SEL_SHIFT) | + (src_clk_div - 1) << CLK_TSADC_TSEN_DIV_SHIFT); + } + else + { + src_clk_div = RT_DIV_ROUND_UP(100 * MHZ, rate); + RT_ASSERT(src_clk_div - 1 <= 7); + rk_clrsetreg(&cru->clksel_con[51], CLK_TSADC_TSEN_SEL_MASK | CLK_TSADC_TSEN_DIV_MASK, + (CLK_TSADC_TSEN_SEL_100M << CLK_TSADC_TSEN_SEL_SHIFT) | + (src_clk_div - 1) << CLK_TSADC_TSEN_DIV_SHIFT); + } + break; + case CLK_TSADC: + prate = adc_get_clk(priv, CLK_TSADC_TSEN); + src_clk_div = RT_DIV_ROUND_UP(prate, rate); + RT_ASSERT(src_clk_div - 1 <= 128); + rk_clrsetreg(&cru->clksel_con[51], CLK_TSADC_DIV_MASK, (src_clk_div - 1) << CLK_TSADC_DIV_SHIFT); + break; + default: + return -RT_ERROR; + } + return adc_get_clk(priv, clk_id); +} + +static rt_ubase_t crypto_get_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + switch (clk_id) + { + case ACLK_SECURE_FLASH: + case ACLK_CRYPTO_NS: + con = HWREG32(&cru->clksel_con[27]); + sel = (con & ACLK_SECURE_FLASH_SEL_MASK) >> ACLK_SECURE_FLASH_SEL_SHIFT; + if (sel == ACLK_SECURE_FLASH_SEL_200M) + { + return 200 * MHZ; + } + else if (sel == ACLK_SECURE_FLASH_SEL_150M) + { + return 150 * MHZ; + } + else if (sel == ACLK_SECURE_FLASH_SEL_100M) + { + return 100 * MHZ; + } + else + { + return 24 * MHZ; + } + case HCLK_SECURE_FLASH: + case HCLK_CRYPTO_NS: + case CLK_CRYPTO_NS_RNG: + con = HWREG32(&cru->clksel_con[27]); + sel = (con & HCLK_SECURE_FLASH_SEL_MASK) >> HCLK_SECURE_FLASH_SEL_SHIFT; + if (sel == HCLK_SECURE_FLASH_SEL_150M) + { + return 150 * MHZ; + } + else if (sel == HCLK_SECURE_FLASH_SEL_100M) + { + return 100 * MHZ; + } + else if (sel == HCLK_SECURE_FLASH_SEL_75M) + { + return 75 * MHZ; + } + else + { + return 24 * MHZ; + } + case CLK_CRYPTO_NS_CORE: + con = HWREG32(&cru->clksel_con[27]); + sel = (con & CLK_CRYPTO_CORE_SEL_MASK) >> CLK_CRYPTO_CORE_SEL_SHIFT; + if (sel == CLK_CRYPTO_CORE_SEL_200M) + { + return 200 * MHZ; + } + else if (sel == CLK_CRYPTO_CORE_SEL_150M) + { + return 150 * MHZ; + } + else + { + return 100 * MHZ; + } + case CLK_CRYPTO_NS_PKA: + con = HWREG32(&cru->clksel_con[27]); + sel = (con & CLK_CRYPTO_PKA_SEL_MASK) >> CLK_CRYPTO_PKA_SEL_SHIFT; + if (sel == CLK_CRYPTO_PKA_SEL_300M) + { + return 300 * MHZ; + } + else if (sel == CLK_CRYPTO_PKA_SEL_200M) + { + return 200 * MHZ; + } + else + { + return 100 * MHZ; + } + default: + return -RT_ERROR; + } +} + +static rt_ubase_t crypto_set_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t src_clk, mask, shift; + + switch (clk_id) + { + case ACLK_SECURE_FLASH: + case ACLK_CRYPTO_NS: + mask = ACLK_SECURE_FLASH_SEL_MASK; + shift = ACLK_SECURE_FLASH_SEL_SHIFT; + if (rate == 200 * MHZ) + { + src_clk = ACLK_SECURE_FLASH_SEL_200M; + } + else if (rate == 150 * MHZ) + { + src_clk = ACLK_SECURE_FLASH_SEL_150M; + } + else if (rate == 100 * MHZ) + { + src_clk = ACLK_SECURE_FLASH_SEL_100M; + } + else + { + src_clk = ACLK_SECURE_FLASH_SEL_24M; + } + break; + case HCLK_SECURE_FLASH: + case HCLK_CRYPTO_NS: + case CLK_CRYPTO_NS_RNG: + mask = HCLK_SECURE_FLASH_SEL_MASK; + shift = HCLK_SECURE_FLASH_SEL_SHIFT; + if (rate == 150 * MHZ) + { + src_clk = HCLK_SECURE_FLASH_SEL_150M; + } + else if (rate == 100 * MHZ) + { + src_clk = HCLK_SECURE_FLASH_SEL_100M; + } + else if (rate == 75 * MHZ) + { + src_clk = HCLK_SECURE_FLASH_SEL_75M; + } + else + { + src_clk = HCLK_SECURE_FLASH_SEL_24M; + } + break; + case CLK_CRYPTO_NS_CORE: + mask = CLK_CRYPTO_CORE_SEL_MASK; + shift = CLK_CRYPTO_CORE_SEL_SHIFT; + if (rate == 200 * MHZ) + { + src_clk = CLK_CRYPTO_CORE_SEL_200M; + } + else if (rate == 150 * MHZ) + { + src_clk = CLK_CRYPTO_CORE_SEL_150M; + } + else + { + src_clk = CLK_CRYPTO_CORE_SEL_100M; + } + break; + case CLK_CRYPTO_NS_PKA: + mask = CLK_CRYPTO_PKA_SEL_MASK; + shift = CLK_CRYPTO_PKA_SEL_SHIFT; + if (rate == 300 * MHZ) + { + src_clk = CLK_CRYPTO_PKA_SEL_300M; + } + else if (rate == 200 * MHZ) + { + src_clk = CLK_CRYPTO_PKA_SEL_200M; + } + else + { + src_clk = CLK_CRYPTO_PKA_SEL_100M; + } + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[27], mask, src_clk << shift); + + return crypto_get_rate(priv, clk_id); +} + +static rt_ubase_t sdmmc_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + switch (clk_id) + { + case HCLK_SDMMC0: + case CLK_SDMMC0: + con = HWREG32(&cru->clksel_con[30]); + sel = (con & CLK_SDMMC0_SEL_MASK) >> CLK_SDMMC0_SEL_SHIFT; + break; + case CLK_SDMMC1: + con = HWREG32(&cru->clksel_con[30]); + sel = (con & CLK_SDMMC1_SEL_MASK) >> CLK_SDMMC1_SEL_SHIFT; + break; + case CLK_SDMMC2: + con = HWREG32(&cru->clksel_con[32]); + sel = (con & CLK_SDMMC2_SEL_MASK) >> CLK_SDMMC2_SEL_SHIFT; + break; + default: + return -RT_ERROR; + } + + switch (sel) + { + case CLK_SDMMC_SEL_24M: + return OSC_HZ; + case CLK_SDMMC_SEL_400M: + return 400 * MHZ; + case CLK_SDMMC_SEL_300M: + return 300 * MHZ; + case CLK_SDMMC_SEL_100M: + return 100 * MHZ; + case CLK_SDMMC_SEL_50M: + return 50 * MHZ; + case CLK_SDMMC_SEL_750K: + return 750 * KHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t sdmmc_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case OSC_HZ: + src_clk = CLK_SDMMC_SEL_24M; + break; + case 400 * MHZ: + src_clk = CLK_SDMMC_SEL_400M; + break; + case 300 * MHZ: + src_clk = CLK_SDMMC_SEL_300M; + break; + case 100 * MHZ: + src_clk = CLK_SDMMC_SEL_100M; + break; + case 52 * MHZ: + case 50 * MHZ: + src_clk = CLK_SDMMC_SEL_50M; + break; + case 750 * KHZ: + case 400 * KHZ: + src_clk = CLK_SDMMC_SEL_750K; + break; + default: + return -RT_ERROR; + } + + switch (clk_id) + { + case HCLK_SDMMC0: + case CLK_SDMMC0: + rk_clrsetreg(&cru->clksel_con[30], CLK_SDMMC0_SEL_MASK, src_clk << CLK_SDMMC0_SEL_SHIFT); + break; + case CLK_SDMMC1: + rk_clrsetreg(&cru->clksel_con[30], CLK_SDMMC1_SEL_MASK, src_clk << CLK_SDMMC1_SEL_SHIFT); + break; + case CLK_SDMMC2: + rk_clrsetreg(&cru->clksel_con[32], CLK_SDMMC2_SEL_MASK, src_clk << CLK_SDMMC2_SEL_SHIFT); + break; + default: + return -RT_ERROR; + } + + return sdmmc_get_clk(priv, clk_id); +} + +static rt_ubase_t sfc_get_clk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[28]); + sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT; + + switch (sel) + { + case SCLK_SFC_SEL_24M: + return OSC_HZ; + case SCLK_SFC_SEL_50M: + return 50 * MHZ; + case SCLK_SFC_SEL_75M: + return 75 * MHZ; + case SCLK_SFC_SEL_100M: + return 100 * MHZ; + case SCLK_SFC_SEL_125M: + return 125 * MHZ; + case SCLK_SFC_SEL_150M: + return 150 * KHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t sfc_set_clk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case OSC_HZ: + src_clk = SCLK_SFC_SEL_24M; + break; + case 50 * MHZ: + src_clk = SCLK_SFC_SEL_50M; + break; + case 75 * MHZ: + src_clk = SCLK_SFC_SEL_75M; + break; + case 100 * MHZ: + src_clk = SCLK_SFC_SEL_100M; + break; + case 125 * MHZ: + src_clk = SCLK_SFC_SEL_125M; + break; + case 150 * KHZ: + src_clk = SCLK_SFC_SEL_150M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[28], SCLK_SFC_SEL_MASK, src_clk << SCLK_SFC_SEL_SHIFT); + + return sfc_get_clk(priv); +} + +static rt_ubase_t nand_get_clk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[28]); + sel = (con & NCLK_NANDC_SEL_MASK) >> NCLK_NANDC_SEL_SHIFT; + + switch (sel) + { + case NCLK_NANDC_SEL_200M: + return 200 * MHZ; + case NCLK_NANDC_SEL_150M: + return 150 * MHZ; + case NCLK_NANDC_SEL_100M: + return 100 * MHZ; + case NCLK_NANDC_SEL_24M: + return OSC_HZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t nand_set_clk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case OSC_HZ: + src_clk = NCLK_NANDC_SEL_24M; + break; + case 100 * MHZ: + src_clk = NCLK_NANDC_SEL_100M; + break; + case 150 * MHZ: + src_clk = NCLK_NANDC_SEL_150M; + break; + case 200 * MHZ: + src_clk = NCLK_NANDC_SEL_200M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[28], NCLK_NANDC_SEL_MASK, src_clk << NCLK_NANDC_SEL_SHIFT); + + return nand_get_clk(priv); +} + +static rt_ubase_t emmc_get_clk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[28]); + sel = (con & CCLK_EMMC_SEL_MASK) >> CCLK_EMMC_SEL_SHIFT; + + switch (sel) + { + case CCLK_EMMC_SEL_200M: + return 200 * MHZ; + case CCLK_EMMC_SEL_150M: + return 150 * MHZ; + case CCLK_EMMC_SEL_100M: + return 100 * MHZ; + case CCLK_EMMC_SEL_50M: + return 50 * MHZ; + case CCLK_EMMC_SEL_375K: + return 375 * KHZ; + case CCLK_EMMC_SEL_24M: + return OSC_HZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t emmc_set_clk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case OSC_HZ: + src_clk = CCLK_EMMC_SEL_24M; + break; + case 52 * MHZ: + case 50 * MHZ: + src_clk = CCLK_EMMC_SEL_50M; + break; + case 100 * MHZ: + src_clk = CCLK_EMMC_SEL_100M; + break; + case 150 * MHZ: + src_clk = CCLK_EMMC_SEL_150M; + break; + case 200 * MHZ: + src_clk = CCLK_EMMC_SEL_200M; + break; + case 400 * KHZ: + case 375 * KHZ: + src_clk = CCLK_EMMC_SEL_375K; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[28], CCLK_EMMC_SEL_MASK, src_clk << CCLK_EMMC_SEL_SHIFT); + + return emmc_get_clk(priv); +} + +static rt_ubase_t emmc_get_bclk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[28]); + sel = (con & BCLK_EMMC_SEL_MASK) >> BCLK_EMMC_SEL_SHIFT; + + switch (sel) + { + case BCLK_EMMC_SEL_200M: + return 200 * MHZ; + case BCLK_EMMC_SEL_150M: + return 150 * MHZ; + case BCLK_EMMC_SEL_125M: + return 125 * MHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t emmc_set_bclk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case 200 * MHZ: + src_clk = BCLK_EMMC_SEL_200M; + break; + case 150 * MHZ: + src_clk = BCLK_EMMC_SEL_150M; + break; + case 125 * MHZ: + src_clk = BCLK_EMMC_SEL_125M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[28], BCLK_EMMC_SEL_MASK, src_clk << BCLK_EMMC_SEL_SHIFT); + + return emmc_get_bclk(priv); +} + +static rt_ubase_t aclk_vop_get_clk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t div, sel, con, parent; + + con = HWREG32(&cru->clksel_con[38]); + div = (con & ACLK_VOP_PRE_DIV_MASK) >> ACLK_VOP_PRE_DIV_SHIFT; + sel = (con & ACLK_VOP_PRE_SEL_MASK) >> ACLK_VOP_PRE_SEL_SHIFT; + + if (sel == ACLK_VOP_PRE_SEL_GPLL) + { + parent = priv->gpll_hz; + } + else if (sel == ACLK_VOP_PRE_SEL_CPLL) + { + parent = priv->cpll_hz; + } + else if (sel == ACLK_VOP_PRE_SEL_VPLL) + { + parent = priv->vpll_hz; + } + else + { + parent = priv->hpll_hz; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_ubase_t aclk_vop_set_clk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div, src_clk_mux; + + if ((priv->cpll_hz % rate) == 0) + { + src_clk_div = RT_DIV_ROUND_UP(priv->cpll_hz, rate); + src_clk_mux = ACLK_VOP_PRE_SEL_CPLL; + } + else + { + src_clk_div = RT_DIV_ROUND_UP(priv->gpll_hz, rate); + src_clk_mux = ACLK_VOP_PRE_SEL_GPLL; + } + + RT_ASSERT(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[38], ACLK_VOP_PRE_SEL_MASK | ACLK_VOP_PRE_DIV_MASK, + src_clk_mux << ACLK_VOP_PRE_SEL_SHIFT | (src_clk_div - 1) << ACLK_VOP_PRE_DIV_SHIFT); + + return aclk_vop_get_clk(priv); +} + +static rt_ubase_t dclk_vop_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t conid, div, sel, con, parent; + + switch (clk_id) + { + case DCLK_VOP0: + conid = 39; + break; + case DCLK_VOP1: + conid = 40; + break; + case DCLK_VOP2: + conid = 41; + break; + default: + return -RT_ERROR; + } + + con = HWREG32(&cru->clksel_con[conid]); + div = (con & DCLK0_VOP_DIV_MASK) >> DCLK0_VOP_DIV_SHIFT; + sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT; + + if (sel == DCLK_VOP_SEL_HPLL) + { + parent = pmu_pll_get_rate(hpll); + } + else if (sel == DCLK_VOP_SEL_VPLL) + { + parent = rk_pll_get_rate(&pll_clks[vpll], &priv->cru); + } + else if (sel == DCLK_VOP_SEL_GPLL) + { + parent = priv->gpll_hz; + } + else if (sel == DCLK_VOP_SEL_CPLL) + { + parent = priv->cpll_hz; + } + else + { + return -RT_ERROR; + } + + return DIV_TO_RATE(parent, div); +} + +#define VOP_PLL_LIMIT_FREQ 600000000 + +static rt_ubase_t dclk_vop_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_ubase_t pll_rate, now, best_rate = 0; + rt_uint32_t i, conid, con, sel, div, best_div = 0, best_sel = 0; + + switch (clk_id) + { + case DCLK_VOP0: + conid = 39; + break; + case DCLK_VOP1: + conid = 40; + break; + case DCLK_VOP2: + conid = 41; + break; + default: + return -RT_ERROR; + } + + con = HWREG32(&cru->clksel_con[conid]); + sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT; + + if (sel == DCLK_VOP_SEL_HPLL) + { + div = 1; + rk_clrsetreg(&cru->clksel_con[conid], DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, + (DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT) | ((div - 1) << DCLK0_VOP_DIV_SHIFT)); + pmu_pll_set_rate(hpll, div * rate); + } + else if (sel == DCLK_VOP_SEL_VPLL) + { + div = RT_DIV_ROUND_UP(VOP_PLL_LIMIT_FREQ, rate); + rk_clrsetreg(&cru->clksel_con[conid], DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, + (DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT) | ((div - 1) << DCLK0_VOP_DIV_SHIFT)); + rk_pll_set_rate(&pll_clks[vpll], priv->cru, div * rate); + } + else + { + for (i = 0; i <= DCLK_VOP_SEL_CPLL; i++) + { + switch (i) + { + case DCLK_VOP_SEL_GPLL: + pll_rate = priv->gpll_hz; + break; + case DCLK_VOP_SEL_CPLL: + pll_rate = priv->cpll_hz; + break; + default: + return -RT_ENOSYS; + } + + div = RT_DIV_ROUND_UP(pll_rate, rate); + + if (div > 255) + { + continue; + } + + now = pll_rate / div; + + if (rt_abs(rate - now) < rt_abs(rate - best_rate)) + { + best_rate = now; + best_div = div; + best_sel = i; + } + } + + if (best_rate) { + rk_clrsetreg(&cru->clksel_con[conid], DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, + best_sel << DCLK0_VOP_SEL_SHIFT | (best_div - 1) << DCLK0_VOP_DIV_SHIFT); + } + else + { + return -RT_ENOSYS; + } + } + return dclk_vop_get_clk(priv, clk_id); +} + +static rt_ubase_t gmac_src_get_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[31 + mac_id * 2]); + sel = (con & CLK_MAC0_2TOP_SEL_MASK) >> CLK_MAC0_2TOP_SEL_SHIFT; + + switch (sel) + { + case CLK_MAC0_2TOP_SEL_125M: + return 125 * MHZ; + case CLK_MAC0_2TOP_SEL_50M: + return 50 * MHZ; + case CLK_MAC0_2TOP_SEL_25M: + return 25 * MHZ; + case CLK_MAC0_2TOP_SEL_PPLL: + return pmu_pll_get_rate(hpll); + default: + return -RT_ERROR; + } +} + +static rt_ubase_t gmac_src_set_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case 125 * MHZ: + src_clk = CLK_MAC0_2TOP_SEL_125M; + break; + case 50 * MHZ: + src_clk = CLK_MAC0_2TOP_SEL_50M; + break; + case 25 * MHZ: + src_clk = CLK_MAC0_2TOP_SEL_25M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], CLK_MAC0_2TOP_SEL_MASK, src_clk << CLK_MAC0_2TOP_SEL_SHIFT); + + return gmac_src_get_clk(priv, mac_id); +} + +static rt_ubase_t gmac_out_get_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[31 + mac_id * 2]); + sel = (con & CLK_MAC0_OUT_SEL_MASK) >> CLK_MAC0_OUT_SEL_SHIFT; + + switch (sel) + { + case CLK_MAC0_OUT_SEL_125M: + return 125 * MHZ; + case CLK_MAC0_OUT_SEL_50M: + return 50 * MHZ; + case CLK_MAC0_OUT_SEL_25M: + return 25 * MHZ; + case CLK_MAC0_OUT_SEL_24M: + return OSC_HZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t gmac_out_set_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case 125 * MHZ: + src_clk = CLK_MAC0_OUT_SEL_125M; + break; + case 50 * MHZ: + src_clk = CLK_MAC0_OUT_SEL_50M; + break; + case 25 * MHZ: + src_clk = CLK_MAC0_OUT_SEL_25M; + break; + case 24 * MHZ: + src_clk = CLK_MAC0_OUT_SEL_24M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], CLK_MAC0_OUT_SEL_MASK, src_clk << CLK_MAC0_OUT_SEL_SHIFT); + + return gmac_out_get_clk(priv, mac_id); +} + +static rt_ubase_t gmac_ptp_ref_get_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t sel, con; + + con = HWREG32(&cru->clksel_con[31 + mac_id * 2]); + sel = (con & CLK_GMAC0_PTP_REF_SEL_MASK) >> CLK_GMAC0_PTP_REF_SEL_SHIFT; + + switch (sel) + { + case CLK_GMAC0_PTP_REF_SEL_62_5M: + return 62500 * KHZ; + case CLK_GMAC0_PTP_REF_SEL_100M: + return 100 * MHZ; + case CLK_GMAC0_PTP_REF_SEL_50M: + return 50 * MHZ; + case CLK_GMAC0_PTP_REF_SEL_24M: + return OSC_HZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t gmac_ptp_ref_set_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk; + + switch (rate) + { + case 62500 * KHZ: + src_clk = CLK_GMAC0_PTP_REF_SEL_62_5M; + break; + case 100 * MHZ: + src_clk = CLK_GMAC0_PTP_REF_SEL_100M; + break; + case 50 * MHZ: + src_clk = CLK_GMAC0_PTP_REF_SEL_50M; + break; + case 24 * MHZ: + src_clk = CLK_GMAC0_PTP_REF_SEL_24M; + break; + default: + return -RT_ERROR; + } + + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], CLK_GMAC0_PTP_REF_SEL_MASK, src_clk << CLK_GMAC0_PTP_REF_SEL_SHIFT); + + return gmac_ptp_ref_get_clk(priv, mac_id); +} + +static rt_ubase_t gmac_tx_rx_set_clk(struct rk_clk_priv *priv, rt_ubase_t mac_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, sel, div_sel; + + con = HWREG32(&cru->clksel_con[31 + mac_id * 2]); + sel = (con & RMII0_MODE_MASK) >> RMII0_MODE_SHIFT; + + if (sel == RMII0_MODE_SEL_RGMII) + { + if (rate == 2500000) + { + div_sel = RGMII0_CLK_SEL_2_5M; + } + else if (rate == 25000000) + { + div_sel = RGMII0_CLK_SEL_25M; + } + else + { + div_sel = RGMII0_CLK_SEL_125M; + } + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], RGMII0_CLK_SEL_MASK, div_sel << RGMII0_CLK_SEL_SHIFT); + } + else if (sel == RMII0_MODE_SEL_RMII) + { + if (rate == 2500000) + { + div_sel = RMII0_CLK_SEL_2_5M; + } + else + { + div_sel = RMII0_CLK_SEL_25M; + } + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], RMII0_CLK_SEL_MASK, div_sel << RMII0_CLK_SEL_SHIFT); + } + + return 0; +} + +static rt_ubase_t ebc_get_clk(struct rk_clk_priv *priv) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, div, p_rate; + + con = HWREG32(&cru->clksel_con[79]); + div = (con & CPLL_333M_DIV_MASK) >> CPLL_333M_DIV_SHIFT; + p_rate = DIV_TO_RATE(priv->cpll_hz, div); + + con = HWREG32(&cru->clksel_con[43]); + div = (con & DCLK_EBC_SEL_MASK) >> DCLK_EBC_SEL_SHIFT; + + switch (div) + { + case DCLK_EBC_SEL_GPLL_400M: + return 400 * MHZ; + case DCLK_EBC_SEL_CPLL_333M: + return p_rate; + case DCLK_EBC_SEL_GPLL_200M: + return 200 * MHZ; + default: + return -RT_ERROR; + } +} + +static rt_ubase_t ebc_set_clk(struct rk_clk_priv *priv, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->cpll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[79], CPLL_333M_DIV_MASK, (src_clk_div - 1) << CPLL_333M_DIV_SHIFT); + rk_clrsetreg(&cru->clksel_con[43], DCLK_EBC_SEL_MASK, DCLK_EBC_SEL_CPLL_333M << DCLK_EBC_SEL_SHIFT); + + return ebc_get_clk(priv); +} + +static rt_ubase_t rkvdec_get_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t con, div, src, p_rate; + + switch (clk_id) + { + case ACLK_RKVDEC_PRE: + case ACLK_RKVDEC: + con = HWREG32(&cru->clksel_con[47]); + src = (con & ACLK_RKVDEC_SEL_MASK) >> ACLK_RKVDEC_SEL_SHIFT; + div = (con & ACLK_RKVDEC_DIV_MASK) >> ACLK_RKVDEC_DIV_SHIFT; + + if (src == ACLK_RKVDEC_SEL_CPLL) + { + p_rate = priv->cpll_hz; + } + else + { + p_rate = priv->gpll_hz; + } + return DIV_TO_RATE(p_rate, div); + case CLK_RKVDEC_CORE: + con = HWREG32(&cru->clksel_con[49]); + src = (con & CLK_RKVDEC_CORE_SEL_MASK) >> CLK_RKVDEC_CORE_SEL_SHIFT; + div = (con & CLK_RKVDEC_CORE_DIV_MASK) >> CLK_RKVDEC_CORE_DIV_SHIFT; + + if (src == CLK_RKVDEC_CORE_SEL_CPLL) + { + p_rate = priv->cpll_hz; + } + else if (src == CLK_RKVDEC_CORE_SEL_NPLL) + { + p_rate = priv->npll_hz; + } + else if (src == CLK_RKVDEC_CORE_SEL_VPLL) + { + p_rate = priv->vpll_hz; + } + else + { + p_rate = priv->gpll_hz; + } + return DIV_TO_RATE(p_rate, div); + default: + return -RT_ERROR; + } +} + +static rt_ubase_t rkvdec_set_clk(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + int src_clk_div, src, p_rate; + + switch (clk_id) + { + case ACLK_RKVDEC_PRE: + case ACLK_RKVDEC: + src = (HWREG32(&cru->clksel_con[47]) & ACLK_RKVDEC_SEL_MASK) >> ACLK_RKVDEC_SEL_SHIFT; + if (src == ACLK_RKVDEC_SEL_CPLL) + { + p_rate = priv->cpll_hz; + } + else + { + p_rate = priv->gpll_hz; + } + src_clk_div = RT_DIV_ROUND_UP(p_rate, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[47], ACLK_RKVDEC_SEL_MASK | ACLK_RKVDEC_DIV_MASK, + (src << ACLK_RKVDEC_SEL_SHIFT) | (src_clk_div - 1) << ACLK_RKVDEC_DIV_SHIFT); + break; + case CLK_RKVDEC_CORE: + src = (HWREG32(&cru->clksel_con[49]) & CLK_RKVDEC_CORE_SEL_MASK) >> CLK_RKVDEC_CORE_SEL_SHIFT; + if (src == CLK_RKVDEC_CORE_SEL_CPLL) + { + p_rate = priv->cpll_hz; + } + else if (src == CLK_RKVDEC_CORE_SEL_NPLL) + { + p_rate = priv->npll_hz; + } + else if (src == CLK_RKVDEC_CORE_SEL_VPLL) + { + p_rate = priv->vpll_hz; + } + else + { + p_rate = priv->gpll_hz; + } + src_clk_div = RT_DIV_ROUND_UP(p_rate, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[49], CLK_RKVDEC_CORE_SEL_MASK | CLK_RKVDEC_CORE_DIV_MASK, + (src << CLK_RKVDEC_CORE_SEL_SHIFT) | (src_clk_div - 1) << CLK_RKVDEC_CORE_DIV_SHIFT); + break; + default: + return -RT_ERROR; + } + + return rkvdec_get_clk(priv, clk_id); +} + +static rt_ubase_t uart_get_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t reg, con, fracdiv, div, src, p_src, p_rate; + rt_ubase_t m, n; + + switch (clk_id) + { + case SCLK_UART1: + reg = 52; + break; + case SCLK_UART2: + reg = 54; + break; + case SCLK_UART3: + reg = 56; + break; + case SCLK_UART4: + reg = 58; + break; + case SCLK_UART5: + reg = 60; + break; + case SCLK_UART6: + reg = 62; + break; + case SCLK_UART7: + reg = 64; + break; + case SCLK_UART8: + reg = 66; + break; + case SCLK_UART9: + reg = 68; + break; + default: + return -RT_ERROR; + } + + con = HWREG32(&cru->clksel_con[reg]); + src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT; + div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT; + p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT; + + if (p_src == CLK_UART_SRC_SEL_GPLL) + { + p_rate = priv->gpll_hz; + } + else if (p_src == CLK_UART_SRC_SEL_CPLL) + { + p_rate = priv->cpll_hz; + } + else + { + p_rate = 480000000; + } + if (src == CLK_UART_SEL_SRC) + { + return DIV_TO_RATE(p_rate, div); + } + else if (src == CLK_UART_SEL_FRAC) + { + fracdiv = HWREG32(&cru->clksel_con[reg + 1]); + n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK; + n >>= CLK_UART_FRAC_NUMERATOR_SHIFT; + m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK; + m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT; + return DIV_TO_RATE(p_rate, div) * n / m; + } + else + { + return OSC_HZ; + } +} + +static rt_ubase_t uart_set_rate(struct rk_clk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + struct rk_cru *cru = priv->cru; + rt_uint32_t reg, clk_src, uart_src, div; + rt_ubase_t m = 0, n = 0, val; + + if (priv->gpll_hz % rate == 0) + { + clk_src = CLK_UART_SRC_SEL_GPLL; + uart_src = CLK_UART_SEL_SRC; + div = RT_DIV_ROUND_UP(priv->gpll_hz, rate); + } + else if (priv->cpll_hz % rate == 0) + { + clk_src = CLK_UART_SRC_SEL_CPLL; + uart_src = CLK_UART_SEL_SRC; + div = RT_DIV_ROUND_UP(priv->gpll_hz, rate); + } + else if (rate == OSC_HZ) + { + clk_src = CLK_UART_SRC_SEL_GPLL; + uart_src = CLK_UART_SEL_XIN24M; + div = 2; + } + else + { + clk_src = CLK_UART_SRC_SEL_GPLL; + uart_src = CLK_UART_SEL_FRAC; + div = 2; + rational_best_approximation(rate, priv->gpll_hz / div, RT_GENMASK(16 - 1, 0), RT_GENMASK(16 - 1, 0), &m, &n); + } + + switch (clk_id) + { + case SCLK_UART1: + reg = 52; + break; + case SCLK_UART2: + reg = 54; + break; + case SCLK_UART3: + reg = 56; + break; + case SCLK_UART4: + reg = 58; + break; + case SCLK_UART5: + reg = 60; + break; + case SCLK_UART6: + reg = 62; + break; + case SCLK_UART7: + reg = 64; + break; + case SCLK_UART8: + reg = 66; + break; + case SCLK_UART9: + reg = 68; + break; + default: + return -RT_ERROR; + } + rk_clrsetreg(&cru->clksel_con[reg], CLK_UART_SEL_MASK | CLK_UART_SRC_SEL_MASK | CLK_UART_SRC_DIV_MASK, + (clk_src << CLK_UART_SRC_SEL_SHIFT) | (uart_src << CLK_UART_SEL_SHIFT) | + ((div - 1) << CLK_UART_SRC_DIV_SHIFT)); + if (m && n) + { + val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; + HWREG32(&cru->clksel_con[reg + 1]) = val; + } + + return uart_get_rate(priv, clk_id); +} + +static rt_ubase_t pmu_get_pmuclk(struct rk_pmuclk_priv *priv) +{ + struct rk_pmucru *pmucru = priv->pmucru; + rt_uint32_t div, con, sel, parent; + + con = HWREG32(&pmucru->pmu_clksel_con[2]); + sel = (con & PCLK_PDPMU_SEL_MASK) >> PCLK_PDPMU_SEL_SHIFT; + div = (con & PCLK_PDPMU_DIV_MASK) >> PCLK_PDPMU_DIV_SHIFT; + + if (sel) + { + parent = GPLL_HZ; + } + else + { + parent = priv->ppll_hz; + } + + return DIV_TO_RATE(parent, div); +} + +static rt_ubase_t pmu_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t rate) +{ + struct rk_pmucru *pmucru = priv->pmucru; + int src_clk_div; + + src_clk_div = RT_DIV_ROUND_UP(priv->ppll_hz, rate); + RT_ASSERT(src_clk_div - 1 <= 31); + + rk_clrsetreg(&pmucru->pmu_clksel_con[2], PCLK_PDPMU_DIV_MASK | PCLK_PDPMU_SEL_MASK, + (PCLK_PDPMU_SEL_PPLL << PCLK_PDPMU_SEL_SHIFT) | ((src_clk_div - 1) << PCLK_PDPMU_DIV_SHIFT)); + + return pmu_get_pmuclk(priv); +} + +static rt_ubase_t pciephy_ref_get_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id) +{ + rt_uint32_t con, div, src; + struct rk_pmucru *pmucru = priv->pmucru; + + switch (clk_id) + { + case CLK_PCIEPHY0_REF: + con = HWREG32(&pmucru->pmu_clksel_con[9]); + src = (con & CLK_PCIE_PHY0_REF_SEL_MASK) >> CLK_PCIE_PHY0_REF_SEL_SHIFT; + con = HWREG32(&pmucru->pmu_clksel_con[9]); + div = (con & CLK_PCIE_PHY0_PLL_DIV_MASK) >> CLK_PCIE_PHY0_PLL_DIV_SHIFT; + break; + case CLK_PCIEPHY1_REF: + con = HWREG32(&pmucru->pmu_clksel_con[9]); + src = (con & CLK_PCIE_PHY1_REF_SEL_MASK) >> CLK_PCIE_PHY1_REF_SEL_SHIFT; + con = HWREG32(&pmucru->pmu_clksel_con[9]); + div = (con & CLK_PCIE_PHY1_PLL_DIV_MASK) >> CLK_PCIE_PHY1_PLL_DIV_SHIFT; + break; + case CLK_PCIEPHY2_REF: + con = HWREG32(&pmucru->pmu_clksel_con[9]); + src = (con & CLK_PCIE_PHY2_REF_SEL_MASK) >> CLK_PCIE_PHY2_REF_SEL_SHIFT; + con = HWREG32(&pmucru->pmu_clksel_con[9]); + div = (con & CLK_PCIE_PHY2_PLL_DIV_MASK) >> CLK_PCIE_PHY2_PLL_DIV_SHIFT; + break; + } + + if (src == CLK_PCIE_PHY_REF_SEL_PPLL) + { + return DIV_TO_RATE(priv->ppll_hz, div); + } + else + { + return OSC_HZ; + } +} + +static rt_ubase_t pciephy_ref_set_pmuclk(struct rk_pmuclk_priv *priv, rt_ubase_t clk_id, rt_ubase_t rate) +{ + rt_uint32_t clk_src, div; + struct rk_pmucru *pmucru = priv->pmucru; + + if (rate == OSC_HZ) + { + clk_src = CLK_PCIE_PHY_REF_SEL_24M; + div = 1; + } + else + { + clk_src = CLK_PCIE_PHY_REF_SEL_PPLL; + div = RT_DIV_ROUND_UP(priv->ppll_hz, rate); + } + + switch (clk_id) { + case CLK_PCIEPHY0_REF: + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY0_REF_SEL_MASK, + (clk_src << CLK_PCIE_PHY0_REF_SEL_SHIFT)); + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY0_PLL_DIV_MASK, + ((div - 1) << CLK_PCIE_PHY0_PLL_DIV_SHIFT)); + break; + case CLK_PCIEPHY1_REF: + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY1_REF_SEL_MASK, + (clk_src << CLK_PCIE_PHY1_REF_SEL_SHIFT)); + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY1_PLL_DIV_MASK, + ((div - 1) << CLK_PCIE_PHY1_PLL_DIV_SHIFT)); + break; + case CLK_PCIEPHY2_REF: + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY2_REF_SEL_MASK, + (clk_src << CLK_PCIE_PHY2_REF_SEL_SHIFT)); + rk_clrsetreg(&pmucru->pmu_clksel_con[9], CLK_PCIE_PHY2_PLL_DIV_MASK, + ((div - 1) << CLK_PCIE_PHY2_PLL_DIV_SHIFT)); + break; + default: + return -RT_EINVAL; + } + + return pciephy_ref_get_pmuclk(priv, clk_id); +} + +static rt_ubase_t rk_pmuclk_type_get_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + struct rk_pmuclk_priv *priv = &rk_clk->pmuclk_info; + rt_ubase_t rate = 0; + + if (!priv->ppll_hz) + { + return -RT_ERROR; + } + + switch (pdata->id) + { + case PLL_PPLL: + rate = rk_pll_get_rate(&pmu_pll_clks[ppll], &priv->pmucru); + break; + case PLL_HPLL: + rate = rk_pll_get_rate(&pmu_pll_clks[hpll], &priv->pmucru); + break; + case CLK_RTC_32K: + case CLK_RTC32K_FRAC: + rate = rtc32k_get_pmuclk(priv); + break; + case SCLK_UART0: + rate = uart_get_pmuclk(priv, pdata->id); + break; + case CLK_I2C0: + rate = i2c_get_pmuclk(priv, pdata->id); + break; + case CLK_PWM0: + rate = pwm_get_pmuclk(priv, pdata->id); + break; + case PCLK_PMU: + rate = pmu_get_pmuclk(priv); + break; + case CLK_PCIEPHY0_REF: + case CLK_PCIEPHY1_REF: + case CLK_PCIEPHY2_REF: + rate = pciephy_ref_get_pmuclk(priv, pdata->id); + break; + default: + return -RT_ERROR; + } + + return rate; +} + +static rt_ubase_t rk_pmuclk_set_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk, rt_ubase_t rate) +{ + struct rk_pmuclk_priv *priv = &rk_clk->pmuclk_info; + rt_ubase_t res = 0; + + if (!priv->ppll_hz) + { + return -RT_ERROR; + } + + switch (pdata->id) + { + case PLL_PPLL: + res = rk_pll_set_rate(&pmu_pll_clks[ppll], priv->pmucru, rate); + priv->ppll_hz = rk_pll_get_rate(&pmu_pll_clks[ppll], &priv->pmucru); + break; + case PLL_HPLL: + res = rk_pll_set_rate(&pmu_pll_clks[hpll], priv->pmucru, rate); + priv->hpll_hz = rk_pll_get_rate(&pmu_pll_clks[hpll], &priv->pmucru); + break; + case CLK_RTC_32K: + case CLK_RTC32K_FRAC: + res = rtc32k_set_pmuclk(priv, rate); + break; + case SCLK_UART0: + res = uart_set_pmuclk(priv, pdata->id, rate); + break; + case CLK_I2C0: + res = i2c_set_pmuclk(priv, pdata->id, rate); + break; + case CLK_PWM0: + res = pwm_set_pmuclk(priv, pdata->id, rate); + break; + case PCLK_PMU: + res = pmu_set_pmuclk(priv, rate); + break; + case CLK_PCIEPHY0_REF: + case CLK_PCIEPHY1_REF: + case CLK_PCIEPHY2_REF: + res = pciephy_ref_set_pmuclk(priv, pdata->id, rate); + break; + default: + return -RT_ERROR; + } + + return res; +} + +static rt_ubase_t rk_clk_type_get_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + rt_ubase_t rate = 0; + + if (!priv->gpll_hz) + { + return -RT_ERROR; + } + + switch (pdata->id) + { + case PLL_APLL: + case ARMCLK: + rate = rk_pll_get_rate(&pll_clks[apll], &priv->cru); + break; + case PLL_CPLL: + rate = rk_pll_get_rate(&pll_clks[cpll], &priv->cru); + break; + case PLL_GPLL: + rate = rk_pll_get_rate(&pll_clks[gpll], &priv->cru); + break; + case PLL_NPLL: + rate = rk_pll_get_rate(&pll_clks[npll], &priv->cru); + break; + case PLL_VPLL: + rate = rk_pll_get_rate(&pll_clks[vpll], &priv->cru); + break; + case PLL_DPLL: + rate = rk_pll_get_rate(&pll_clks[dpll], &priv->cru); + break; + case ACLK_BUS: + case PCLK_BUS: + case PCLK_WDT_NS: + rate = bus_get_clk(priv, pdata->id); + break; + case ACLK_PERIMID: + case HCLK_PERIMID: + rate = perimid_get_clk(priv, pdata->id); + break; + case ACLK_TOP_HIGH: + case ACLK_TOP_LOW: + case HCLK_TOP: + case PCLK_TOP: + rate = top_get_clk(priv, pdata->id); + break; + case CLK_I2C1: + case CLK_I2C2: + case CLK_I2C3: + case CLK_I2C4: + case CLK_I2C5: + rate = i2c_get_clk(priv, pdata->id); + break; + case CLK_SPI0: + case CLK_SPI1: + case CLK_SPI2: + case CLK_SPI3: + rate = spi_get_clk(priv, pdata->id); + break; + case CLK_PWM1: + case CLK_PWM2: + case CLK_PWM3: + rate = pwm_get_clk(priv, pdata->id); + break; + case CLK_SARADC: + case CLK_TSADC_TSEN: + case CLK_TSADC: + rate = adc_get_clk(priv, pdata->id); + break; + case HCLK_SDMMC0: + case CLK_SDMMC0: + case CLK_SDMMC1: + case CLK_SDMMC2: + rate = sdmmc_get_clk(priv, pdata->id); + break; + case SCLK_SFC: + rate = sfc_get_clk(priv); + break; + case NCLK_NANDC: + rate = nand_get_clk(priv); + break; + case CCLK_EMMC: + rate = emmc_get_clk(priv); + break; + case BCLK_EMMC: + rate = emmc_get_bclk(priv); + break; + case ACLK_VOP: + rate = aclk_vop_get_clk(priv); + break; + case DCLK_VOP0: + case DCLK_VOP1: + case DCLK_VOP2: + rate = dclk_vop_get_clk(priv, pdata->id); + break; + case SCLK_GMAC0: + case CLK_MAC0_2TOP: + case CLK_MAC0_REFOUT: + rate = gmac_src_get_clk(priv, 0); + break; + case CLK_MAC0_OUT: + rate = gmac_out_get_clk(priv, 0); + break; + case CLK_GMAC0_PTP_REF: + rate = gmac_ptp_ref_get_clk(priv, 0); + break; + case SCLK_GMAC1: + case CLK_MAC1_2TOP: + case CLK_MAC1_REFOUT: + rate = gmac_src_get_clk(priv, 1); + break; + case CLK_MAC1_OUT: + rate = gmac_out_get_clk(priv, 1); + break; + case CLK_GMAC1_PTP_REF: + rate = gmac_ptp_ref_get_clk(priv, 1); + break; + case DCLK_EBC: + rate = ebc_get_clk(priv); + break; + case ACLK_RKVDEC_PRE: + case ACLK_RKVDEC: + case CLK_RKVDEC_CORE: + rate = rkvdec_get_clk(priv, pdata->id); + break; + case TCLK_WDT_NS: + rate = OSC_HZ; + break; + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + case SCLK_UART5: + case SCLK_UART6: + case SCLK_UART7: + case SCLK_UART8: + case SCLK_UART9: + rate = uart_get_rate(priv, pdata->id); + break; + case ACLK_SECURE_FLASH: + case ACLK_CRYPTO_NS: + case HCLK_SECURE_FLASH: + case HCLK_CRYPTO_NS: + case CLK_CRYPTO_NS_RNG: + case CLK_CRYPTO_NS_CORE: + case CLK_CRYPTO_NS_PKA: + rate = crypto_get_rate(priv, pdata->id); + break; + case CPLL_500M: + case CPLL_333M: + case CPLL_250M: + case CPLL_125M: + case CPLL_100M: + case CPLL_62P5M: + case CPLL_50M: + case CPLL_25M: + rate = cpll_div_get_rate(priv, pdata->id); + break; + case CLK_TIMER0: + case CLK_TIMER1: + case CLK_TIMER2: + case CLK_TIMER3: + case CLK_TIMER4: + case CLK_TIMER5: + rate = OSC_HZ; + break; + default: + return -RT_ERROR; + } + + return rate; +}; + +static rt_ubase_t rk_clk_set_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk, rt_ubase_t rate) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + rt_ubase_t res = 0; + + if (!priv->gpll_hz) + { + return -RT_ERROR; + } + + switch (pdata->id) + { + case PLL_APLL: + case ARMCLK: + if (priv->armclk_hz) + { + armclk_set_clk(priv, rate); + } + priv->armclk_hz = rate; + break; + case PLL_CPLL: + res = rk_pll_set_rate(&pll_clks[cpll], priv->cru, rate); + priv->cpll_hz = rk_pll_get_rate(&pll_clks[cpll], &priv->cru); + break; + case PLL_GPLL: + res = rk_pll_set_rate(&pll_clks[gpll], priv->cru, rate); + priv->gpll_hz = rk_pll_get_rate(&pll_clks[gpll], &priv->cru); + break; + case PLL_NPLL: + res = rk_pll_set_rate(&pll_clks[npll], priv->cru, rate); + break; + case PLL_VPLL: + res = rk_pll_set_rate(&pll_clks[vpll], priv->cru, rate); + priv->vpll_hz = rk_pll_get_rate(&pll_clks[vpll], &priv->cru); + break; + case ACLK_BUS: + case PCLK_BUS: + case PCLK_WDT_NS: + res = bus_set_clk(priv, pdata->id, rate); + break; + case ACLK_PERIMID: + case HCLK_PERIMID: + res = perimid_set_clk(priv, pdata->id, rate); + break; + case ACLK_TOP_HIGH: + case ACLK_TOP_LOW: + case HCLK_TOP: + case PCLK_TOP: + res = top_set_clk(priv, pdata->id, rate); + break; + case CLK_I2C1: + case CLK_I2C2: + case CLK_I2C3: + case CLK_I2C4: + case CLK_I2C5: + res = i2c_set_clk(priv, pdata->id, rate); + break; + case CLK_SPI0: + case CLK_SPI1: + case CLK_SPI2: + case CLK_SPI3: + res = spi_set_clk(priv, pdata->id, rate); + break; + case CLK_PWM1: + case CLK_PWM2: + case CLK_PWM3: + res = pwm_set_clk(priv, pdata->id, rate); + break; + case CLK_SARADC: + case CLK_TSADC_TSEN: + case CLK_TSADC: + res = adc_set_clk(priv, pdata->id, rate); + break; + case HCLK_SDMMC0: + case CLK_SDMMC0: + case CLK_SDMMC1: + case CLK_SDMMC2: + res = sdmmc_set_clk(priv, pdata->id, rate); + break; + case SCLK_SFC: + res = sfc_set_clk(priv, rate); + break; + case NCLK_NANDC: + res = nand_set_clk(priv, rate); + break; + case CCLK_EMMC: + res = emmc_set_clk(priv, rate); + break; + case BCLK_EMMC: + res = emmc_set_bclk(priv, rate); + break; + case ACLK_VOP: + res = aclk_vop_set_clk(priv, rate); + break; + case DCLK_VOP0: + case DCLK_VOP1: + case DCLK_VOP2: + res = dclk_vop_set_clk(priv, pdata->id, rate); + break; + case SCLK_GMAC0: + case CLK_MAC0_2TOP: + case CLK_MAC0_REFOUT: + res = gmac_src_set_clk(priv, 0, rate); + break; + case CLK_MAC0_OUT: + res = gmac_out_set_clk(priv, 0, rate); + break; + case SCLK_GMAC0_RX_TX: + res = gmac_tx_rx_set_clk(priv, 0, rate); + break; + case CLK_GMAC0_PTP_REF: + res = gmac_ptp_ref_set_clk(priv, 0, rate); + break; + case SCLK_GMAC1: + case CLK_MAC1_2TOP: + case CLK_MAC1_REFOUT: + res = gmac_src_set_clk(priv, 1, rate); + break; + case CLK_MAC1_OUT: + res = gmac_out_set_clk(priv, 1, rate); + break; + case SCLK_GMAC1_RX_TX: + res = gmac_tx_rx_set_clk(priv, 1, rate); + break; + case CLK_GMAC1_PTP_REF: + res = gmac_ptp_ref_set_clk(priv, 1, rate); + break; + case DCLK_EBC: + res = ebc_set_clk(priv, rate); + break; + case ACLK_RKVDEC_PRE: + case ACLK_RKVDEC: + case CLK_RKVDEC_CORE: + res = rkvdec_set_clk(priv, pdata->id, rate); + break; + case TCLK_WDT_NS: + res = OSC_HZ; + break; + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + case SCLK_UART5: + case SCLK_UART6: + case SCLK_UART7: + case SCLK_UART8: + case SCLK_UART9: + res = uart_set_rate(priv, pdata->id, rate); + break; + case ACLK_SECURE_FLASH: + case ACLK_CRYPTO_NS: + case HCLK_SECURE_FLASH: + case HCLK_CRYPTO_NS: + case CLK_CRYPTO_NS_RNG: + case CLK_CRYPTO_NS_CORE: + case CLK_CRYPTO_NS_PKA: + res = crypto_set_rate(priv, pdata->id, rate); + break; + case CPLL_500M: + case CPLL_333M: + case CPLL_250M: + case CPLL_125M: + case CPLL_100M: + case CPLL_62P5M: + case CPLL_50M: + case CPLL_25M: + res = cpll_div_set_rate(priv, pdata->id, rate); + break; + default: + return -RT_ERROR; + } + + return res; +}; + +static rt_uint32_t rk_clk_get_rate(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + rt_uint32_t rate = 0; + + if (rk_clk->type == rk_clk_type_clk) + { + rate = rk_clk_type_get_rate(pdata, rk_clk); + } + else if (rk_clk->type == rk_clk_type_pmuclk) + { + rate = rk_pmuclk_type_get_rate(pdata, rk_clk); + } + + return rate; +} + +static rt_err_t rk_clk_wait_lock(struct rk_clk_platform_data *pdata) +{ + rt_err_t err = RT_EOK; + rt_uint32_t count = 0, pllcon; + + /* + * Lock time typical 250, max 500 input clock cycles @24MHz, So define a + * very safe maximum of 1000us, meaning 24000 cycles. + */ + do { + pllcon = HWREG32(pdata->base + PLL_CON(1)); + rt_hw_us_delay(100); + ++count; + } while (pllcon & PLLCON1_LOCK_STATUS && count < 10); + + if (count >= 10) + { + err = -RT_ETIMEOUT; + } + + return err; +} + +static rt_err_t rtc32k_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_pmuclk_priv *priv = &rk_clk->pmuclk_info; + struct rk_pmucru *pmucru = priv->pmucru; + + if (ppdata->id == CLK_RTC32K_FRAC) + { + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, + RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT); + } + else + { + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, + RTC32K_SEL_OSC1_32K << RTC32K_SEL_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t rk_pmuclk_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + switch (pdata->id) + { + case CLK_RTC_32K: + return rtc32k_set_parent(pdata, ppdata, rk_clk); + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_err_t gmac0_src_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + if (ppdata->id == CLK_MAC0_2TOP) + { + rk_clrsetreg(&cru->clksel_con[31], RMII0_EXTCLK_SEL_MASK, + RMII0_EXTCLK_SEL_MAC0_TOP << RMII0_EXTCLK_SEL_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[31], RMII0_EXTCLK_SEL_MASK, + RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t gmac1_src_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + if (ppdata->id == CLK_MAC1_2TOP) + { + rk_clrsetreg(&cru->clksel_con[33], RMII0_EXTCLK_SEL_MASK, + RMII0_EXTCLK_SEL_MAC0_TOP << RMII0_EXTCLK_SEL_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[33], RMII0_EXTCLK_SEL_MASK, + RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t gmac0_tx_rx_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + if (ppdata->id == SCLK_GMAC0_RGMII_SPEED) + { + rk_clrsetreg(&cru->clksel_con[31], RMII0_MODE_MASK, + RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT); + } + else if (ppdata->id == SCLK_GMAC0_RMII_SPEED) + { + rk_clrsetreg(&cru->clksel_con[31], RMII0_MODE_MASK, + RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[31], RMII0_MODE_MASK, + RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t gmac1_tx_rx_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + if (ppdata->id == SCLK_GMAC1_RGMII_SPEED) + { + rk_clrsetreg(&cru->clksel_con[33], RMII0_MODE_MASK, + RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT); + } + else if (ppdata->id == SCLK_GMAC1_RMII_SPEED) + { + rk_clrsetreg(&cru->clksel_con[33], RMII0_MODE_MASK, + RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[33], RMII0_MODE_MASK, + RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t dclk_vop_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + rt_uint32_t con_id; + + switch (pdata->id) + { + case DCLK_VOP0: + con_id = 39; + break; + + case DCLK_VOP1: + con_id = 40; + break; + + case DCLK_VOP2: + con_id = 41; + break; + + default: + return -RT_EINVAL; + } + + if (ppdata->id == PLL_VPLL) + { + rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK, + DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT); + } + else + { + rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK, + DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT); + } + + return RT_EOK; +} + +static rt_err_t rkvdec_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + rt_uint32_t con_id, mask, shift; + + switch (pdata->id) + { + case ACLK_RKVDEC_PRE: + con_id = 47; + mask = ACLK_RKVDEC_SEL_MASK; + shift = ACLK_RKVDEC_SEL_SHIFT; + break; + + case CLK_RKVDEC_CORE: + con_id = 49; + mask = CLK_RKVDEC_CORE_SEL_MASK; + shift = CLK_RKVDEC_CORE_SEL_SHIFT; + break; + + default: + return -RT_EINVAL; + } + + if (ppdata->id == PLL_CPLL) + { + rk_clrsetreg(&cru->clksel_con[con_id], mask, + ACLK_RKVDEC_SEL_CPLL << shift); + } + else + { + rk_clrsetreg(&cru->clksel_con[con_id], mask, + ACLK_RKVDEC_SEL_GPLL << shift); + } + + return RT_EOK; +} + +static int rk_clk_set_parent(struct rk_clk_platform_data *pdata, + struct rk_clk_platform_data *ppdata, struct rk_clk *rk_clk) +{ + switch (pdata->id) + { + case SCLK_GMAC0: + return gmac0_src_set_parent(pdata, ppdata, rk_clk); + + case SCLK_GMAC1: + return gmac1_src_set_parent(pdata, ppdata, rk_clk); + + case SCLK_GMAC0_RX_TX: + return gmac0_tx_rx_set_parent(pdata, ppdata, rk_clk); + + case SCLK_GMAC1_RX_TX: + return gmac1_tx_rx_set_parent(pdata, ppdata, rk_clk); + + case DCLK_VOP0: + case DCLK_VOP1: + case DCLK_VOP2: + return dclk_vop_set_parent(pdata, ppdata, rk_clk); + + case ACLK_RKVDEC_PRE: + case CLK_RKVDEC_CORE: + return rkvdec_set_parent(pdata, ppdata, rk_clk); + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +#define ROCKCHIP_MMC_DELAY_SEL RT_BIT(10) +#define ROCKCHIP_MMC_DEGREE_MASK 0x3 +#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 +#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) +/* + * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. + */ +#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 + +static rt_err_t mmc_set_phase(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk, rt_uint32_t degrees) +{ + rt_ubase_t rate; + rt_uint32_t raw_value, delay; + rt_uint8_t nineties, remainder, delay_num; + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + rate = rk_clk_get_rate(pdata, rk_clk); + + if (rate < 0) + { + return rate; + } + + nineties = degrees / 90; + remainder = (degrees % 90); + + /* + * Convert to delay; do a little extra work to make sure we + * don't overflow 32-bit / 64-bit numbers. + */ + delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ + delay *= remainder; + delay = RT_DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * + (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); + + delay_num = (rt_uint8_t)rt_min_t(rt_uint32_t, delay, 255); + + raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; + raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; + raw_value |= nineties; + + raw_value <<= 1; + if (pdata->id == SCLK_EMMC_SAMPLE) + { + HWREG32(&cru->emmc_con[1]) = raw_value | 0xffff0000; + } + else if (pdata->id == SCLK_SDMMC0_SAMPLE) + { + HWREG32(&cru->sdmmc0_con[1]) = raw_value | 0xffff0000; + } + else if (pdata->id == SCLK_SDMMC1_SAMPLE) + { + HWREG32(&cru->sdmmc1_con[1]) = raw_value | 0xffff0000; + } + else + { + HWREG32(&cru->sdmmc2_con[1]) = raw_value | 0xffff0000; + } + + return 0; +} + +static rt_base_t mmc_get_phase(struct rk_clk_platform_data *pdata, + struct rk_clk *rk_clk) +{ + rt_ubase_t rate; + rt_uint16_t degrees = 0; + rt_uint32_t raw_value, delay_num; + struct rk_clk_priv *priv = &rk_clk->clk_info; + struct rk_cru *cru = priv->cru; + + rate = rk_clk_get_rate(pdata, rk_clk); + + if (rate < 0) + { + return rate; + } + + if (pdata->id == SCLK_EMMC_SAMPLE) + { + raw_value = HWREG32(&cru->emmc_con[1]); + } + else if (pdata->id == SCLK_SDMMC0_SAMPLE) + { + raw_value = HWREG32(&cru->sdmmc0_con[1]); + } + else if (pdata->id == SCLK_SDMMC1_SAMPLE) + { + raw_value = HWREG32(&cru->sdmmc1_con[1]); + } + else + { + raw_value = HWREG32(&cru->sdmmc2_con[1]); + } + + raw_value >>= 1; + degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; + + if (raw_value & ROCKCHIP_MMC_DELAY_SEL) + { + /* degrees/delaynum * 10000 */ + rt_ubase_t factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * + 36 * (rate / 1000000); + + delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); + delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; + degrees += RT_DIV_ROUND_CLOSEST(delay_num * factor, 10000); + } + + return degrees % 360; +} + +static rt_err_t rk3568_clk_init(struct rt_clk *clk, void *fw_data) +{ + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rt_ofw_cell_args *args = fw_data; + struct rk_clk_platform_data *pdata; + rt_uint32_t clk_id = args->args[0]; + rt_ubase_t reg_base; + + pdata = &rk_clk->pdata[clk_id]; + + if (rk_clk->type == rk_clk_type_pmuclk) + { + reg_base = (rt_ubase_t)rk_clk->pmuclk_info.pmucru; + + switch (clk_id) + { + case PLL_PPLL: + reg_base += pmu_pll_clks[ppll].con_offset; + break; + case PLL_HPLL: + reg_base += pmu_pll_clks[hpll].con_offset; + break; + default: + reg_base = RT_NULL; + break; + } + } + else if (rk_clk->type == rk_clk_type_clk) + { + reg_base = (rt_ubase_t)rk_clk->clk_info.cru; + + switch (clk_id) + { + case PLL_APLL: + case ARMCLK: + reg_base += pll_clks[apll].con_offset; + break; + case PLL_CPLL: + reg_base += pll_clks[cpll].con_offset; + break; + case PLL_GPLL: + reg_base += pll_clks[gpll].con_offset; + break; + case PLL_NPLL: + reg_base += pll_clks[npll].con_offset; + break; + case PLL_VPLL: + reg_base += pll_clks[vpll].con_offset; + break; + case PLL_DPLL: + reg_base += pll_clks[dpll].con_offset; + break; + default: + reg_base = RT_NULL; + break; + } + } + else + { + LOG_E("Unknow type of rk clk = %d", rk_clk->type); + RT_ASSERT(0); + } + + pdata->id = clk_id; + pdata->base = (void *)reg_base; + + clk->rate = rk_clk_get_rate(pdata, rk_clk); + clk->priv = pdata; + + rk_clk_set_default_rates(clk, clk->clk_np->ops->set_rate, clk_id); + + return RT_EOK; +} + +static rt_err_t rk3568_clk_enable(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rk_cru *cru = rk_clk->clk_info.cru; + struct rk_pmucru *pmucru = rk_clk->pmuclk_info.pmucru; + + if (pdata->base) + { + HWREG32(pdata->base + PLL_CON(1)) = HIWORD_UPDATE(0, PLLCON1_PWRDOWN, 0); + + rk_clk_wait_lock(pdata); + } + else + { + void *con_regs; + struct rk_clk_gate *gate; + + if (rk_clk->type == rk_clk_type_clk) + { + gate = &clk_gates[pdata->id]; + con_regs = &cru->clkgate_con[gate->con_idx]; + } + else if (rk_clk->type == rk_clk_type_pmuclk) + { + gate = &pmu_clk_gates[pdata->id]; + con_regs = &pmucru->pmu_clkgate_con[gate->con_idx]; + } + else + { + return -RT_EINVAL; + } + + rk_clrreg(con_regs, RT_BIT(gate->con_bit)); + } + + return RT_EOK; +} + +static void rk3568_clk_disable(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rk_cru *cru = rk_clk->clk_info.cru; + struct rk_pmucru *pmucru = rk_clk->pmuclk_info.pmucru; + + if (pdata->base) + { + HWREG32(pdata->base + PLL_CON(1)) = HIWORD_UPDATE(PLLCON1_PWRDOWN, PLLCON1_PWRDOWN, 0); + } + else + { + void *con_regs; + struct rk_clk_gate *gate; + + if (rk_clk->type == rk_clk_type_clk) + { + gate = &clk_gates[pdata->id]; + con_regs = &cru->clkgate_con[gate->con_idx]; + } + else if (rk_clk->type == rk_clk_type_pmuclk) + { + gate = &pmu_clk_gates[pdata->id]; + con_regs = &pmucru->pmu_clkgate_con[gate->con_idx]; + } + else + { + return; + } + + rk_setreg(con_regs, RT_BIT(gate->con_bit)); + } +} + +static rt_bool_t rk3568_clk_is_enabled(struct rt_clk *clk) +{ + struct rk_clk_platform_data *pdata = clk->priv; + + if (pdata->base) + { + rt_uint32_t pllcon = HWREG32(pdata->base + PLL_CON(1)); + + return !(pllcon & PLLCON1_PWRDOWN); + } + + return RT_TRUE; +} + +static rt_err_t rk3568_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate, rt_ubase_t parent_rate) +{ + rt_ubase_t res_rate; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + if (rk_clk->type == rk_clk_type_clk) + { + res_rate = rk_clk_set_rate(pdata, rk_clk, rate); + + if ((rt_base_t)res_rate > 0) + { + clk->rate = res_rate; + } + } + else if (rk_clk->type == rk_clk_type_pmuclk) + { + res_rate = rk_pmuclk_set_rate(pdata, rk_clk, rate); + + if ((rt_base_t)res_rate > 0) + { + clk->rate = res_rate; + } + } + else + { + return -RT_EINVAL; + } + + return (rt_ubase_t)res_rate > 0 ? RT_EOK : (rt_err_t)res_rate; +} + +static rt_err_t rk3568_clk_set_parent(struct rt_clk *clk, struct rt_clk *parent) +{ + rt_err_t err; + struct rk_clk_platform_data *pdata = clk->priv, *ppdata = parent->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + struct rk_clk *rk_clk_parent = raw_to_rk_clk(clk->clk_np); + + if (rk_clk->type != rk_clk_parent->type) + { + return -RT_EINVAL; + } + + if (rk_clk->type == rk_clk_type_clk) + { + err = rk_clk_set_parent(pdata, ppdata, rk_clk); + } + else if (rk_clk->type == rk_clk_type_pmuclk) + { + err = rk_pmuclk_set_parent(pdata, ppdata, rk_clk); + } + else + { + return -RT_EINVAL; + } + + return err; +} + +static rt_err_t rk3568_clk_set_phase(struct rt_clk *clk, int degrees) +{ + rt_err_t res; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + switch (pdata->id) + { + case SCLK_EMMC_SAMPLE: + case SCLK_SDMMC0_SAMPLE: + case SCLK_SDMMC1_SAMPLE: + case SCLK_SDMMC2_SAMPLE: + res = mmc_set_phase(pdata, rk_clk, degrees); + break; + + default: + return -RT_EINVAL; + } + + return res; +} + +static rt_base_t rk3568_clk_get_phase(struct rt_clk *clk) +{ + rt_base_t res; + struct rk_clk_platform_data *pdata = clk->priv; + struct rk_clk *rk_clk = raw_to_rk_clk(clk->clk_np); + + switch (pdata->id) + { + case SCLK_EMMC_SAMPLE: + case SCLK_SDMMC0_SAMPLE: + case SCLK_SDMMC1_SAMPLE: + case SCLK_SDMMC2_SAMPLE: + res = mmc_get_phase(pdata, rk_clk); + break; + + default: + return -RT_EINVAL; + } + + return res; +} + +static rt_base_t rk3568_clk_round_rate(struct rt_clk *clk, rt_ubase_t drate, + rt_ubase_t *prate) +{ + return rk_clk_pll_round_rate(pll_rates, RT_ARRAY_SIZE(pll_rates), drate, prate); +} + +static const struct rt_clk_ops rk3568_clk_ops = +{ + .init = rk3568_clk_init, + .enable = rk3568_clk_enable, + .disable = rk3568_clk_disable, + .is_enabled = rk3568_clk_is_enabled, + .set_rate = rk3568_clk_set_rate, + .set_parent = rk3568_clk_set_parent, + .set_phase = rk3568_clk_set_phase, + .get_phase = rk3568_clk_get_phase, + .round_rate = rk3568_clk_round_rate, +}; + +static void rk3568_clk_type_init(struct rk_clk *rk_clk, struct rt_ofw_node *np) +{ + rt_ubase_t cpu_freq = APLL_HZ; + struct rk_clk_priv *priv = &rk_clk->clk_info; + const char *rockchip_cpu_freq = rt_ofw_bootargs_select("rockchip.cpu_freq=", 0); + + priv->cru = (struct rk_cru *)rk_clk->base; + + if (!priv->armclk_enter_hz) + { + priv->armclk_enter_hz = rk_pll_get_rate(&pll_clks[apll], &priv->cru); + priv->armclk_init_hz = priv->armclk_enter_hz; + } + + if (rockchip_cpu_freq) + { + cpu_freq = atol(rockchip_cpu_freq); + } + + if (priv->armclk_init_hz != cpu_freq) + { + if (!armclk_set_clk(priv, cpu_freq)) + { + priv->armclk_init_hz = cpu_freq; + } + } + + if (priv->cpll_hz != CPLL_HZ) + { + if (!rk_pll_set_rate(&pll_clks[cpll], priv->cru, CPLL_HZ)) + { + priv->cpll_hz = CPLL_HZ; + } + } + + if (priv->gpll_hz != GPLL_HZ) + { + if (!rk_pll_set_rate(&pll_clks[gpll], priv->cru, GPLL_HZ)) + { + priv->gpll_hz = GPLL_HZ; + } + } + + priv->ppll_hz = pmu_pll_get_rate(ppll); + priv->hpll_hz = pmu_pll_get_rate(hpll); +} + +static void rk3568_pmu_clk_type_init(struct rk_clk *rk_clk, struct rt_ofw_node *np) +{ + struct rk_pmuclk_priv *priv = &rk_clk->pmuclk_info; + priv->pmucru = (struct rk_pmucru *)rk_clk->base; + + if (priv->ppll_hz != PPLL_HZ) + { + if (!rk_pll_set_rate(&pmu_pll_clks[ppll], priv->pmucru, PPLL_HZ)) + { + priv->ppll_hz = PPLL_HZ; + } + } + + /* Ungate PCIe30phy refclk_m and refclk_n */ + rk_clrsetreg(&priv->pmucru->pmu_clkgate_con[2], 0x3 << 13, 0 << 13); +} + +static rt_err_t clk_rk3568_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_size_t data_size = 0; + struct rk_clk *rk_clk; + struct rt_ofw_node *np = pdev->parent.ofw_node; + enum rk_clk_type type = (rt_ubase_t)pdev->id->data; + + if (type == rk_clk_type_clk) + { + data_size = CLK_NR_CLKS; + } + else if (type == rk_clk_type_pmuclk) + { + data_size = CLKPMU_NR_CLKS; + } + + data_size *= sizeof(struct rk_clk_platform_data); + rk_clk = rt_malloc(sizeof(*rk_clk) + data_size); + + if (rk_clk) + { + void *softrst_regs = RT_NULL; + rt_memset(&rk_clk->parent, 0, sizeof(rk_clk->parent)); + + rk_clk->base = rt_ofw_iomap(np, 0); + + if (!rk_clk->base) + { + err = -RT_EIO; + goto _fail; + } + + if (type == rk_clk_type_clk) + { + rk_clk->type = rk_clk_type_clk; + + rk3568_clk_type_init(rk_clk, np); + softrst_regs = &rk_clk->clk_info.cru->softrst_con; + } + else if (type == rk_clk_type_pmuclk) + { + rk_clk->type = rk_clk_type_pmuclk; + + rk3568_pmu_clk_type_init(rk_clk, np); + softrst_regs = &rk_clk->pmuclk_info.pmucru->pmu_softrst_con; + } + + rk_clk->parent.parent.ops = &rk3568_clk_ops; + + if ((err = rt_clk_register(&rk_clk->parent.parent, RT_NULL))) + { + goto _fail; + } + + if ((err = rk_register_softrst(&rk_clk->parent.rstcer, np, + softrst_regs, ROCKCHIP_SOFTRST_HIWORD_MASK))) + { + goto _fail; + } + + rt_ofw_data(np) = &rk_clk->parent; + } + else + { + err = -RT_ENOMEM; + } + + return err; + +_fail: + if (rk_clk->base) + { + rt_iounmap(rk_clk->base); + } + + rt_free(rk_clk); + + return err; +} + +static const struct rt_ofw_node_id clk_rk3568_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-cru", .data = (void *)rk_clk_type_clk }, + { .compatible = "rockchip,rk3568-pmucru", .data = (void *)rk_clk_type_pmuclk }, + { /* sentinel */ } +}; + +static struct rt_platform_driver clk_rk3568_driver = +{ + .name = "clk-rk3568", + .ids = clk_rk3568_ofw_ids, + + .probe = clk_rk3568_probe, +}; + +static int clk_rk3568_register(void) +{ + rt_platform_driver_register(&clk_rk3568_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(clk_rk3568_register); diff --git a/components/drivers/clk/rockchip/clk.h b/components/drivers/clk/rockchip/clk.h new file mode 100644 index 000000000000..3da01a648b47 --- /dev/null +++ b/components/drivers/clk/rockchip/clk.h @@ -0,0 +1,119 @@ +/* + * 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 + */ + +#ifndef __ROCKCHIP_CLK_H__ +#define __ROCKCHIP_CLK_H__ + +#include +#include +#include + +#include +#include "../../soc/rockchip/rockchip.h" + +#define HZ 100 +#define KHZ 1000 +#define MHZ 1000000 +#define OSC_HZ (24 * MHZ) + +#define PSECS_PER_SEC 1000000000000LL + +struct rk_cpu_rate_table +{ + rt_ubase_t rate; + rt_uint32_t aclk_div; + rt_uint32_t pclk_div; +}; + +struct rk_pll_rate_table +{ + rt_ubase_t rate; + rt_uint32_t nr; + rt_uint32_t nf; + rt_uint32_t no; + rt_uint32_t nb; + + rt_uint32_t fbdiv; + rt_uint32_t postdiv1; + rt_uint32_t refdiv; + rt_uint32_t postdiv2; + rt_uint32_t dsmpd; + rt_uint32_t frac; +}; + +struct rk_pll_clock +{ + rt_uint32_t id; + rt_uint32_t con_offset; + rt_uint32_t mode_offset; + rt_uint32_t mode_shift; + rt_uint32_t lock_shift; + rt_uint32_t pll_flags; + struct rk_pll_rate_table *rate_table; + rt_uint32_t mode_mask; +}; + +struct rk_clk_gate +{ + const char *name; + const char *parent_name; + + int con_idx; + int con_bit; +}; + +#define GATE(_id, _name, \ +_pname, _con_idx, _con_bit) \ +[_id] = \ +{ \ + .name = _name, \ + .parent_name = _pname, \ + .con_idx = _con_idx, \ + .con_bit = _con_bit, \ +} + + +#define CPUCLK_RATE(_rate, \ + _aclk_div, _pclk_div) \ +{ \ + .rate = _rate##U, \ + .aclk_div = _aclk_div, \ + .pclk_div = _pclk_div, \ +} + +#define PLL_RATE(_rate, _refdiv, _fbdiv, \ + _postdiv1, _postdiv2, _dsmpd, _frac) \ +{ \ + .rate = _rate##U, \ + .fbdiv = _fbdiv, \ + .postdiv1 = _postdiv1, \ + .refdiv = _refdiv, \ + .postdiv2 = _postdiv2, \ + .dsmpd = _dsmpd, \ + .frac = _frac, \ +} + +#define PLL(_id, _con, _mode, _mshift, \ + _lshift, _pflags, _rtable) \ +{ \ + .id = _id, \ + .con_offset = _con, \ + .mode_offset = _mode, \ + .mode_shift = _mshift, \ + .lock_shift = _lshift, \ + .pll_flags = _pflags, \ + .rate_table = _rtable, \ +} + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +#define ROCKCHIP_SOFTRST_HIWORD_MASK RT_BIT(0) + +#endif /* __ROCKCHIP_CLK_H__ */ diff --git a/components/drivers/clk/rockchip/softrst.c b/components/drivers/clk/rockchip/softrst.c new file mode 100644 index 000000000000..cd2ba7faba3d --- /dev/null +++ b/components/drivers/clk/rockchip/softrst.c @@ -0,0 +1,112 @@ +/* + * 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 + */ + +struct rockchip_softrst +{ + void *regs; + int num_per_reg; + rt_uint8_t flags; + + struct rt_spinlock lock; +}; + +static rt_err_t rockchip_softrst_assert(struct rt_reset_control *rstc) +{ + int bank, offset; + struct rockchip_softrst *softrst = rstc->rstcer->priv; + + bank = rstc->id / softrst->num_per_reg; + offset = rstc->id % softrst->num_per_reg; + + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) + { + HWREG32(softrst->regs + (bank * 4)) = RT_BIT(offset) | (RT_BIT(offset) << 16); + } + else + { + rt_uint32_t reg; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(&softrst->lock); + + reg = HWREG32(softrst->regs + (bank * 4)); + HWREG32(softrst->regs + (bank * 4)) = reg | RT_BIT(offset); + + rt_spin_unlock_irqrestore(&softrst->lock, level); + } + + return RT_EOK; +} + +static rt_err_t rockchip_softrst_deassert(struct rt_reset_control *rstc) +{ + int bank, offset; + struct rockchip_softrst *softrst = rstc->rstcer->priv; + + bank = rstc->id / softrst->num_per_reg; + offset = rstc->id % softrst->num_per_reg; + + if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) + { + HWREG32(softrst->regs + (bank * 4)) = (RT_BIT(offset) << 16); + } + else + { + rt_uint32_t reg; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(&softrst->lock); + + reg = HWREG32(softrst->regs + (bank * 4)); + HWREG32(softrst->regs + (bank * 4)) = reg & ~RT_BIT(offset); + + rt_spin_unlock_irqrestore(&softrst->lock, level); + } + + return RT_EOK; +} + +static const struct rt_reset_control_ops rockchip_softrst_ops = +{ + .assert = rockchip_softrst_assert, + .deassert = rockchip_softrst_deassert, +}; + +static rt_err_t rk_register_softrst(struct rt_reset_controller *rstcer, + struct rt_ofw_node *np, void *regs, rt_uint8_t flags) +{ + rt_err_t err; + struct rockchip_softrst *softrst = rt_calloc(1, sizeof(*softrst)); + + if (!softrst) + { + return -RT_ENOMEM; + } + + rstcer->priv = softrst; + + rt_spin_lock_init(&softrst->lock); + + softrst->regs = regs; + softrst->flags = flags; + softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 : 32; + + rstcer->ofw_node = np; + rstcer->ops = &rockchip_softrst_ops; + + if ((err = rt_reset_controller_register(rstcer))) + { + rt_free(softrst); + + return err; + } + + return RT_EOK; +} diff --git a/components/drivers/core/bus.c b/components/drivers/core/bus.c index e5293d0f44b0..bff3e6e88282 100644 --- a/components/drivers/core/bus.c +++ b/components/drivers/core/bus.c @@ -15,6 +15,11 @@ #define DBG_LVL DBG_INFO #include +#if defined(RT_USING_DFS) && defined(RT_USING_DFS_DIRECTFS) +#include +#include +#endif + static struct rt_bus bus_root = { .name = "root", @@ -29,6 +34,35 @@ rt_bus_t rt_bus_root(void) return &bus_root; } +void rt_bus_lock(rt_bus_t bus) +{ + while (!rt_bus_trylock(bus)) + { + rt_thread_yield(); + } +} + +rt_bool_t rt_bus_trylock(rt_bus_t bus) +{ + rt_bool_t res = RT_FALSE; + rt_ubase_t level = rt_spin_lock_irqsave(&bus->spinlock); + + if (rt_atomic_load(&bus->exclusive) == 0) + { + res = RT_TRUE; + rt_atomic_store(&bus->exclusive, 1); + } + + rt_spin_unlock_irqrestore(&bus->spinlock, level); + + return res; +} + +void rt_bus_unlock(rt_bus_t bus) +{ + rt_atomic_store(&bus->exclusive, 0); +} + /** * @brief This function loop the dev_list of the bus, and call fn in each loop * @@ -42,20 +76,19 @@ rt_bus_t rt_bus_root(void) */ rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev)) { - rt_base_t level; rt_device_t dev; RT_ASSERT(bus != RT_NULL); RT_ASSERT(drv != RT_NULL); - level = rt_spin_lock_irqsave(&bus->spinlock); + rt_bus_lock(bus); rt_list_for_each_entry(dev, &bus->dev_list, node) { fn(drv, dev); } - rt_spin_unlock_irqrestore(&bus->spinlock, level); + rt_bus_unlock(bus); return RT_EOK; } @@ -74,7 +107,6 @@ rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_ rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev)) { rt_err_t err; - rt_base_t level; rt_driver_t drv; RT_ASSERT(bus != RT_NULL); @@ -87,7 +119,7 @@ rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_ err = -RT_ERROR; - level = rt_spin_lock_irqsave(&bus->spinlock); + rt_bus_lock(bus); rt_list_for_each_entry(drv, &bus->drv_list, node) { @@ -99,7 +131,7 @@ rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_ } } - rt_spin_unlock_irqrestore(&bus->spinlock, level); + rt_bus_unlock(bus); return err; } @@ -113,18 +145,32 @@ rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_ */ rt_err_t rt_bus_add(rt_bus_t bus_node) { - rt_base_t level; - RT_ASSERT(bus_node != RT_NULL); bus_node->bus = &bus_root; rt_list_init(&bus_node->list); - level = rt_spin_lock_irqsave(&bus_node->spinlock); + rt_bus_lock(bus_node); rt_list_insert_before(&bus_root.children, &bus_node->list); +#ifdef RT_USING_DFS_DIRECTFS + do { + static rt_object_t bus_obj = RT_NULL; + + if (!bus_obj) + { + bus_obj = dfs_directfs_find_object(RT_NULL, "bus"); + + RT_ASSERT(bus_obj != RT_NULL); + } + + dfs_directfs_create_link(bus_obj, &bus_node->parent, bus_node->name); + dfs_directfs_create_link(&bus_node->parent, (rt_object_t)&bus_node->dev_list, "devices"); + dfs_directfs_create_link(&bus_node->parent, (rt_object_t)&bus_node->drv_list, "drivers"); + } while (0); +#endif - rt_spin_unlock_irqrestore(&bus_node->spinlock, level); + rt_bus_unlock(bus_node); return RT_EOK; } @@ -176,21 +222,23 @@ static int rt_bus_probe(rt_driver_t drv, rt_device_t dev) */ rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv) { - rt_base_t level; - RT_ASSERT(bus != RT_NULL); RT_ASSERT(drv != RT_NULL); drv->bus = bus; - level = rt_spin_lock_irqsave(&bus->spinlock); + rt_bus_lock(bus); rt_list_insert_before(&bus->drv_list, &drv->node); - rt_spin_unlock_irqrestore(&bus->spinlock, level); + rt_bus_unlock(bus); rt_bus_for_each_dev(drv->bus, drv, rt_bus_probe); +#ifdef RT_USING_DFS_DIRECTFS + dfs_directfs_create_link((rt_object_t)&bus->drv_list, (rt_object_t)&drv->node, drv->name); +#endif + return RT_EOK; } @@ -205,21 +253,23 @@ rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv) */ rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev) { - rt_base_t level; - RT_ASSERT(bus != RT_NULL); RT_ASSERT(dev != RT_NULL); dev->bus = bus; - level = rt_spin_lock_irqsave(&bus->spinlock); + rt_bus_lock(bus); rt_list_insert_before(&bus->dev_list, &dev->node); - rt_spin_unlock_irqrestore(&bus->spinlock, level); + rt_bus_unlock(bus); rt_bus_for_each_drv(dev->bus, dev, rt_bus_probe); +#ifdef RT_USING_DFS_DIRECTFS + dfs_directfs_create_link((rt_object_t)&bus->dev_list, (rt_object_t)&dev->parent, dev->parent.name); +#endif + return RT_EOK; } @@ -297,12 +347,10 @@ rt_bus_t rt_bus_find_by_name(char *name) */ rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev) { - rt_base_t level; - RT_ASSERT(new_bus != RT_NULL); RT_ASSERT(dev != RT_NULL); - level = rt_spin_lock_irqsave(&new_bus->spinlock); + rt_bus_lock(new_bus); rt_list_remove(&dev->node); rt_list_insert_before(&new_bus->dev_list, &dev->node); @@ -310,7 +358,7 @@ rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev) rt_list_remove(&dev->drv->node); rt_list_insert_before(&new_bus->drv_list, &dev->drv->node); - rt_spin_unlock_irqrestore(&new_bus->spinlock, level); + rt_bus_unlock(new_bus); return RT_EOK; } @@ -327,6 +375,9 @@ rt_err_t rt_bus_register(rt_bus_t bus) rt_list_init(&bus->dev_list); rt_list_init(&bus->drv_list); + rt_spin_lock_init(&bus->spinlock); + rt_atomic_store(&bus->exclusive, 0); + rt_bus_add(bus); return RT_EOK; diff --git a/components/drivers/core/dm.c b/components/drivers/core/dm.c index 12ec3e18f844..b3e112c3eba3 100644 --- a/components/drivers/core/dm.c +++ b/components/drivers/core/dm.c @@ -10,6 +10,10 @@ #include +#ifdef RT_USING_OFW +#include +#include +#endif #include #ifdef RT_USING_SMP @@ -56,10 +60,10 @@ struct prefix_track int uid; const char *prefix; }; -static struct rt_spinlock _prefix_nodes_lock; +static struct rt_spinlock _prefix_nodes_lock = { 0 }; static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes); -int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix) +int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix) { int uid = -1; struct prefix_track *pt = RT_NULL; @@ -104,17 +108,17 @@ int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix) rt_spin_unlock(&_prefix_nodes_lock); } - return rt_dm_set_dev_name(dev, "%s%u", prefix, uid); + return rt_dm_dev_set_name(dev, "%s%u", prefix, uid); } -int rt_dm_get_dev_name_id(rt_device_t dev) +int rt_dm_dev_get_name_id(rt_device_t dev) { int id = 0, len; const char *name; RT_ASSERT(dev != RT_NULL); - name = rt_dm_get_dev_name(dev); + name = rt_dm_dev_get_name(dev); len = rt_strlen(name) - 1; name += len; @@ -137,7 +141,7 @@ int rt_dm_get_dev_name_id(rt_device_t dev) return id; } -int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...) +int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...) { int n; va_list arg_ptr; @@ -152,9 +156,275 @@ int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...) return n; } -const char *rt_dm_get_dev_name(rt_device_t dev) +const char *rt_dm_dev_get_name(rt_device_t dev) { RT_ASSERT(dev != RT_NULL); return dev->parent.name; } + +#ifdef RT_USING_OFW +#define ofw_api_call(name, ...) rt_ofw_##name(__VA_ARGS__) +#define ofw_api_call_ptr(name, ...) ofw_api_call(name, __VA_ARGS__) +#else +#define ofw_api_call(name, ...) (-RT_ENOSYS) +#define ofw_api_call_ptr(name, ...) RT_NULL +#endif + +int rt_dm_dev_get_address_count(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_address_count, dev->ofw_node); + } + + return -RT_ENOSYS; +} + +rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index, + rt_uint64_t *out_address, rt_uint64_t *out_size) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_address, dev->ofw_node, index, + out_address, out_size); + } + + return -RT_ENOSYS; +} + +rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name, + rt_uint64_t *out_address, rt_uint64_t *out_size) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_address_by_name, dev->ofw_node, name, + out_address, out_size); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_address_array, dev->ofw_node, nr, out_regs); + } + + return -RT_ENOSYS; +} + +void *rt_dm_dev_iomap(rt_device_t dev, int index) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call_ptr(iomap, dev->ofw_node, index); + } + + return RT_NULL; +} + +void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call_ptr(iomap_by_name, dev->ofw_node, name); + } + + return RT_NULL; +} + +int rt_dm_dev_get_irq_count(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_irq_count, dev->ofw_node); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_get_irq(rt_device_t dev, int index) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_irq, dev->ofw_node, index); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(get_irq_by_name, dev->ofw_node, name); + } + + return -RT_ENOSYS; +} + +void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data) +{ + RT_ASSERT(dev != RT_NULL); + + if (!dev->ofw_node && fw_np) + { + #ifdef RT_USING_OFW + dev->ofw_node = fw_np; + rt_ofw_data(fw_np) = data; + #endif + } + + RT_ASSERT(dev->ofw_node != RT_NULL); + +#ifdef RT_USING_OFW + rt_ofw_data(dev->ofw_node) = data; +#endif +} + +void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np) +{ + void *dev_fw_np; + + RT_ASSERT(dev != RT_NULL); + + if (!dev->ofw_node && fw_np) + { + #ifdef RT_USING_OFW + dev_fw_np = fw_np; + rt_ofw_data(fw_np) = RT_NULL; + #endif + } + + RT_ASSERT(dev_fw_np != RT_NULL); + +#ifdef RT_USING_OFW + rt_ofw_data(dev_fw_np) = RT_NULL; +#endif +} + +int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint8_t *out_values) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_u8_array_index, dev->ofw_node, propname, + index, nr, out_values); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint16_t *out_values) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_u16_array_index, dev->ofw_node, propname, + index, nr, out_values); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint32_t *out_values) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_u32_array_index, dev->ofw_node, propname, + index, nr, out_values); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint64_t *out_values) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_u64_array_index, dev->ofw_node, propname, + index, nr, out_values); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname, + int index, int nr, const char **out_strings) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_string_array_index, dev->ofw_node, propname, + index, nr, out_strings); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_count_of_size, dev->ofw_node, propname, size); + } + + return -RT_ENOSYS; +} + +int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_index_of_string, dev->ofw_node, propname, string); + } + + return -RT_ENOSYS; +} + +rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname) +{ + RT_ASSERT(dev != RT_NULL); + + if (dev->ofw_node) + { + return ofw_api_call(prop_read_bool, dev->ofw_node, propname); + } + + return RT_FALSE; +} diff --git a/components/drivers/core/platform.c b/components/drivers/core/platform.c index 62e092a3fa9c..727e92b0cabc 100644 --- a/components/drivers/core/platform.c +++ b/components/drivers/core/platform.c @@ -10,6 +10,10 @@ #include +#define DBG_TAG "rtdm.platform" +#define DBG_LVL DBG_INFO +#include + #include #include #include @@ -27,6 +31,11 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name) { struct rt_platform_device *pdev = rt_calloc(1, sizeof(*pdev)); + if (!pdev) + { + return RT_NULL; + } + pdev->parent.bus = &platform_bus; pdev->name = name; @@ -43,6 +52,7 @@ rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv) RT_ASSERT(pdrv != RT_NULL); pdrv->parent.bus = &platform_bus; + pdrv->parent.name = pdrv->name; return rt_driver_register(&pdrv->parent); } @@ -56,6 +66,8 @@ rt_err_t rt_platform_device_register(struct rt_platform_device *pdev) { RT_ASSERT(pdev != RT_NULL); + rt_dm_dev_set_name(&pdev->parent, "%s", pdev->name); + return rt_bus_add_device(&platform_bus, &pdev->parent); } @@ -67,8 +79,12 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev) if (np) { + #ifdef RT_USING_OFW /* 1、match with ofw node */ pdev->id = rt_ofw_node_match(np, pdrv->ids); + #else + pdev->id = RT_NULL; + #endif return !!pdev->id; } @@ -99,17 +115,26 @@ static rt_err_t platform_probe(rt_device_t dev) if (!err) { + #ifdef RT_USING_OFW if (np) { rt_ofw_node_set_flag(np, RT_OFW_F_READLY); } + #endif } else { + if (err == -RT_ENOMEM) + { + LOG_W("System not memory in driver %s", pdrv->name); + } + + #ifdef RT_USING_OFW if (np) { rt_ofw_data(np) = &pdev->parent; } + #endif } return err; diff --git a/components/drivers/core/platform_ofw.c b/components/drivers/core/platform_ofw.c index 5327a9af6b59..0c2a6497dfab 100644 --- a/components/drivers/core/platform_ofw.c +++ b/components/drivers/core/platform_ofw.c @@ -36,6 +36,26 @@ static const struct rt_ofw_node_id platform_ofw_ids[] = { /* sentinel */ } }; +static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *np) +{ + struct rt_platform_device *pdev = rt_platform_device_alloc(np->name); + + if (pdev) + { + /* inc reference of dt-node */ + rt_ofw_node_get(np); + rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM); + + pdev->parent.ofw_node = np; + } + else + { + LOG_E("Alloc device fail for %s", rt_ofw_node_full_name(np)); + } + + return pdev; +} + static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np) { rt_err_t err = RT_EOK; @@ -81,7 +101,7 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np) } } - pdev = rt_platform_device_alloc(np->name); + pdev = alloc_ofw_platform_device(np); if (!pdev) { @@ -90,14 +110,38 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np) break; } - /* inc reference of dt-node */ - rt_ofw_node_get(np); - rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM); + rt_platform_device_register(pdev); + } - pdev->parent.ofw_node = np; + return err; +} - rt_platform_device_register(pdev); +rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np) +{ + rt_err_t err; + struct rt_ofw_node *parent = rt_ofw_get_parent(np); + + if (parent && rt_strcmp(parent->name, "/") && + rt_ofw_get_prop(np, "compatible", RT_NULL) && + !rt_ofw_node_test_flag(np, RT_OFW_F_PLATFORM)) + { + struct rt_platform_device *pdev = alloc_ofw_platform_device(np); + + if (pdev) + { + err = rt_platform_device_register(pdev); + } + else + { + err = -RT_ENOMEM; + } } + else + { + err = -RT_EINVAL; + } + + rt_ofw_node_put(parent); return err; } diff --git a/components/drivers/firmware/Kconfig b/components/drivers/firmware/Kconfig index 270926f538ba..d9f390e4676d 100644 --- a/components/drivers/firmware/Kconfig +++ b/components/drivers/firmware/Kconfig @@ -7,4 +7,12 @@ config RT_FIRMWARE_PSCI bool "Power State Coordination Interface (PSCI)" depends on RT_USING_FIRMWARE select RT_USING_PM + select RT_USING_OFW + default n + +config RT_FIRMWARE_QEMU_FW_CFG + bool "QEMU Firmware Configuration" + depends on RT_USING_FIRMWARE + select RT_USING_DFS + select RT_USING_DFS_DIRECTFS default n diff --git a/components/drivers/firmware/psci/psci.c b/components/drivers/firmware/psci/psci.c index c1b4ff41827a..3789a96d50c4 100644 --- a/components/drivers/firmware/psci/psci.c +++ b/components/drivers/firmware/psci/psci.c @@ -319,14 +319,14 @@ static rt_err_t psci_0_2_init(struct rt_ofw_node *np) _psci_ops.get_affinity_info = psci_affinity_info; _psci_ops.migrate_info_type = psci_migrate_info_type; - if (!rt_pm_shutdown) + if (!rt_pm_machine_shutdown) { - rt_pm_shutdown = psci_system_off; + rt_pm_machine_shutdown = psci_system_off; } - if (!rt_pm_reset) + if (!rt_pm_machine_reset) { - rt_pm_reset = psci_system_reboot; + rt_pm_machine_reset = psci_system_reboot; } } else @@ -427,4 +427,4 @@ static int psci_drv_register(void) return 0; } -INIT_SUBSYS_EXPORT(psci_drv_register); +INIT_FRAMEWORK_EXPORT(psci_drv_register); diff --git a/components/drivers/firmware/qemu/SConscript b/components/drivers/firmware/qemu/SConscript new file mode 100644 index 000000000000..1f5108aa31e8 --- /dev/null +++ b/components/drivers/firmware/qemu/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_FIRMWARE_QEMU_FW_CFG']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = Glob('*.c') + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/firmware/qemu/fw_cfg.c b/components/drivers/firmware/qemu/fw_cfg.c new file mode 100644 index 000000000000..2d27118fc0cb --- /dev/null +++ b/components/drivers/firmware/qemu/fw_cfg.c @@ -0,0 +1,472 @@ +/* + * 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 + +#define DBG_TAG "fw.qemu" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#include +#include + +#include "fw_cfg.h" + +/* arch-specific ctrl & data register offsets are not available in ACPI, DT */ +#if !(defined(FW_CFG_CTRL_OFF) && defined(FW_CFG_DATA_OFF)) +# if (defined(ARCH_ARM) || defined(ARCH_ARMV8) || defined(ARCH_LOONGARCH)) +# define FW_CFG_CTRL_OFF 0x08 +# define FW_CFG_DATA_OFF 0x00 +# define FW_CFG_DMA_OFF 0x10 +# elif defined(ARCH_PARISC) /* parisc */ +# define FW_CFG_CTRL_OFF 0x00 +# define FW_CFG_DATA_OFF 0x04 +# elif (defined(ARCH_PPC) || defined(ARCH_SPARC32)) /* ppc/mac,sun4m */ +# define FW_CFG_CTRL_OFF 0x00 +# define FW_CFG_DATA_OFF 0x02 +# elif (defined(ARCH_IA32) || defined(ARCH_SPARC64)) /* x86, sun4u */ +# define FW_CFG_CTRL_OFF 0x00 +# define FW_CFG_DATA_OFF 0x01 +# define FW_CFG_DMA_OFF 0x04 +# else +# error "QEMU FW_CFG not available on this architecture!" +# endif +#endif + +struct fw_cfg_info +{ + struct rt_object obj; + + rt_list_t list; + + rt_uint32_t size; + rt_uint16_t select; + char name[FW_CFG_MAX_FILE_PATH]; +}; +#define raw_to_fw_cfg_info(raw) rt_container_of(raw, struct fw_cfg_info, obj) + +static void *_fw_cfg_dev_base; +static void *_fw_cfg_reg_ctrl; +static void *_fw_cfg_reg_data; +static void *_fw_cfg_reg_dma; +static rt_bool_t _fw_cfg_is_mmio; +static rt_uint32_t _fw_cfg_rev = 0; + +static rt_object_t _directfs_firmware_root = RT_NULL; +static struct rt_spinlock _fw_cfg_dev_lock = { 0 }; +static rt_list_t _fw_cfg_nodes = RT_LIST_OBJECT_INIT(_fw_cfg_nodes); + +static void fw_cfg_sel_endianness(rt_uint16_t key) +{ + rt_hw_barrier(dsb, st); + + if (_fw_cfg_is_mmio) + { + HWREG16(_fw_cfg_reg_ctrl) = rt_cpu_to_be16(key); + } + else + { + HWREG16(_fw_cfg_reg_ctrl) = key; + } +} + +static rt_base_t fw_cfg_read_blob(rt_uint16_t key, void *buf, rt_off_t pos, rt_size_t count) +{ + rt_uint8_t tmp; + + rt_spin_lock(&_fw_cfg_dev_lock); + fw_cfg_sel_endianness(key); + + while (pos-- > 0) + { + tmp = HWREG8(_fw_cfg_reg_data); + } + + if (count) + { + int loop = count; + rt_uint8_t *buffer = buf; + + do { + tmp = HWREG8(_fw_cfg_reg_data); + *buffer++ = tmp; + } while (--loop); + } + + rt_spin_unlock(&_fw_cfg_dev_lock); + + return count; +} + +rt_inline rt_bool_t fw_cfg_dma_enabled(void) +{ + return (_fw_cfg_rev & FW_CFG_VERSION_DMA) && _fw_cfg_reg_dma; +} + +/* qemu fw_cfg device is sync today, but spec says it may become async */ +static void fw_cfg_wait_for_control(struct fw_cfg_dma_access *dma) +{ + for (;;) + { + rt_uint32_t ctrl = rt_be32_to_cpu(HWREG32(&dma->control)); + + /* do not reorder the read to d->control */ + rt_hw_barrier(dsb, ld); + + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0) + { + break; + } + + rt_hw_cpu_relax(); + } +} + +static rt_base_t fw_cfg_dma_transfer(void *address, rt_uint32_t length, rt_uint32_t control) +{ + rt_ubase_t dma_pa; + rt_base_t res = length; + struct fw_cfg_dma_access dma = + { + .address = rt_cpu_to_be64((rt_uint64_t)(address ? rt_kmem_v2p(address) : 0)), + .length = rt_cpu_to_be32(length), + .control = rt_cpu_to_be32(control), + }; + + dma_pa = (rt_ubase_t)rt_kmem_v2p(&dma); + + HWREG32(_fw_cfg_reg_dma) = rt_cpu_to_be32((rt_uint64_t)dma_pa >> 32); + /* force memory to sync before notifying device via MMIO */ + rt_hw_barrier(dsb, st); + HWREG32(_fw_cfg_reg_dma + 4) = rt_cpu_to_be32(dma_pa); + + fw_cfg_wait_for_control(&dma); + + if ((rt_be32_to_cpu(HWREG32(&dma.control)) & FW_CFG_DMA_CTL_ERROR)) + { + res = -RT_EIO; + } + + return res; +} + +static rt_base_t fw_cfg_write_blob(rt_uint16_t key, void *buf, rt_off_t pos, rt_size_t count) +{ + rt_base_t res = count; + + rt_spin_lock(&_fw_cfg_dev_lock); + + if (pos == 0) + { + res = fw_cfg_dma_transfer(buf, count, key << 16 | FW_CFG_DMA_CTL_SELECT | FW_CFG_DMA_CTL_WRITE); + } + else + { + fw_cfg_sel_endianness(key); + res = fw_cfg_dma_transfer(RT_NULL, pos, FW_CFG_DMA_CTL_SKIP); + + if (res >= 0) + { + res = fw_cfg_dma_transfer(buf, count, FW_CFG_DMA_CTL_WRITE); + } + } + + rt_spin_unlock(&_fw_cfg_dev_lock); + + return res; +} + +#ifdef RT_USING_CRASH_CORE +static rt_base_t fw_cfg_write_vmcoreinfo(const struct fw_cfg_file *file) +{ + rt_ubase_t res; + struct fw_cfg_vmcoreinfo info = + { + .guest_format = rt_cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF), + .size = rt_cpu_to_le32(VMCOREINFO_NOTE_SIZE), + .paddr = rt_cpu_to_le64(vmcoreinfo_note_paddr()), + }; + + res = fw_cfg_write_blob(rt_be16_to_cpu(file->select), &info, 0, sizeof(struct fw_cfg_vmcoreinfo)); + + return res; +} +#endif /* RT_USING_CRASH_CORE */ + +#define fourcc_code(a, b, c, d) ((rt_uint32_t)(a) | ((rt_uint32_t)(b) << 8) | ((rt_uint32_t)(c) << 16) | ((rt_uint32_t)(d) << 24)) + +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') + +static rt_base_t fw_cfg_setup_ramfb(const struct fw_cfg_file *file) +{ + rt_ubase_t res; + void *fb = rt_malloc_align(800 * 600 * 4, 4096); + struct fw_cfg_ram_fb ram_fb = + { + .addr = rt_cpu_to_be64((rt_ubase_t)rt_kmem_v2p(fb)), + .fourcc = rt_cpu_to_be32(DRM_FORMAT_XRGB8888), + .flags = rt_cpu_to_be32(0), + .width = rt_cpu_to_be32(800), + .height = rt_cpu_to_be32(600), + .stride = rt_cpu_to_be32(4 * 800), + }; + + res = fw_cfg_write_blob(rt_be16_to_cpu(file->select), &ram_fb, 0, sizeof(struct fw_cfg_ram_fb)); + + rt_memset(fb, 0xff, 800 * 600 * 4); + + return res; +} + +static rt_ssize_t fw_cfg_directfs_read_raw(rt_object_t obj, struct directfs_bin_attribute *attr, + char *buffer, rt_off_t pos, rt_size_t count) +{ + rt_ssize_t res; + struct fw_cfg_info *info = raw_to_fw_cfg_info(obj); + + if (pos <= info->size) + { + if (count > info->size - pos) + { + count = info->size - pos; + } + + res = fw_cfg_read_blob(info->select, buffer, pos, count); + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +static struct directfs_bin_attribute fw_cfg_directfs_attr_raw = +{ + .attr = + { + .name = "raw", + }, + .read = fw_cfg_directfs_read_raw, +}; + +static rt_err_t fw_cfg_register_file(const struct fw_cfg_file *file) +{ + rt_err_t res = RT_EOK; + struct fw_cfg_info *info = rt_malloc(sizeof(*info)); + + if (info) + { + char *path; + rt_object_t parent = _directfs_firmware_root; + + #ifdef RT_USING_CRASH_CORE + if (fw_cfg_dma_enabled() && !rt_strcmp(file->name, FW_CFG_VMCOREINFO_FILENAME)) + { + if (fw_cfg_write_vmcoreinfo(file) < 0) + { + LOG_W("failed to write vmcoreinfo"); + } + } + #endif /* RT_USING_CRASH_CORE */ + + if (fw_cfg_dma_enabled() && !rt_strcmp(file->name, FW_CFG_RAMFB_FILENAME)) + { + if (fw_cfg_setup_ramfb(file) < 0) + { + LOG_W("failed to setup ramfb"); + } + } + + rt_list_init(&info->list); + + info->size = rt_be32_to_cpu(file->size); + info->select = rt_be16_to_cpu(file->select); + rt_strncpy(info->name, file->name, FW_CFG_MAX_FILE_PATH); + + rt_list_insert_before(&_fw_cfg_nodes, &info->list); + + path = info->name; + + while (*path) + { + const char *basename = path; + + while (*path && *path != '/') + { + ++path; + } + + if (*path) + { + rt_object_t dir; + + *path = '\0'; + dir = dfs_directfs_find_object(parent, basename); + + if (!dir) + { + dir = rt_malloc(sizeof(*dir)); + + if (!dir) + { + break; + } + + dfs_directfs_create_link(parent, dir, basename); + } + + parent = dir; + *path = '/'; + } + else + { + dfs_directfs_create_link(parent, &info->obj, basename); + dfs_directfs_create_bin_file(&info->obj, &fw_cfg_directfs_attr_raw); + + break; + } + + ++path; + } + } + + return res; +} + +static rt_err_t fw_cfg_register_dir_entries(void) +{ + rt_err_t err = 0; + rt_uint32_t count; + rt_size_t dir_size; + rt_be32_t files_count; + struct fw_cfg_file *dir; + + err = fw_cfg_read_blob(FW_CFG_FILE_DIR, &files_count, 0, sizeof(files_count)); + + if (err >= 0) + { + count = rt_be32_to_cpu(files_count); + dir_size = count * sizeof(struct fw_cfg_file); + + dir = rt_malloc(dir_size); + + if (dir) + { + err = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size); + + if (err >= 0) + { + _directfs_firmware_root = dfs_directfs_find_object(RT_NULL, "firmware"); + + for (int i = 0; i < count; ++i) + { + if ((err = fw_cfg_register_file(&dir[i]))) + { + break; + } + } + } + + rt_free(dir); + } + else + { + err = -RT_ENOMEM; + } + } + + return err; +} + +static rt_err_t qemu_fw_cfg_ofw_init(struct rt_platform_device *pdev, rt_uint32_t *ctrl, rt_uint32_t *data, rt_uint32_t *dma) +{ + struct rt_ofw_node *np = pdev->parent.ofw_node; + + rt_ofw_prop_read_u32(np, "ctrl", ctrl); + rt_ofw_prop_read_u32(np, "data", data); + rt_ofw_prop_read_u32(np, "dma", dma); + + _fw_cfg_dev_base = rt_ofw_iomap(np, 0); + + return _fw_cfg_dev_base ? RT_EOK : -RT_ERROR; +} + +static rt_err_t qemu_fw_cfg_probe(struct rt_platform_device *pdev) +{ + rt_le32_t rev; + rt_err_t err = RT_EOK; + char sig[FW_CFG_SIG_SIZE]; + rt_uint32_t ctrl = FW_CFG_CTRL_OFF, data = FW_CFG_DATA_OFF, dma = FW_CFG_DMA_OFF; + + if ((err = qemu_fw_cfg_ofw_init(pdev, &ctrl, &data, &dma))) + { + goto _fail; + } + +#ifdef ARCH_SUPPORT_PIO + _fw_cfg_is_mmio = RT_FALSE; +#else + _fw_cfg_is_mmio = RT_TRUE; +#endif + + _fw_cfg_reg_ctrl = _fw_cfg_dev_base + ctrl; + _fw_cfg_reg_data = _fw_cfg_dev_base + data; + _fw_cfg_reg_dma = _fw_cfg_dev_base + dma; + + if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE) < 0 || rt_memcmp(sig, "QEMU", FW_CFG_SIG_SIZE)) + { + err = -RT_ENOSYS; + goto _fail; + } + + if (fw_cfg_read_blob(FW_CFG_ID, &rev, 0, sizeof(rev)) < 0) + { + err = -RT_ENOSYS; + goto _fail; + } + + _fw_cfg_rev = rt_le32_to_cpu(rev); + + fw_cfg_register_dir_entries(); + +_fail: + return err; +} + +static const struct rt_ofw_node_id qemu_fw_cfg_ofw_ids[] = +{ + { .compatible = "qemu,fw-cfg-mmio", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver qemu_fw_cfg_driver = +{ + .name = "qemu-fw-cfg", + .ids = qemu_fw_cfg_ofw_ids, + + .probe = qemu_fw_cfg_probe, +}; + +static int qemu_fw_cfg_drv_register(void) +{ + rt_platform_driver_register(&qemu_fw_cfg_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(qemu_fw_cfg_drv_register); diff --git a/components/drivers/firmware/qemu/fw_cfg.h b/components/drivers/firmware/qemu/fw_cfg.h new file mode 100644 index 000000000000..412d1b98ad1a --- /dev/null +++ b/components/drivers/firmware/qemu/fw_cfg.h @@ -0,0 +1,122 @@ +/* + * 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 __QEMU_FW_CFG_H__ +#define __QEMU_FW_CFG_H__ + +#include +#include + +#define FW_CFG_ACPI_DEVICE_ID "QEMU0002" + +/* selector key values for "well-known" fw_cfg entries */ +#define FW_CFG_SIGNATURE 0x00 +#define FW_CFG_ID 0x01 +#define FW_CFG_UUID 0x02 +#define FW_CFG_RAM_SIZE 0x03 +#define FW_CFG_NOGRAPHIC 0x04 +#define FW_CFG_NB_CPUS 0x05 +#define FW_CFG_MACHINE_ID 0x06 +#define FW_CFG_KERNEL_ADDR 0x07 +#define FW_CFG_KERNEL_SIZE 0x08 +#define FW_CFG_KERNEL_CMDLINE 0x09 +#define FW_CFG_INITRD_ADDR 0x0a +#define FW_CFG_INITRD_SIZE 0x0b +#define FW_CFG_BOOT_DEVICE 0x0c +#define FW_CFG_NUMA 0x0d +#define FW_CFG_BOOT_MENU 0x0e +#define FW_CFG_MAX_CPUS 0x0f +#define FW_CFG_KERNEL_ENTRY 0x10 +#define FW_CFG_KERNEL_DATA 0x11 +#define FW_CFG_INITRD_DATA 0x12 +#define FW_CFG_CMDLINE_ADDR 0x13 +#define FW_CFG_CMDLINE_SIZE 0x14 +#define FW_CFG_CMDLINE_DATA 0x15 +#define FW_CFG_SETUP_ADDR 0x16 +#define FW_CFG_SETUP_SIZE 0x17 +#define FW_CFG_SETUP_DATA 0x18 +#define FW_CFG_FILE_DIR 0x19 + +#define FW_CFG_FILE_FIRST 0x20 +#define FW_CFG_FILE_SLOTS_MIN 0x10 + +#define FW_CFG_WRITE_CHANNEL 0x4000 +#define FW_CFG_ARCH_LOCAL 0x8000 +#define FW_CFG_ENTRY_MASK (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)) + +#define FW_CFG_INVALID 0xffff + +/* width in bytes of fw_cfg control register */ +#define FW_CFG_CTL_SIZE 0x02 + +/* fw_cfg "file name" is up to 56 characters (including terminating nul) */ +#define FW_CFG_MAX_FILE_PATH 56 + +/* size in bytes of fw_cfg signature */ +#define FW_CFG_SIG_SIZE 4 + +/* FW_CFG_ID bits */ +#define FW_CFG_VERSION 0x01 +#define FW_CFG_VERSION_DMA 0x02 + +/* fw_cfg file directory entry type */ +struct fw_cfg_file +{ + rt_be32_t size; + rt_be16_t select; + rt_le16_t reserved; + char name[FW_CFG_MAX_FILE_PATH]; +}; + +/* FW_CFG_DMA_CONTROL bits */ +#define FW_CFG_DMA_CTL_ERROR 0x01 +#define FW_CFG_DMA_CTL_READ 0x02 +#define FW_CFG_DMA_CTL_SKIP 0x04 +#define FW_CFG_DMA_CTL_SELECT 0x08 +#define FW_CFG_DMA_CTL_WRITE 0x10 + +#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */ + +/* Control as first field allows for different structures selected by this + * field, which might be useful in the future + */ +struct fw_cfg_dma_access +{ + rt_be32_t control; + rt_be32_t length; + rt_be64_t address; +} __attribute__ ((packed)); + +#define FW_CFG_RAMFB_FILENAME "etc/ramfb" + +struct fw_cfg_ram_fb +{ + rt_be64_t addr; + rt_be32_t fourcc; + rt_be32_t flags; + rt_be32_t width; + rt_be32_t height; + rt_be32_t stride; +} __attribute__ ((packed)); + +#define FW_CFG_VMCOREINFO_FILENAME "etc/vmcoreinfo" + +#define FW_CFG_VMCOREINFO_FORMAT_NONE 0x0 +#define FW_CFG_VMCOREINFO_FORMAT_ELF 0x1 + +struct fw_cfg_vmcoreinfo +{ + rt_le16_t host_format; + rt_le16_t guest_format; + rt_le32_t size; + rt_le64_t paddr; +} __attribute__ ((packed)); + +#endif /* __QEMU_FW_CFG_H__ */ diff --git a/components/drivers/hwcrypto/Kconfig b/components/drivers/hwcrypto/Kconfig new file mode 100644 index 000000000000..213403e803cd --- /dev/null +++ b/components/drivers/hwcrypto/Kconfig @@ -0,0 +1,173 @@ +menuconfig RT_USING_HWCRYPTO + bool "Using Hardware Crypto drivers" + default n + + if RT_USING_HWCRYPTO + config RT_HWCRYPTO_DEFAULT_NAME + string "Hardware crypto device name" + default "hwcryto" + + config RT_HWCRYPTO_IV_MAX_SIZE + int "IV max size" + default "16" + + config RT_HWCRYPTO_KEYBIT_MAX_SIZE + int "Key max bit length" + default 256 + + config RT_HWCRYPTO_USING_GCM + bool "Using Hardware GCM" + default n + + config RT_HWCRYPTO_USING_AES + bool "Using Hardware AES" + default n + + if RT_HWCRYPTO_USING_AES + config RT_HWCRYPTO_USING_AES_ECB + bool "Using Hardware AES ECB mode" + default y + + config RT_HWCRYPTO_USING_AES_CBC + bool "Using Hardware AES CBC mode" + default n + + config RT_HWCRYPTO_USING_AES_CFB + bool "Using Hardware AES CFB mode" + default n + + config RT_HWCRYPTO_USING_AES_CTR + bool "Using Hardware AES CTR mode" + default n + + config RT_HWCRYPTO_USING_AES_OFB + bool "Using Hardware AES OFB mode" + default n + endif + + config RT_HWCRYPTO_USING_DES + bool "Using Hardware DES" + default n + + if RT_HWCRYPTO_USING_DES + config RT_HWCRYPTO_USING_DES_ECB + bool "Using Hardware DES ECB mode" + default y + + config RT_HWCRYPTO_USING_DES_CBC + bool "Using Hardware DES CBC mode" + default n + endif + + config RT_HWCRYPTO_USING_3DES + bool "Using Hardware 3DES" + default n + + if RT_HWCRYPTO_USING_3DES + config RT_HWCRYPTO_USING_3DES_ECB + bool "Using Hardware 3DES ECB mode" + default y + + config RT_HWCRYPTO_USING_3DES_CBC + bool "Using Hardware 3DES CBC mode" + default n + endif + + config RT_HWCRYPTO_USING_RC4 + bool "Using Hardware RC4" + default n + + config RT_HWCRYPTO_USING_MD5 + bool "Using Hardware MD5" + default n + + config RT_HWCRYPTO_USING_SHA1 + bool "Using Hardware SHA1" + default n + + config RT_HWCRYPTO_USING_SHA2 + bool "Using Hardware SHA2" + default n + + if RT_HWCRYPTO_USING_SHA2 + config RT_HWCRYPTO_USING_SHA2_224 + bool "Using Hardware SHA2_224 mode" + default n + + config RT_HWCRYPTO_USING_SHA2_256 + bool "Using Hardware SHA2_256 mode" + default y + + config RT_HWCRYPTO_USING_SHA2_384 + bool "Using Hardware SHA2_384 mode" + default n + + config RT_HWCRYPTO_USING_SHA2_512 + bool "Using Hardware SHA2_512 mode" + default n + endif + + config RT_HWCRYPTO_USING_RNG + bool "Using Hardware RNG" + default n + + config RT_HWCRYPTO_USING_CRC + bool "Using Hardware CRC" + default n + + if RT_HWCRYPTO_USING_CRC + config RT_HWCRYPTO_USING_CRC_07 + bool "Using Hardware CRC-8 0x07 polynomial" + default n + + config RT_HWCRYPTO_USING_CRC_8005 + bool "Using Hardware CRC-16 0x8005 polynomial" + default n + + config RT_HWCRYPTO_USING_CRC_1021 + bool "Using Hardware CRC-16 0x1021 polynomial" + default n + + config RT_HWCRYPTO_USING_CRC_3D65 + bool "Using Hardware CRC-16 0x3D65 polynomial" + default n + + config RT_HWCRYPTO_USING_CRC_04C11DB7 + bool "Using Hardware CRC-32 0x04C11DB7 polynomial" + default n + endif + + config RT_HWCRYPTO_USING_BIGNUM + bool "Using Hardware bignum" + default n + + if RT_HWCRYPTO_USING_BIGNUM + config RT_HWCRYPTO_USING_BIGNUM_EXPTMOD + bool "Using Hardware bignum expt_mod operation" + default y + + config RT_HWCRYPTO_USING_BIGNUM_MULMOD + bool "Using Hardware bignum mul_mod operation" + default y + + config RT_HWCRYPTO_USING_BIGNUM_MUL + bool "Using Hardware bignum mul operation" + default n + + config RT_HWCRYPTO_USING_BIGNUM_ADD + bool "Using Hardware bignum add operation" + default n + + config RT_HWCRYPTO_USING_BIGNUM_SUB + bool "Using Hardware bignum sub operation" + default n + endif + endif + +config RT_HWCRYPTO_RNG_ROCKCHIP + bool "Rockchip Random Number Generator support" + depends on RT_USING_DM + depends on RT_USING_HWCRYPTO + select RT_HWCRYPTO_USING_RNG + select RT_USING_RESET + default n diff --git a/components/drivers/hwcrypto/SConscript b/components/drivers/hwcrypto/SConscript index 90feff50b36d..7f814d60a0ec 100644 --- a/components/drivers/hwcrypto/SConscript +++ b/components/drivers/hwcrypto/SConscript @@ -29,6 +29,9 @@ if GetDepend(['RT_HWCRYPTO_USING_CRC']): if GetDepend(['RT_HWCRYPTO_USING_BIGNUM']): src += ['hw_bignum.c'] +if GetDepend(['RT_HWCRYPTO_RNG_ROCKCHIP']): + src += ['hw-rng-rockchip.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWCRYPTO'], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/hwcrypto/hw-rng-rockchip.c b/components/drivers/hwcrypto/hw-rng-rockchip.c new file mode 100644 index 000000000000..ce5174042824 --- /dev/null +++ b/components/drivers/hwcrypto/hw-rng-rockchip.c @@ -0,0 +1,548 @@ +/* + * 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.rockchip" +#define DBG_LVL DBG_INFO +#include + +#include "../../soc/rockchip/rockchip.h" + +#define ROCKCHIP_AUTOSUSPEND_DELAY 100 +#define ROCKCHIP_POLL_PERIOD_US 100 +#define ROCKCHIP_POLL_TIMEOUT_US 50000 +#define RK_MAX_RNG_BYTE (32) + +/* start of CRYPTO V1 register define */ +#define CRYPTO_V1_CTRL 0x0008 +#define CRYPTO_V1_RNG_START RT_BIT(8) +#define CRYPTO_V1_RNG_FLUSH RT_BIT(9) + +#define CRYPTO_V1_TRNG_CTRL 0x0200 +#define CRYPTO_V1_OSC_ENABLE RT_BIT(16) +#define CRYPTO_V1_TRNG_SAMPLE_PERIOD(x) (x) + +#define CRYPTO_V1_TRNG_DOUT_0 0x0204 +/* end of CRYPTO V1 register define */ + +/* start of CRYPTO V2 register define */ +#define CRYPTO_V2_RNG_DEFAULT_OFFSET 0x0400 +#define CRYPTO_V2_RNG_CTL 0x0 +#define CRYPTO_V2_RNG_64_BIT_LEN ((0x00) << (4)) +#define CRYPTO_V2_RNG_128_BIT_LEN ((0x01) << (4)) +#define CRYPTO_V2_RNG_192_BIT_LEN ((0x02) << (4)) +#define CRYPTO_V2_RNG_256_BIT_LEN ((0x03) << (4)) +#define CRYPTO_V2_RNG_FATESY_SOC_RING ((0x00) << (2)) +#define CRYPTO_V2_RNG_SLOWER_SOC_RING_0 ((0x01) << (2)) +#define CRYPTO_V2_RNG_SLOWER_SOC_RING_1 ((0x02) << (2)) +#define CRYPTO_V2_RNG_SLOWEST_SOC_RING ((0x03) << (2)) +#define CRYPTO_V2_RNG_ENABLE RT_BIT(1) +#define CRYPTO_V2_RNG_START RT_BIT(0) +#define CRYPTO_V2_RNG_SAMPLE_CNT 0x0004 +#define CRYPTO_V2_RNG_DOUT_0 0x0010 +/* end of CRYPTO V2 register define */ + +/* start of TRNG_V1 register define */ +/* TRNG is no longer subordinate to the Crypto module */ +#define TRNG_V1_CTRL 0x0000 +#define TRNG_V1_CTRL_NOP ((0x00) << (0)) +#define TRNG_V1_CTRL_RAND ((0x01) << (0)) +#define TRNG_V1_CTRL_SEED ((0x02) << (0)) + +#define TRNG_V1_STAT 0x0004 +#define TRNG_V1_STAT_SEEDED RT_BIT(9) +#define TRNG_V1_STAT_GENERATING RT_BIT(30) +#define TRNG_V1_STAT_RESEEDING RT_BIT(31) + +#define TRNG_V1_MODE 0x0008 +#define TRNG_V1_MODE_128_BIT ((0x00) << (3)) +#define TRNG_V1_MODE_256_BIT ((0x01) << (3)) + +#define TRNG_V1_IE 0x0010 +#define TRNG_V1_IE_GLBL_EN RT_BIT(31) +#define TRNG_V1_IE_SEED_DONE_EN RT_BIT(1) +#define TRNG_V1_IE_RAND_RDY_EN RT_BIT(0) + +#define TRNG_V1_ISTAT 0x0014 +#define TRNG_V1_ISTAT_RAND_RDY RT_BIT(0) + +/* RAND0 ~ RAND7 */ +#define TRNG_V1_RAND0 0x0020 +#define TRNG_V1_RAND7 0x003C + +#define TRNG_V1_AUTO_RQSTS 0x0060 + +#define TRNG_V1_VERSION 0x00F0 +#define TRNG_v1_VERSION_CODE 0x46bc +/* end of TRNG_V1 register define */ + +struct rockchip_rng; + +struct rockchip_rng_soc_data +{ + rt_uint32_t default_offset; + + rt_err_t (*init)(struct rockchip_rng *rk_rng); + rt_uint32_t (*read)(struct rockchip_rng *rk_rng, void *buf, rt_size_t max, rt_bool_t wait); +}; + +struct rockchip_rng +{ + struct rt_hwcrypto_device parent; + + void *regs; + + struct rt_clk_array *clk_arr; + struct rt_reset_control *rstc; + + const struct rockchip_rng_soc_data *soc_data; +}; + +#define raw_to_rockchip_rng(raw) rt_container_of(raw, struct rockchip_rng, parent) + +static void rockchip_rng_writel(struct rockchip_rng *rk_rng, rt_uint32_t val, int offset) +{ + HWREG32(rk_rng->regs + offset) = val; +} + +static rt_uint32_t rockchip_rng_readl(struct rockchip_rng *rk_rng, int offset) +{ + return HWREG32(rk_rng->regs + offset); +} + +static void rockchip_rng_read_regs(struct rockchip_rng *rk_rng, rt_uint32_t offset, + void *buf, rt_size_t size) +{ + rt_uint32_t *data = buf; + + for (int i = 0; i < size; i += 4, ++offset) + { + data[i] = rt_be32_to_cpu(rockchip_rng_readl(rk_rng, offset)); + } +} + +static rt_uint32_t rockchip_crypto_v1_read(struct rockchip_rng *rk_rng, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_tick_t start; + rt_uint32_t res = 0, reg_ctrl = 0; + int timeout = rt_tick_from_millisecond(ROCKCHIP_POLL_TIMEOUT_US / 1000); + + /* enable osc_ring to get entropy, sample period is set as 100 */ + reg_ctrl = CRYPTO_V1_OSC_ENABLE | CRYPTO_V1_TRNG_SAMPLE_PERIOD(100); + rockchip_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_TRNG_CTRL); + + reg_ctrl = HIWORD_UPDATE(CRYPTO_V1_RNG_START, CRYPTO_V1_RNG_START, 0); + + rockchip_rng_writel(rk_rng, reg_ctrl, CRYPTO_V1_CTRL); + + start = rt_tick_get(); + + while (rockchip_rng_readl(rk_rng, CRYPTO_V1_CTRL) & CRYPTO_V1_RNG_START) + { + rt_hw_us_delay(ROCKCHIP_POLL_PERIOD_US); + + if ((rt_tick_get() - start) > timeout) + { + goto _time_out; + } + + rt_hw_cpu_relax(); + } + + res = rt_min_t(rt_size_t, max, RK_MAX_RNG_BYTE); + + rockchip_rng_read_regs(rk_rng, CRYPTO_V1_TRNG_DOUT_0, buf, res); + +_time_out: + /* close TRNG */ + rockchip_rng_writel(rk_rng, HIWORD_UPDATE(0, CRYPTO_V1_RNG_START, 0), CRYPTO_V1_CTRL); + + return res; +} + +static rt_uint32_t rockchip_crypto_v2_read(struct rockchip_rng *rk_rng, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_tick_t start; + rt_uint32_t res = 0, reg_ctrl = 0; + int timeout = rt_tick_from_millisecond(ROCKCHIP_POLL_TIMEOUT_US / 1000); + + /* enable osc_ring to get entropy, sample period is set as 100 */ + rockchip_rng_writel(rk_rng, 100, CRYPTO_V2_RNG_SAMPLE_CNT); + + reg_ctrl |= CRYPTO_V2_RNG_256_BIT_LEN; + reg_ctrl |= CRYPTO_V2_RNG_SLOWER_SOC_RING_0; + reg_ctrl |= CRYPTO_V2_RNG_ENABLE; + reg_ctrl |= CRYPTO_V2_RNG_START; + + rockchip_rng_writel(rk_rng, HIWORD_UPDATE(reg_ctrl, 0xffff, 0), CRYPTO_V2_RNG_CTL); + + start = rt_tick_get(); + + while (rockchip_rng_readl(rk_rng, CRYPTO_V2_RNG_CTL) & CRYPTO_V2_RNG_START) + { + rt_hw_us_delay(ROCKCHIP_POLL_PERIOD_US); + + if ((rt_tick_get() - start) > timeout) + { + goto _time_out; + } + + rt_hw_cpu_relax(); + } + + res = rt_min_t(rt_size_t, max, RK_MAX_RNG_BYTE); + + rockchip_rng_read_regs(rk_rng, CRYPTO_V2_RNG_DOUT_0, buf, res); + +_time_out: + /* close TRNG */ + rockchip_rng_writel(rk_rng, HIWORD_UPDATE(0, 0xffff, 0), CRYPTO_V2_RNG_CTL); + + return res; +} + +static rt_err_t rockchip_trng_v1_init(struct rockchip_rng *rk_rng) +{ + rt_uint32_t auto_reseed_cnt = 1000; + rt_uint32_t reg_ctrl, status, version; + + version = rockchip_rng_readl(rk_rng, TRNG_V1_VERSION); + + if (version != TRNG_v1_VERSION_CODE) + { + LOG_E("Wrong trng version, expected = %08x, actual = %08x", + TRNG_V1_VERSION, version); + + return -RT_EIO; + } + + status = rockchip_rng_readl(rk_rng, TRNG_V1_STAT); + + /* TRNG should wait RAND_RDY triggered if it is busy or not seeded */ + if (!(status & TRNG_V1_STAT_SEEDED) || (status & TRNG_V1_STAT_GENERATING) || + (status & TRNG_V1_STAT_RESEEDING)) + { + rt_tick_t start; + rt_uint32_t mask = TRNG_V1_STAT_SEEDED | TRNG_V1_STAT_GENERATING | + TRNG_V1_STAT_RESEEDING; + int timeout = rt_tick_from_millisecond(ROCKCHIP_POLL_TIMEOUT_US / 1000); + + rt_hw_us_delay(10); + + /* wait for GENERATING and RESEEDING flag to clear */ + start = rt_tick_get(); + + while ((rockchip_rng_readl(rk_rng, TRNG_V1_STAT) & mask) != TRNG_V1_STAT_SEEDED) + { + rt_hw_us_delay(ROCKCHIP_POLL_PERIOD_US); + + if ((rt_tick_get() - start) > timeout) + { + break; + } + + rt_hw_cpu_relax(); + } + } + + /* clear ISTAT flag because trng may auto reseeding when power on */ + reg_ctrl = rockchip_rng_readl(rk_rng, TRNG_V1_ISTAT); + rockchip_rng_writel(rk_rng, reg_ctrl, TRNG_V1_ISTAT); + + /* auto reseed after (auto_reseed_cnt * 16) byte rand generate */ + rockchip_rng_writel(rk_rng, auto_reseed_cnt, TRNG_V1_AUTO_RQSTS); + + return RT_EOK; +} + +static rt_uint32_t rockchip_trng_v1_read(struct rockchip_rng *rk_rng, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_uint32_t res = 0, reg_ctrl = 0; + + /* clear ISTAT anyway */ + reg_ctrl = rockchip_rng_readl(rk_rng, TRNG_V1_ISTAT); + rockchip_rng_writel(rk_rng, reg_ctrl, TRNG_V1_ISTAT); + + /* generate 256bit random */ + rockchip_rng_writel(rk_rng, TRNG_V1_MODE_256_BIT, TRNG_V1_MODE); + rockchip_rng_writel(rk_rng, TRNG_V1_CTRL_RAND, TRNG_V1_CTRL); + + /* + * Generate2 56 bit random data will cost 1024 clock cycles. + * Estimated at 150M RNG module frequency, it takes 6.7 microseconds. + */ + rt_hw_us_delay(10); + reg_ctrl = rockchip_rng_readl(rk_rng, TRNG_V1_ISTAT); + + if (!(reg_ctrl & TRNG_V1_ISTAT_RAND_RDY)) + { + rt_tick_t start = rt_tick_get(); + int timeout = rt_tick_from_millisecond(ROCKCHIP_POLL_TIMEOUT_US / 1000); + + /* wait RAND_RDY triggered */ + while (!(rockchip_rng_readl(rk_rng, TRNG_V1_ISTAT) & TRNG_V1_ISTAT_RAND_RDY)) + { + rt_hw_us_delay(ROCKCHIP_POLL_PERIOD_US); + + if ((rt_tick_get() - start) > timeout) + { + goto _time_out; + } + + rt_hw_cpu_relax(); + } + } + + res = rt_min_t(rt_size_t, max, RK_MAX_RNG_BYTE); + + rockchip_rng_read_regs(rk_rng, TRNG_V1_RAND0, buf, res); + + /* clear all status flag */ + rockchip_rng_writel(rk_rng, reg_ctrl, TRNG_V1_ISTAT); +_time_out: + /* close TRNG */ + rockchip_rng_writel(rk_rng, TRNG_V1_CTRL_NOP, TRNG_V1_CTRL); + + return res; +} + +static rt_uint32_t rockchip_rng_read(struct rockchip_rng *rk_rng, void *buf, + rt_size_t max, rt_bool_t wait) +{ + rt_uint32_t res; + int read_len = 0; + + if (!rk_rng->soc_data->read) + { + return 0; + } + + res = 0; + + while (max > res) + { + read_len = rk_rng->soc_data->read(rk_rng, buf + res, max - res, wait); + + if (read_len < 0) + { + res = read_len; + + break; + } + res += read_len; + } + + return res; +} + +static rt_uint32_t rockchip_rng_rand(struct hwcrypto_rng *ctx) +{ + rt_uint32_t rand; + struct rockchip_rng *rk_rng = raw_to_rockchip_rng(ctx->parent.device); + + if (rockchip_rng_read(rk_rng, &rand, sizeof(rand), RT_TRUE) != sizeof(rand)) + { + return 0; + } + + return rand; +} + +static const struct hwcrypto_rng_ops rng_ops = +{ + .update = rockchip_rng_rand, +}; + +static rt_err_t rockchip_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 rockchip_rng_destroy(struct rt_hwcrypto_ctx *ctx) +{ + rt_free(ctx->contex); +} + +static rt_err_t rockchip_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 rockchip_rng_reset(struct rt_hwcrypto_ctx *ctx) +{ +} + +static const struct rt_hwcrypto_ops rockchip_rng_ops = +{ + .create = rockchip_rng_create, + .destroy = rockchip_rng_destroy, + .copy = rockchip_rng_copy, + .reset = rockchip_rng_reset, +}; + +static rt_err_t rockchip_rng_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct rt_device *dev = &pdev->parent; + struct rockchip_rng *rk_rng = rt_calloc(1, sizeof(*rk_rng)); + + if (!rk_rng) + { + return -RT_ENOMEM; + } + + rk_rng->soc_data = pdev->id->data; + + rk_rng->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_rng->regs) + { + err = -RT_EIO; + goto _fail; + } + + if (rt_dm_dev_prop_read_bool(dev, "resets")) + { + rk_rng->rstc = rt_reset_control_get_by_name(dev, "reset"); + + if (!rk_rng->rstc) + { + err = -RT_EIO; + + goto _fail; + } + } + + if (rk_rng->rstc) + { + rt_reset_control_assert(rk_rng->rstc); + rt_hw_us_delay(10); + rt_reset_control_deassert(rk_rng->rstc); + } + + rk_rng->clk_arr = rt_clk_get_array(dev); + + if (!rk_rng->clk_arr) + { + err = -RT_EIO; + + goto _fail; + } + + rt_clk_array_prepare_enable(rk_rng->clk_arr); + + if (rk_rng->soc_data->init) + { + err = rk_rng->soc_data->init(rk_rng); + } + + if (err) + { + goto _fail; + } + + rk_rng->parent.ops = &rockchip_rng_ops; + + if ((err = rt_hwcrypto_register(&rk_rng->parent, "hwrng"))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (!rk_rng->regs) + { + rt_iounmap(rk_rng->regs); + } + if (rk_rng->rstc) + { + rt_reset_control_assert(rk_rng->rstc); + rt_reset_control_put(rk_rng->rstc); + } + if (rk_rng->clk_arr) + { + rt_clk_array_disable_unprepare(rk_rng->clk_arr); + rt_clk_array_put(rk_rng->clk_arr); + } + rt_free(rk_rng); + + return err; +} + +static const struct rockchip_rng_soc_data rk_crypto_v1_soc_data = +{ + .default_offset = 0, + .read = rockchip_crypto_v1_read, +}; + +static const struct rockchip_rng_soc_data rk_crypto_v2_soc_data = +{ + .default_offset = CRYPTO_V2_RNG_DEFAULT_OFFSET, + .read = rockchip_crypto_v2_read, +}; + +static const struct rockchip_rng_soc_data rk_trng_v1_soc_data = +{ + .default_offset = 0, + .init = rockchip_trng_v1_init, + .read = rockchip_trng_v1_read, +}; + +static const struct rt_ofw_node_id rockchip_rng_ofw_ids[] = +{ + { .compatible = "rockchip,cryptov1-rng", .data = &rk_crypto_v1_soc_data, }, + { .compatible = "rockchip,cryptov2-rng", .data = &rk_crypto_v2_soc_data, }, + { .compatible = "rockchip,trngv1", .data = &rk_trng_v1_soc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_rng_driver = +{ + .name = "rockchip-rng", + .ids = rockchip_rng_ofw_ids, + + .probe = rockchip_rng_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_rng_driver); diff --git a/components/drivers/hwspinlock/Kconfig b/components/drivers/hwspinlock/Kconfig new file mode 100644 index 000000000000..374af056f410 --- /dev/null +++ b/components/drivers/hwspinlock/Kconfig @@ -0,0 +1,15 @@ +menuconfig RT_USING_HWSPINLOCK + bool "Using Hardware Spinlock drivers" + depends on RT_USING_DM + select RT_USING_OFW + select RT_USING_ADT_REF + default n + help + Hardware spinlock modules provide hardware assistance for + synchronization and mutual exclusion between heterogeneous processors + and those not operating under a single, shared operating system. + +config RT_HWSPINLOCK_ROCKCHIP + bool "Rockchip Hardware Spinlock device" + depends on RT_USING_HWSPINLOCK + default n diff --git a/components/drivers/hwspinlock/SConscript b/components/drivers/hwspinlock/SConscript new file mode 100755 index 000000000000..dfd6370e5f74 --- /dev/null +++ b/components/drivers/hwspinlock/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_HWSPINLOCK']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['hwspinlock.c'] + +if GetDepend(['RT_HWSPINLOCK_ROCKCHIP']): + src += ['hwspinlock-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/hwspinlock/hwspinlock-rockchip.c b/components/drivers/hwspinlock/hwspinlock-rockchip.c new file mode 100644 index 000000000000..467cd1dc0a3d --- /dev/null +++ b/components/drivers/hwspinlock/hwspinlock-rockchip.c @@ -0,0 +1,126 @@ +/* + * 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 "hwspinlock_dm.h" + +#define HWSPINLOCK_NUMBER 64 +#define HWSPINLOCK_STATUS_OFFSET(x) (0x4 * (x)) +#define HWSPINLOCK_OWNER_ID 0x1 + +struct rockchip_hwspinlock +{ + struct rt_hwspinlock_bank parent; + + void *regs; +}; + +static rt_err_t rockchip_hwspinlock_trylock(struct rt_hwspinlock *hwlock) +{ + void *lock_regs = hwlock->priv; + + HWREG32(lock_regs) = HWSPINLOCK_OWNER_ID; + + /* + * Get only first 4bits and compare to HWSPINLOCK_OWNER_ID: + * when 4bits is 0, 4bits can be written with new value. + * when 4bits is not 0, 4bits cannot be written. + * when write data is 0x0000, 4bits clean to 0. + */ + + return ((HWREG32(lock_regs) & 0xf) == HWSPINLOCK_OWNER_ID); +} + +static void rockchip_hwspinlock_unlock(struct rt_hwspinlock *hwlock) +{ + void *lock_regs = hwlock->priv; + + HWREG32(lock_regs) = 0; +} + +static const struct rt_hwspinlock_ops rk_hwspinlock_ops = +{ + .trylock = rockchip_hwspinlock_trylock, + .unlock = rockchip_hwspinlock_unlock, +}; + +static rt_err_t rockchip_hwspinlock_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_hwspinlock *hwlock; + struct rt_hwspinlock_bank *bank; + struct rt_device *dev = &pdev->parent; + struct rockchip_hwspinlock *rk_hwspinlock; + + rk_hwspinlock = hwspinlock_bank_alloc(rk_hwspinlock, HWSPINLOCK_NUMBER); + + if (!rk_hwspinlock) + { + return -RT_ENOMEM; + } + + rk_hwspinlock->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_hwspinlock->regs) + { + err = -RT_EIO; + + goto _fail; + } + + bank = &rk_hwspinlock->parent; + hwlock = &bank->locks[0]; + + for (int i = 0; i < HWSPINLOCK_NUMBER; ++i, ++hwlock) + { + hwlock->priv = rk_hwspinlock->regs + HWSPINLOCK_STATUS_OFFSET(i); + } + + bank->dev = dev; + bank->ops = &rk_hwspinlock_ops; + bank->locks_nr = HWSPINLOCK_NUMBER; + + if ((err = rt_hwspinlock_bank_register(bank))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rk_hwspinlock->regs) + { + rt_iounmap(rk_hwspinlock->regs); + } + rt_free(rk_hwspinlock); + + return err; +} + +static const struct rt_ofw_node_id rockchip_hwspinlock_ofw_ids[] = +{ + { .compatible = "rockchip,hwspinlock" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_hwspinlock_driver = +{ + .name = "hwspinlock-rockchip", + .ids = rockchip_hwspinlock_ofw_ids, + + .probe = rockchip_hwspinlock_probe, +}; + +static int rockchip_hwspinlock_drv_register(void) +{ + rt_platform_driver_register(&rockchip_hwspinlock_driver); + + return 0; +} +INIT_FRAMEWORK_EXPORT(rockchip_hwspinlock_drv_register); diff --git a/components/drivers/hwspinlock/hwspinlock.c b/components/drivers/hwspinlock/hwspinlock.c new file mode 100644 index 000000000000..cd987d349640 --- /dev/null +++ b/components/drivers/hwspinlock/hwspinlock.c @@ -0,0 +1,344 @@ +/* + * 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 + +#define DBG_TAG "rtdm.hwspinlock" +#define DBG_LVL DBG_INFO +#include + +#include "hwspinlock_dm.h" + +static struct rt_spinlock hwspinlock_ops_lock = {}; +static rt_list_t hwspinlock_bank_nodes = RT_LIST_OBJECT_INIT(hwspinlock_bank_nodes); + +rt_err_t rt_hwspinlock_bank_register(struct rt_hwspinlock_bank *bank) +{ + struct rt_hwspinlock *hwlock; + + if (!bank || !bank->ops || bank->locks_nr <= 0 || !bank->dev) + { + return -RT_EINVAL; + } + + rt_list_init(&bank->list); + ref_init(&bank->ref); + + hwlock = &bank->locks[0]; + + for (int i = bank->locks_nr - 1; i >= 0; --i, ++hwlock) + { + rt_spin_lock_init(&hwlock->lock); + hwlock->used = RT_FALSE; + } + + rt_spin_lock(&hwspinlock_ops_lock); + + rt_list_insert_after(&hwspinlock_bank_nodes, &bank->list); + + rt_spin_unlock(&hwspinlock_ops_lock); + + rt_dm_dev_bind_fwdata(bank->dev, RT_NULL, bank); + + return RT_EOK; +} + +rt_err_t rt_hwspinlock_bank_unregister(struct rt_hwspinlock_bank *bank) +{ + rt_err_t err; + + if (!bank) + { + return -RT_EINVAL; + } + + rt_spin_lock(&hwspinlock_ops_lock); + + if (ref_read(&bank->ref) == 1) + { + rt_dm_dev_unbind_fwdata(bank->dev, RT_NULL); + + err = RT_EOK; + } + else + { + err = -RT_EBUSY; + } + + rt_spin_unlock(&hwspinlock_ops_lock); + + return err; +} + +rt_err_t rt_hwspin_trylock_mode(struct rt_hwspinlock *hwlock, int mode, + rt_ubase_t *out_level) +{ + rt_err_t err; + + if (!hwlock || (!out_level && mode == RT_HWSPINLOCK_IRQSTATE)) + { + return -RT_EINVAL; + } + + switch (mode) + { + case RT_HWSPINLOCK_IRQSTATE: + err = rt_spin_trylock_irqsave(&hwlock->lock, out_level); + break; + + case RT_HWSPINLOCK_RAW: + case RT_HWSPINLOCK_IN_ATOMIC: + err = RT_EOK; + break; + + default: + err = rt_spin_trylock(&hwlock->lock); + break; + } + + if (err < 0) + { + return -RT_EBUSY; + } + + err = hwlock->bank->ops->trylock(hwlock); + + if (!err) + { + switch (mode) + { + case RT_HWSPINLOCK_IRQSTATE: + rt_spin_unlock_irqrestore(&hwlock->lock, *out_level); + break; + + case RT_HWSPINLOCK_RAW: + case RT_HWSPINLOCK_IN_ATOMIC: + break; + + default: + rt_spin_unlock(&hwlock->lock); + break; + } + + return -RT_EBUSY; + } + + rt_hw_dmb(); + + return err; +} + +rt_err_t rt_hwspin_lock_timeout_mode(struct rt_hwspinlock *hwlock, int mode, + rt_uint32_t timeout_ms, rt_ubase_t *out_level) +{ + rt_err_t err; + rt_base_t us_timeout; + rt_tick_t timeout = rt_tick_get() + rt_tick_from_millisecond(timeout_ms); + + if (mode == RT_HWSPINLOCK_IN_ATOMIC) + { + us_timeout = timeout_ms * 1000; + } + + for (;;) + { + err = rt_hwspin_trylock_mode(hwlock, mode, out_level); + + if (err != -RT_EBUSY) + { + break; + } + + if (mode == RT_HWSPINLOCK_IN_ATOMIC) + { + /* timeout_ms is ms unit, so delay 1/10 ms */ + const int retry_us = 100; + + rt_hw_us_delay(retry_us); + us_timeout -= retry_us; + + if (us_timeout < 0) + { + return -RT_ETIMEOUT; + } + } + else if (timeout > rt_tick_get()) + { + return -RT_ETIMEOUT; + } + + if (hwlock->bank->ops->relax) + { + hwlock->bank->ops->relax(hwlock); + } + } + + return err; +} + +void rt_hwspin_unlock_mode(struct rt_hwspinlock *hwlock, int mode, + rt_ubase_t *out_level) +{ + if (!hwlock || (!out_level && mode == RT_HWSPINLOCK_IRQSTATE)) + { + return; + } + + rt_hw_dmb(); + + hwlock->bank->ops->unlock(hwlock); + + switch (mode) + { + case RT_HWSPINLOCK_IRQSTATE: + rt_spin_unlock_irqrestore(&hwlock->lock, *out_level); + break; + + case RT_HWSPINLOCK_RAW: + case RT_HWSPINLOCK_IN_ATOMIC: + break; + + default: + rt_spin_unlock(&hwlock->lock); + break; + } +} + +static struct rt_hwspinlock *hwspinlock_request(int id) +{ + struct rt_hwspinlock_bank *bank; + struct rt_hwspinlock *hwlock = RT_NULL; + + rt_spin_lock(&hwspinlock_ops_lock); + + rt_list_for_each_entry(bank, &hwspinlock_bank_nodes, list) + { + if (id <= 0) + { + for (int i = 0; i < bank->locks_nr; ++i) + { + if (!bank->locks[i].used) + { + hwlock = &bank->locks[i]; + break; + } + } + } + else if (id >= bank->base_id && id <= bank->base_id + bank->locks_nr) + { + int offset = id - bank->base_id; + + if (!bank->locks[offset].used) + { + hwlock = &bank->locks[offset]; + break; + } + } + } + + if (hwlock) + { + hwlock->used = RT_TRUE; + } + + rt_spin_unlock(&hwspinlock_ops_lock); + + return hwlock; +} + +struct rt_hwspinlock *rt_hwspinlock_request(void) +{ + return hwspinlock_request(-1); +} + +struct rt_hwspinlock *rt_hwspinlock_request_id(int id) +{ + return hwspinlock_request(id); +} + +static void hwspinlock_release(struct ref *r) +{ + struct rt_hwspinlock_bank *bank = rt_container_of(r, struct rt_hwspinlock_bank, ref); + + LOG_E("%s is release", rt_dm_dev_get_name(bank->dev)); + + RT_ASSERT(0); +} + +rt_err_t rt_hwspinlock_free(struct rt_hwspinlock *hwlock) +{ + if (!hwlock) + { + return -RT_EINVAL; + } + + ref_put(&hwlock->bank->ref, &hwspinlock_release); + hwlock->used = RT_TRUE; + + return RT_EOK; +} + +int rt_ofw_get_hwspinlock_id(struct rt_ofw_node *np, int index) +{ + int id; + rt_err_t err; + struct rt_ofw_cell_args args; + struct rt_hwspinlock_bank *bank; + + if (!np && index < 0) + { + return -RT_EINVAL; + } + + rt_spin_lock(&hwspinlock_ops_lock); + + err = rt_ofw_parse_phandle_cells(np, "hwlocks", "#hwlock-cells", index, &args); + + if (err) + { + goto _out_lock; + } + + bank = rt_ofw_data(args.data); + rt_ofw_node_put(args.data); + + if (!bank || args.args_count != 1) + { + err = -RT_ENOSYS; + } + else + { + id = bank->base_id + args.args[0]; + } + +_out_lock: + rt_spin_unlock(&hwspinlock_ops_lock); + + return err < 0 ? err : id; +} + +int rt_ofw_get_hwspinlock_id_byname(struct rt_ofw_node *np, const char *name) +{ + int index; + + if (!np && !name) + { + return -RT_EINVAL; + } + + index = rt_ofw_prop_index_of_string(np, "hwlock-names", name); + + if (index < 0) + { + return index; + } + + return rt_ofw_get_hwspinlock_id(np, index); +} diff --git a/components/drivers/hwspinlock/hwspinlock_dm.h b/components/drivers/hwspinlock/hwspinlock_dm.h new file mode 100644 index 000000000000..7602a92c226d --- /dev/null +++ b/components/drivers/hwspinlock/hwspinlock_dm.h @@ -0,0 +1,57 @@ +/* + * 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 + */ + +#ifndef __HWSPINLOCK_DM_H__ +#define __HWSPINLOCK_DM_H__ + +#include +#include +#include + +struct rt_hwspinlock +{ + struct rt_hwspinlock_bank *bank; + struct rt_spinlock lock; + + rt_bool_t used; + void *priv; +}; + +struct rt_hwspinlock_ops +{ + rt_err_t (*trylock)(struct rt_hwspinlock *hwlock); + void (*unlock)(struct rt_hwspinlock *hwlock); + void (*relax)(struct rt_hwspinlock *hwlock); +}; + +struct rt_hwspinlock_bank +{ + rt_list_t list; + struct ref ref; + + struct rt_device *dev; + const struct rt_hwspinlock_ops *ops; + + int base_id; + rt_size_t locks_nr; + struct rt_hwspinlock locks[]; +}; + +#define hwspinlock_bank_alloc(obj, locks_nr) \ + rt_calloc(1, sizeof(typeof(*obj)) + sizeof(struct rt_hwspinlock) * (locks_nr)) + +rt_inline int hwspinlock_find_id(struct rt_hwspinlock *hwlock) +{ + int idx_offset = hwlock - &hwlock->bank->locks[0]; + + return hwlock->bank->base_id + idx_offset; +} + +#endif /* __HWSPINLOCK_DM_H__ */ diff --git a/components/drivers/hwtimer/Kconfig b/components/drivers/hwtimer/Kconfig index 624b05f6f76a..811cf27afb51 100755 --- a/components/drivers/hwtimer/Kconfig +++ b/components/drivers/hwtimer/Kconfig @@ -1,15 +1,22 @@ menuconfig RT_USING_HWTIMER - bool "Using hardware timer device drivers" + bool "Using Hardware Timer device drivers" default n config RT_HWTIMER_ARM_ARCH bool "ARM ARCH Timer" depends on RT_USING_DM depends on RT_USING_HWTIMER + depends on ARCH_ARM_CORTEX_A || ARCH_ARMV8 default n -config RT_HWTIMER_RISCV_CLINT - bool "RISC-V CLINT Timer" +config RT_HWTIMER_BCM2835 + bool "BCM2835 Timer" + depends on RT_USING_DM + depends on RT_USING_HWTIMER + default n + +config RT_HWTIMER_ROCKCHIP + bool "RockChip Timer" depends on RT_USING_DM depends on RT_USING_HWTIMER default n diff --git a/components/drivers/hwtimer/SConscript b/components/drivers/hwtimer/SConscript index 44d9c8a1a26c..1806e5cd507a 100644 --- a/components/drivers/hwtimer/SConscript +++ b/components/drivers/hwtimer/SConscript @@ -11,10 +11,13 @@ CPPPATH = [cwd + '/../include'] src = ['hwtimer.c'] if GetDepend(['RT_HWTIMER_ARM_ARCH']): - src += ['hwtimer-arm-arch.c'] + src += ['hwtimer-arm_arch.c'] -if GetDepend(['RT_HWTIMER_RISCV_CLINT']): - src += ['hwtimer-riscv-clint.c'] +if GetDepend(['RT_HWTIMER_BCM2835']): + src += ['hwtimer-bcm2835_timer.c'] + +if GetDepend(['RT_HWTIMER_ROCKCHIP']): + src += ['hwtimer-rockchip_timer.c'] group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) diff --git a/components/drivers/hwtimer/hwtimer-arm-arch.c b/components/drivers/hwtimer/hwtimer-arm_arch.c similarity index 88% rename from components/drivers/hwtimer/hwtimer-arm-arch.c rename to components/drivers/hwtimer/hwtimer-arm_arch.c index 5c53f918d8b6..651d62243020 100644 --- a/components/drivers/hwtimer/hwtimer-arm-arch.c +++ b/components/drivers/hwtimer/hwtimer-arm_arch.c @@ -305,36 +305,6 @@ static void arm_arch_timer_isr(int vector, void *param) rt_tick_increase(); } -static rt_err_t arm_arch_timer_ofw_init(struct rt_platform_device *pdev, int irq_idx) -{ - rt_err_t err = RT_EOK; - const char *irq_name[] = - { - "phys", /* Secure Phys IRQ */ - "virt", /* Non-secure Phys IRQ */ - "hyp-phys", /* Virt IRQ */ - "hyp-virt", /* Hyp IRQ */ - }; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - if (np) - { - arm_arch_timer_irq = rt_ofw_get_irq_by_name(np, irq_name[irq_idx]); - - if (arm_arch_timer_irq < 0) - { - arm_arch_timer_irq = rt_ofw_get_irq(np, irq_idx); - } - } - - if (arm_arch_timer_irq < 0) - { - err = -RT_EEMPTY; - } - - return err; -} - static int arm_arch_timer_post_init(void) { arm_arch_timer_local_enable(); @@ -345,8 +315,14 @@ INIT_SECONDARY_CPU_EXPORT(arm_arch_timer_post_init); static rt_err_t arm_arch_timer_probe(struct rt_platform_device *pdev) { - rt_err_t err; int mode_idx, irq_idx; + const char *irq_name[] = + { + "phys", /* Secure Phys IRQ */ + "virt", /* Non-secure Phys IRQ */ + "hyp-phys", /* Virt IRQ */ + "hyp-virt", /* Hyp IRQ */ + }; #if defined(ARCH_SUPPORT_TEE) mode_idx = 0; @@ -359,21 +335,28 @@ static rt_err_t arm_arch_timer_probe(struct rt_platform_device *pdev) irq_idx = 1; #endif - err = arm_arch_timer_ofw_init(pdev, irq_idx); + arm_arch_timer_irq = rt_dm_dev_get_irq_by_name(&pdev->parent, irq_name[irq_idx]); - if (!err) + if (arm_arch_timer_irq < 0) { - arm_arch_timer_ctrl_handle = ctrl_handle[mode_idx]; - arm_arch_timer_value_handle = value_handle[mode_idx]; + arm_arch_timer_irq = rt_dm_dev_get_irq(&pdev->parent, irq_idx); + } + + if (arm_arch_timer_irq < 0) + { + return -RT_EEMPTY; + } - rt_hw_interrupt_install(arm_arch_timer_irq, arm_arch_timer_isr, RT_NULL, "tick-arm-timer"); + arm_arch_timer_ctrl_handle = ctrl_handle[mode_idx]; + arm_arch_timer_value_handle = value_handle[mode_idx]; - timer_step = arm_arch_timer_get_frequency() / RT_TICK_PER_SECOND; + rt_hw_interrupt_install(arm_arch_timer_irq, arm_arch_timer_isr, RT_NULL, "tick-arm-timer"); - arm_arch_timer_local_enable(); - } + timer_step = arm_arch_timer_get_frequency() / RT_TICK_PER_SECOND; + + arm_arch_timer_local_enable(); - return err; + return RT_EOK; } static const struct rt_ofw_node_id arm_arch_timer_ofw_ids[] = diff --git a/components/drivers/hwtimer/hwtimer-bcm2835_timer.c b/components/drivers/hwtimer/hwtimer-bcm2835_timer.c new file mode 100644 index 000000000000..8b8dd8a9a6fb --- /dev/null +++ b/components/drivers/hwtimer/hwtimer-bcm2835_timer.c @@ -0,0 +1,222 @@ +/* + * 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 + +#define REG_CONTROL 0x00 +#define REG_COUNTER_LO 0x04 +#define REG_COUNTER_HI 0x08 +#define REG_COMPARE(n) (0x0c + (n) * 4) +#define MAX_TIMER 3 +#define DEFAULT_TIMER 3 + +struct bcm2835_timer +{ + struct rt_hwtimer_device parent; + + int irq; + void *base; + void *control; + void *compare; + int match_mask; + + struct rt_hwtimer_info info; +}; + +#define raw_to_bcm2835_timer(raw) rt_container_of(raw, struct bcm2835_timer, parent) + +static void bcm2835_timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state) +{ +} + +static rt_err_t bcm2835_timer_start(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + rt_err_t err = RT_EOK; + struct bcm2835_timer *bcm2835_timer = raw_to_bcm2835_timer(timer); + + switch (mode) + { + case HWTIMER_MODE_ONESHOT: + HWREG32(bcm2835_timer->compare) = HWREG32(bcm2835_timer->base + REG_COUNTER_LO) + cnt; + break; + + case HWTIMER_MODE_PERIOD: + err = -RT_ENOSYS; + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +static void bcm2835_timer_stop(struct rt_hwtimer_device *timer) +{ +} + +static rt_uint32_t bcm2835_timer_count_get(struct rt_hwtimer_device *timer) +{ + struct bcm2835_timer *bcm2835_timer = raw_to_bcm2835_timer(timer); + + return HWREG32(bcm2835_timer->base + REG_COUNTER_LO); +} + +static rt_err_t bcm2835_timer_ctrl(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct bcm2835_timer *bcm2835_timer = raw_to_bcm2835_timer(timer); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + err = -RT_ENOSYS; + break; + + case HWTIMER_CTRL_STOP: + break; + + case HWTIMER_CTRL_INFO_GET: + if (args) + { + rt_memcpy(args, &bcm2835_timer->info, sizeof(bcm2835_timer->info)); + } + else + { + err = -RT_ERROR; + } + break; + + case HWTIMER_CTRL_MODE_SET: + err = -RT_ENOSYS; + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_hwtimer_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 *bcm2835_timer = (struct bcm2835_timer *)param; + + if (HWREG32(bcm2835_timer->control) & bcm2835_timer->match_mask) + { + HWREG32(bcm2835_timer->control) = bcm2835_timer->match_mask; + + rt_device_hwtimer_isr(&bcm2835_timer->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; + } + + timer->control = timer->base + REG_CONTROL; + timer->compare = timer->base + REG_COMPARE(DEFAULT_TIMER); + timer->match_mask = RT_BIT(DEFAULT_TIMER); + + timer->irq = rt_dm_dev_get_irq(dev, DEFAULT_TIMER); + + if (timer->irq < 0) + { + err = -RT_EIO; + + goto _fail; + } + + if (rt_dm_dev_prop_read_u32(dev, "clock-frequency", &freq)) + { + err = -RT_EIO; + + goto _fail; + } + + timer->parent.ops = &bcm2835_timer_ops; + timer->parent.info = &timer->info; + + timer->info.maxfreq = freq; + timer->info.minfreq = freq; + timer->info.maxcnt = 0xffffffff; + timer->info.cntmode = HWTIMER_CNTMODE_UP; + + rt_dm_dev_set_name_auto(&timer->parent.parent, "timer"); + dev_name = rt_dm_dev_get_name(&timer->parent.parent); + + rt_device_hwtimer_register(&timer->parent, dev_name, RT_NULL); + rt_hw_interrupt_install(timer->irq, bcm2835_timer_isr, timer, dev_name); + rt_hw_interrupt_umask(timer->irq); + + return err; + +_fail: + if (timer->base) + { + rt_iounmap(timer->base); + } + rt_free(timer); + + return err; +} + +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 = "hwtimer-bcm2835", + .ids = bcm2835_timer_ofw_ids, + + .probe = bcm2835_timer_probe, +}; + +static int bcm2835_timer_drv_register(void) +{ + rt_platform_driver_register(&bcm2835_timer_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(bcm2835_timer_drv_register); diff --git a/components/drivers/hwtimer/hwtimer-riscv-clint.c b/components/drivers/hwtimer/hwtimer-riscv-clint.c deleted file mode 100755 index c03e54956e62..000000000000 --- a/components/drivers/hwtimer/hwtimer-riscv-clint.c +++ /dev/null @@ -1,251 +0,0 @@ -clint@2000000 { - interrupts-extended = <0x08 0x03 0x08 0x07 0x06 0x03 0x06 0x07 0x04 0x03 0x04 0x07 0x02 0x03 0x02 0x07>; - reg = <0x00 0x2000000 0x00 0x10000>; - compatible = "sifive,clint0", "riscv,clint0"; -}; - - -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2020 Western Digital Corporation or its affiliates. - * - * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a - * CLINT MMIO timer device. - */ - -#define pr_fmt(fmt) "clint: " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_RISCV_M_MODE -#include -#endif - -#define CLINT_IPI_OFF 0 -#define CLINT_TIMER_CMP_OFF 0x4000 -#define CLINT_TIMER_VAL_OFF 0xbff8 - -/* CLINT manages IPI and Timer for RISC-V M-mode */ -static u32 __iomem *clint_ipi_base; -static u64 __iomem *clint_timer_cmp; -static u64 __iomem *clint_timer_val; -static unsigned long clint_timer_freq; -static unsigned int clint_timer_irq; - -#ifdef CONFIG_RISCV_M_MODE -u64 __iomem *clint_time_val; -EXPORT_SYMBOL(clint_time_val); -#endif - -static void clint_send_ipi(const struct cpumask *target) -{ - unsigned int cpu; - - for_each_cpu(cpu, target) - writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu)); -} - -static void clint_clear_ipi(void) -{ - writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id())); -} - -static struct riscv_ipi_ops clint_ipi_ops = { - .ipi_inject = clint_send_ipi, - .ipi_clear = clint_clear_ipi, -}; - -#ifdef CONFIG_64BIT -#define clint_get_cycles() readq_relaxed(clint_timer_val) -#else -#define clint_get_cycles() readl_relaxed(clint_timer_val) -#define clint_get_cycles_hi() readl_relaxed(((u32 *)clint_timer_val) + 1) -#endif - -#ifdef CONFIG_64BIT -static u64 notrace clint_get_cycles64(void) -{ - return clint_get_cycles(); -} -#else /* CONFIG_64BIT */ -static u64 notrace clint_get_cycles64(void) -{ - u32 hi, lo; - - do { - hi = clint_get_cycles_hi(); - lo = clint_get_cycles(); - } while (hi != clint_get_cycles_hi()); - - return ((u64)hi << 32) | lo; -} -#endif /* CONFIG_64BIT */ - -static u64 clint_rdtime(struct clocksource *cs) -{ - return clint_get_cycles64(); -} - -static struct clocksource clint_clocksource = { - .name = "clint_clocksource", - .rating = 300, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .read = clint_rdtime, -}; - -static int clint_clock_next_event(unsigned long delta, - struct clock_event_device *ce) -{ - void __iomem *r = clint_timer_cmp + - cpuid_to_hartid_map(smp_processor_id()); - - csr_set(CSR_IE, IE_TIE); - writeq_relaxed(clint_get_cycles64() + delta, r); - return 0; -} - -static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = { - .name = "clint_clockevent", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 100, - .set_next_event = clint_clock_next_event, -}; - -static int clint_timer_starting_cpu(unsigned int cpu) -{ - struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu); - - ce->cpumask = cpumask_of(cpu); - clockevents_config_and_register(ce, clint_timer_freq, 100, 0x7fffffff); - - enable_percpu_irq(clint_timer_irq, - irq_get_trigger_type(clint_timer_irq)); - return 0; -} - -static int clint_timer_dying_cpu(unsigned int cpu) -{ - disable_percpu_irq(clint_timer_irq); - return 0; -} - -static irqreturn_t clint_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evdev = this_cpu_ptr(&clint_clock_event); - - csr_clear(CSR_IE, IE_TIE); - evdev->event_handler(evdev); - - return IRQ_HANDLED; -} - -static int __init clint_timer_init_dt(struct device_node *np) -{ - int rc; - u32 i, nr_irqs; - void __iomem *base; - struct of_phandle_args oirq; - - /* - * Ensure that CLINT device interrupts are either RV_IRQ_TIMER or - * RV_IRQ_SOFT. If it's anything else then we ignore the device. - */ - nr_irqs = of_irq_count(np); - for (i = 0; i < nr_irqs; i++) { - if (of_irq_parse_one(np, i, &oirq)) { - pr_err("%pOFP: failed to parse irq %d.\n", np, i); - continue; - } - - if ((oirq.args_count != 1) || - (oirq.args[0] != RV_IRQ_TIMER && - oirq.args[0] != RV_IRQ_SOFT)) { - pr_err("%pOFP: invalid irq %d (hwirq %d)\n", - np, i, oirq.args[0]); - return -ENODEV; - } - - /* Find parent irq domain and map timer irq */ - if (!clint_timer_irq && - oirq.args[0] == RV_IRQ_TIMER && - irq_find_host(oirq.np)) - clint_timer_irq = irq_of_parse_and_map(np, i); - } - - /* If CLINT timer irq not found then fail */ - if (!clint_timer_irq) { - pr_err("%pOFP: timer irq not found\n", np); - return -ENODEV; - } - - base = of_iomap(np, 0); - if (!base) { - pr_err("%pOFP: could not map registers\n", np); - return -ENODEV; - } - - clint_ipi_base = base + CLINT_IPI_OFF; - clint_timer_cmp = base + CLINT_TIMER_CMP_OFF; - clint_timer_val = base + CLINT_TIMER_VAL_OFF; - clint_timer_freq = riscv_timebase; - -#ifdef CONFIG_RISCV_M_MODE - /* - * Yes, that's an odd naming scheme. time_val is public, but hopefully - * will die in favor of something cleaner. - */ - clint_time_val = clint_timer_val; -#endif - - pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq); - - rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq); - if (rc) { - pr_err("%pOFP: clocksource register failed [%d]\n", np, rc); - goto fail_iounmap; - } - - sched_clock_register(clint_get_cycles64, 64, clint_timer_freq); - - rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt, - "clint-timer", &clint_clock_event); - if (rc) { - pr_err("registering percpu irq failed [%d]\n", rc); - goto fail_iounmap; - } - - rc = cpuhp_setup_state(CPUHP_AP_CLINT_TIMER_STARTING, - "clockevents/clint/timer:starting", - clint_timer_starting_cpu, - clint_timer_dying_cpu); - if (rc) { - pr_err("%pOFP: cpuhp setup state failed [%d]\n", np, rc); - goto fail_free_irq; - } - - riscv_set_ipi_ops(&clint_ipi_ops); - clint_clear_ipi(); - - return 0; - -fail_free_irq: - free_irq(clint_timer_irq, &clint_clock_event); -fail_iounmap: - iounmap(base); - return rc; -} - -TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt); -TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt); \ No newline at end of file diff --git a/components/drivers/hwtimer/hwtimer-rockchip_timer.c b/components/drivers/hwtimer/hwtimer-rockchip_timer.c new file mode 100644 index 000000000000..cab18c37a37e --- /dev/null +++ b/components/drivers/hwtimer/hwtimer-rockchip_timer.c @@ -0,0 +1,304 @@ +/* + * 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 "../clk/rockchip/clk.h" + +#define TIMER_LOAD_COUNT0 0x00 +#define TIMER_LOAD_COUNT1 0x04 +#define TIMER_CURRENT_VALUE0 0x08 +#define TIMER_CURRENT_VALUE1 0x0c +#define TIMER_CONTROL_REG3288 0x10 +#define TIMER_CONTROL_REG3399 0x1c +#define TIMER_INT_STATUS 0x18 + +#define TIMER_DISABLE 0x0 +#define TIMER_ENABLE 0x1 +#define TIMER_MODE_FREE_RUNNING (0 << 1) +#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1) +#define TIMER_INT_UNMASK (1 << 2) + +struct rk_timer +{ + struct rt_hwtimer_device parent; + + void *base; + void *ctrl; + struct rt_clk *clk; + struct rt_clk *pclk; + + int irq; + rt_uint32_t freq; + rt_uint32_t cycle; + rt_bool_t status; + + struct rt_hwtimer_info info; +}; + +#define raw_to_rk_timer(raw) rt_container_of(raw, struct rk_timer, parent) + +struct rk_timer_data +{ + rt_uint32_t ctrl_reg; +}; + +rt_inline void rk_timer_disable(struct rk_timer *timer) +{ + HWREG32(timer->ctrl) = TIMER_DISABLE; +} + +rt_inline void rk_timer_enable(struct rk_timer *timer, rt_uint32_t flags) +{ + HWREG32(timer->ctrl) = TIMER_ENABLE | flags; +} + +rt_inline rt_uint32_t rk_timer_current_value(struct rk_timer *timer) +{ + return HWREG32(timer->base + TIMER_CURRENT_VALUE0); +} + +static void rk_timer_update_counter(unsigned long cycles, struct rk_timer *timer) +{ + HWREG32(timer->base + TIMER_LOAD_COUNT0) = cycles; + HWREG32(timer->base + TIMER_LOAD_COUNT1) = 0; +} + +static void rk_timer_interrupt_clear(struct rk_timer *timer) +{ + HWREG32(timer->base + TIMER_INT_STATUS) = 1; +} + +static void rk_timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state) +{ +} + +static rt_err_t rk_timer_start(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + rt_err_t err = RT_EOK; + struct rk_timer *rk_timer = raw_to_rk_timer(timer); + + switch (mode) + { + case HWTIMER_MODE_ONESHOT: + rk_timer_disable(rk_timer); + rk_timer_update_counter(cnt, rk_timer); + rk_timer_enable(rk_timer, TIMER_MODE_USER_DEFINED_COUNT | TIMER_INT_UNMASK); + break; + + case HWTIMER_MODE_PERIOD: + rk_timer_disable(rk_timer); + rk_timer_update_counter(rk_timer->freq / HZ - 1, rk_timer); + rk_timer_enable(rk_timer, TIMER_MODE_FREE_RUNNING | TIMER_INT_UNMASK); + break; + + default: + err = -RT_EINVAL; + break; + } + + if (!err) + { + rk_timer->cycle = cnt; + rk_timer->status = RT_TRUE; + } + + return err; +} + +static void rk_timer_stop(struct rt_hwtimer_device *timer) +{ + struct rk_timer *rk_timer = raw_to_rk_timer(timer); + + rk_timer->status = RT_FALSE; + rk_timer_disable(rk_timer); +} + +static rt_uint32_t rk_timer_count_get(struct rt_hwtimer_device *timer) +{ + struct rk_timer *rk_timer = raw_to_rk_timer(timer); + + return rk_timer_current_value(rk_timer); +} + +static rt_err_t rk_timer_ctrl(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rk_timer *rk_timer = raw_to_rk_timer(timer); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + err = -RT_ENOSYS; + break; + + case HWTIMER_CTRL_STOP: + rk_timer_stop(timer); + break; + + case HWTIMER_CTRL_INFO_GET: + if (args) + { + rt_memcpy(args, &rk_timer->info, sizeof(rk_timer->info)); + } + else + { + err = -RT_ERROR; + } + break; + + case HWTIMER_CTRL_MODE_SET: + err = rk_timer_start(timer, rk_timer->cycle, (rt_hwtimer_mode_t)args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +const static struct rt_hwtimer_ops rk_timer_ops = +{ + .init = rk_timer_init, + .start = rk_timer_start, + .stop = rk_timer_stop, + .count_get = rk_timer_count_get, + .control = rk_timer_ctrl, +}; + +static void rk_timer_isr(int irqno, void *param) +{ + struct rk_timer *rk_timer = (struct rk_timer *)param; + + rk_timer_interrupt_clear(rk_timer); + + if (rk_timer->status) + { + rt_device_hwtimer_isr(&rk_timer->parent); + } +} + +static rt_err_t rk_timer_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct rk_timer *timer = rt_calloc(1, sizeof(*timer)); + const struct rk_timer_data *timer_data = pdev->id->data; + + if (!timer) + { + return -RT_ENOMEM; + } + + if (!(timer->pclk = rt_clk_get_by_name(dev, "pclk"))) + { + err = -RT_EIO; + + goto _fail; + } + + if (!(timer->clk = rt_clk_get_by_name(dev, "timer"))) + { + err = -RT_EIO; + + goto _fail; + } + + timer->base = rt_dm_dev_iomap(dev, 0); + + if (!timer->base) + { + err = -RT_EIO; + + goto _fail; + } + + timer->ctrl = timer->base + timer_data->ctrl_reg; + + rt_clk_enable(timer->pclk); + rt_clk_enable(timer->clk); + timer->freq = rt_clk_get_rate(timer->clk); + timer->irq = rt_dm_dev_get_irq(dev, 0); + + rk_timer_interrupt_clear(timer); + rk_timer_disable(timer); + + timer->parent.ops = &rk_timer_ops; + timer->parent.info = &timer->info; + + timer->info.maxfreq = timer->freq; + timer->info.minfreq = timer->freq; + timer->info.maxcnt = 0xffffffff; + timer->info.cntmode = HWTIMER_CNTMODE_UP; + + rt_dm_dev_set_name_auto(&timer->parent.parent, "timer"); + dev_name = rt_dm_dev_get_name(&timer->parent.parent); + + rt_device_hwtimer_register(&timer->parent, dev_name, RT_NULL); + rt_hw_interrupt_install(timer->irq, rk_timer_isr, timer, dev_name); + rt_hw_interrupt_umask(timer->irq); + + return err; + +_fail: + if (timer->base) + { + rt_iounmap(timer->base); + } + if (timer->pclk) + { + rt_clk_put(timer->pclk); + } + if (timer->clk) + { + rt_clk_put(timer->clk); + } + rt_free(timer); + + return err; +} + +static const struct rk_timer_data rk3288_timer_data = +{ + .ctrl_reg = TIMER_CONTROL_REG3288, +}; + +static const struct rk_timer_data rk3399_timer_data = +{ + .ctrl_reg = TIMER_CONTROL_REG3399, +}; + +static const struct rt_ofw_node_id rk_timer_ofw_ids[] = +{ + { .compatible = "rockchip,rk3288-timer", .data = &rk3288_timer_data }, + { .compatible = "rockchip,rk3399-timer", .data = &rk3399_timer_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_timer_driver = +{ + .name = "hwtimer-rockchip", + .ids = rk_timer_ofw_ids, + + .probe = rk_timer_probe, +}; + +static int rk_timer_drv_register(void) +{ + rt_platform_driver_register(&rk_timer_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(rk_timer_drv_register); diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c index b10f5dc696ed..cc43be7ee409 100644 --- a/components/drivers/hwtimer/hwtimer.c +++ b/components/drivers/hwtimer/hwtimer.c @@ -15,8 +15,24 @@ #define DBG_LVL DBG_INFO #include +#ifdef RT_USING_DM void (*rt_device_hwtimer_us_delay)(rt_uint32_t us) = RT_NULL; +void rt_hw_us_delay(rt_uint32_t us) +{ + if (rt_device_hwtimer_us_delay) + { + rt_device_hwtimer_us_delay(us); + } + else + { + LOG_E("Implemented at least in the libcpu"); + + RT_ASSERT(0); + } +} +#endif /* RT_USING_DM */ + rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv) { float overflow; diff --git a/components/drivers/i2c/Kconfig b/components/drivers/i2c/Kconfig new file mode 100755 index 000000000000..a0e7bd642c30 --- /dev/null +++ b/components/drivers/i2c/Kconfig @@ -0,0 +1,27 @@ +menuconfig RT_USING_I2C + bool "Using I2C device drivers" + default n + +if RT_USING_I2C + config RT_I2C_DEBUG + bool "Use I2C debug message" + default n + + config RT_USING_I2C_BITOPS + bool "Use GPIO to simulate I2C" + default y + + if RT_USING_I2C_BITOPS + config RT_I2C_BITOPS_DEBUG + bool "Use simulate I2C debug message" + default n + endif +endif + +config RT_I2C_RK3X + bool "Rockchip RK3xxx I2C adapter" + depends on RT_USING_DM + depends on RT_USING_I2C + select RT_MFD_SYSCON + select RT_USING_PINCTRL + default n diff --git a/components/drivers/i2c/SConscript b/components/drivers/i2c/SConscript index 5e85a645a7c3..4a2ee9260eb5 100644 --- a/components/drivers/i2c/SConscript +++ b/components/drivers/i2c/SConscript @@ -1,6 +1,8 @@ Import('RTT_ROOT') from building import * +objs = [] + cwd = GetCurrentDir() src = Split(""" i2c_core.c @@ -13,6 +15,15 @@ if GetDepend('RT_USING_I2C_BITOPS'): # The set of source files associated with this SConscript file. path = [cwd + '/../include'] +if GetDepend(['RT_USING_DM']): + src += ['i2c_bus.c', 'i2c_dm.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_I2C'], CPPPATH = path) -Return('group') +for d in os.listdir(cwd): + 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 + group + +Return('objs') diff --git a/components/drivers/i2c/busses/SConscript b/components/drivers/i2c/busses/SConscript new file mode 100644 index 000000000000..203446b96836 --- /dev/null +++ b/components/drivers/i2c/busses/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_I2C']) and not GetDepend(['RT_USING_DM']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend('RT_I2C_RK3X'): + src += ['i2c-rk3x.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/i2c/busses/i2c-rk3x.c b/components/drivers/i2c/busses/i2c-rk3x.c new file mode 100644 index 000000000000..7ca513813f6b --- /dev/null +++ b/components/drivers/i2c/busses/i2c-rk3x.c @@ -0,0 +1,1314 @@ +/* + * 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.rk3x" +#define DBG_LVL DBG_INFO +#include + +#include "../i2c_dm.h" + +/* Register Map */ +#define REG_CON 0x00 /* control register */ +#define REG_CLKDIV 0x04 /* clock divisor register */ +#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */ +#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */ +#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */ +#define REG_MRXCNT 0x14 /* number of bytes to be received */ +#define REG_IEN 0x18 /* interrupt enable */ +#define REG_IPD 0x1c /* interrupt pending */ +#define REG_FCNT 0x20 /* finished count */ + +/* Data buffer offsets */ +#define TXBUFFER_BASE 0x100 +#define RXBUFFER_BASE 0x200 + +/* REG_CON bits */ +#define REG_CON_EN RT_BIT(0) + +enum +{ + REG_CON_MOD_TX = 0, /* transmit data */ + REG_CON_MOD_REGISTER_TX, /* select register and restart */ + REG_CON_MOD_RX, /* receive data */ + REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes register addr */ +}; + +#define REG_CON_MOD(mod) ((mod) << 1) +#define REG_CON_MOD_MASK (RT_BIT(1) | RT_BIT(2)) +#define REG_CON_START RT_BIT(3) +#define REG_CON_STOP RT_BIT(4) +#define REG_CON_LASTACK RT_BIT(5) /* 1: send NACK after last received byte */ +#define REG_CON_ACTACK RT_BIT(6) /* 1: stop if NACK is received */ + +#define REG_CON_TUNING_MASK RT_GENMASK_ULL(15, 8) + +#define REG_CON_SDA_CFG(cfg) ((cfg) << 8) +#define REG_CON_STA_CFG(cfg) ((cfg) << 12) +#define REG_CON_STO_CFG(cfg) ((cfg) << 14) + +/* REG_MRXADDR bits */ +#define REG_MRXADDR_VALID(x) RT_BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ + +/* REG_IEN/REG_IPD bits */ +#define REG_INT_BTF RT_BIT(0) /* a byte was transmitted */ +#define REG_INT_BRF RT_BIT(1) /* a byte was received */ +#define REG_INT_MBTF RT_BIT(2) /* master data transmit finished */ +#define REG_INT_MBRF RT_BIT(3) /* master data receive finished */ +#define REG_INT_START RT_BIT(4) /* START condition generated */ +#define REG_INT_STOP RT_BIT(5) /* STOP condition generated */ +#define REG_INT_NAKRCV RT_BIT(6) /* NACK received */ +#define REG_INT_ALL 0x7f + +/* Constants */ +#define WAIT_TIMEOUT 1000 /* ms */ +#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ + +/* I2C specification values for various modes */ +struct i2c_spec_values +{ + rt_ubase_t min_hold_start_ns; /* min hold time (repeated) START condition */ + rt_ubase_t min_low_ns; /* min LOW period of the SCL clock */ + rt_ubase_t min_high_ns; /* min HIGH period of the SCL cloc */ + rt_ubase_t min_setup_start_ns; /* min set-up time for a repeated START conditio */ + rt_ubase_t max_data_hold_ns; /* max data hold time */ + rt_ubase_t min_data_setup_ns; /* min data set-up time */ + rt_ubase_t min_setup_stop_ns; /* min set-up time for STOP condition */ + rt_ubase_t min_hold_buffer_ns; /* min bus free time between a STOP and */ +}; + +static const struct i2c_spec_values standard_mode_spec = +{ + .min_hold_start_ns = 4000, + .min_low_ns = 4700, + .min_high_ns = 4000, + .min_setup_start_ns = 4700, + .max_data_hold_ns = 3450, + .min_data_setup_ns = 250, + .min_setup_stop_ns = 4000, + .min_hold_buffer_ns = 4700, +}; + +static const struct i2c_spec_values fast_mode_spec = +{ + .min_hold_start_ns = 600, + .min_low_ns = 1300, + .min_high_ns = 600, + .min_setup_start_ns = 600, + .max_data_hold_ns = 900, + .min_data_setup_ns = 100, + .min_setup_stop_ns = 600, + .min_hold_buffer_ns = 1300, +}; + +static const struct i2c_spec_values fast_mode_plus_spec = +{ + .min_hold_start_ns = 260, + .min_low_ns = 500, + .min_high_ns = 260, + .min_setup_start_ns = 260, + .max_data_hold_ns = 400, + .min_data_setup_ns = 50, + .min_setup_stop_ns = 260, + .min_hold_buffer_ns = 500, +}; + +/* + * Calculated V1 timings, setup/hold start time and setup stop time for v1's + * calc_timings, the tuning should all be 0 for old hardware anyone using v0's + * calc_timings. + */ +struct rk3x_i2c_calced_timings +{ + rt_ubase_t div_low; /* Divider output for low */ + rt_ubase_t div_high; /* Divider output for high */ + rt_uint32_t tuning; /* Used to adjust setup/hold data time */ +}; + +enum rk3x_i2c_state +{ + STATE_IDLE, + STATE_START, + STATE_READ, + STATE_WRITE, + STATE_STOP +}; + +struct rk3x_i2c_soc_data +{ + int grf_offset; + rt_err_t (*calc_timings)(rt_ubase_t, struct i2c_timings *, + struct rk3x_i2c_calced_timings *); +}; + +struct rk3x_i2c +{ + struct rt_i2c_bus_device parent; + + const struct rk3x_i2c_soc_data *soc_data; + + int irq; + void *regs; + + struct rt_clk *clk; + struct rt_clk *pclk; + struct rt_clk_notifier clk_notifier; + + struct i2c_timings timings; + + struct rt_spinlock lock; + struct rt_completion done; + + struct rt_i2c_msg *msg; + rt_uint8_t addr; + rt_uint32_t mode; + rt_bool_t is_last_msg; + + enum rk3x_i2c_state state; + rt_uint32_t processed; + rt_err_t error; +}; + +#define raw_to_rk3x_i2c(raw) rt_container_of(raw, struct rk3x_i2c, parent) + +rt_inline void i2c_writel(struct rk3x_i2c *i2c, rt_uint32_t value, int offset) +{ + HWREG32(i2c->regs + offset) = value; +} + +rt_inline rt_uint32_t i2c_readl(struct rk3x_i2c *i2c, int offset) +{ + return HWREG32(i2c->regs + offset); +} + +/* Reset all interrupt pending bits */ +rt_inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) +{ + i2c_writel(i2c, REG_INT_ALL, REG_IPD); +} + +/* Generate a START condition, which triggers a REG_INT_START interrupt */ +static void rk3x_i2c_start(struct rk3x_i2c *i2c) +{ + rt_uint32_t val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + + i2c_writel(i2c, REG_INT_START, REG_IEN); + + /* enable adapter with correct mode, send START condition */ + val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + + /* if we want to react to NACK, set ACTACK bit */ + if (!(i2c->msg->flags & RT_I2C_IGNORE_NACK)) + { + val |= REG_CON_ACTACK; + } + + i2c_writel(i2c, val, REG_CON); +} + +/* Generate a STOP condition, which triggers a REG_INT_STOP interrupt */ +static void rk3x_i2c_stop(struct rk3x_i2c *i2c, rt_err_t error) +{ + rt_uint32_t ctrl; + + i2c->processed = 0; + i2c->msg = RT_NULL; + i2c->error = error; + + if (i2c->is_last_msg) + { + /* Enable stop interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IEN); + + i2c->state = STATE_STOP; + + ctrl = i2c_readl(i2c, REG_CON); + ctrl |= REG_CON_STOP; + i2c_writel(i2c, ctrl, REG_CON); + } + else + { + /* Signal rk3x_i2c_xfer to start the next message. */ + i2c->state = STATE_IDLE; + + /* + * The HW is actually not capable of REPEATED START. But we can + * get the intended effect by resetting its internal state + * and issuing an ordinary START. + */ + ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + i2c_writel(i2c, ctrl, REG_CON); + + /* signal that we are finished with the current msg */ + rt_completion_done(&i2c->done); + } +} + +/* Setup a read according to i2c->msg */ +static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) +{ + rt_uint32_t con, len = i2c->msg->len - i2c->processed; + + con = i2c_readl(i2c, REG_CON); + + /* + * The hw can read up to 32 bytes at a time. If we need more than one + * chunk, send an ACK after the last byte of the current chunk. + */ + if (len > 32) + { + len = 32; + con &= ~REG_CON_LASTACK; + } + else + { + con |= REG_CON_LASTACK; + } + + /* make sure we are in plain RX mode if we read a second chunk */ + if (i2c->processed != 0) + { + con &= ~REG_CON_MOD_MASK; + con |= REG_CON_MOD(REG_CON_MOD_RX); + } + + i2c_writel(i2c, con, REG_CON); + i2c_writel(i2c, len, REG_MRXCNT); +} + +/* Fill the transmit buffer with data from i2c->msg */ +static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) +{ + rt_uint32_t cnt = 0; + + for (int i = 0; i < 8; ++i) + { + rt_uint32_t val = 0; + + for (int j = 0; j < 4; ++j) + { + rt_uint8_t byte; + + if ((i2c->processed == i2c->msg->len) && (cnt != 0)) + { + break; + } + + if (i2c->processed == 0 && cnt == 0) + { + byte = (i2c->addr & 0x7f) << 1; + } + else + { + byte = i2c->msg->buf[i2c->processed++]; + } + + val |= byte << (j * 8); + cnt++; + } + + i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i); + + if (i2c->processed == i2c->msg->len) + { + break; + } + } + + i2c_writel(i2c, cnt, REG_MTXCNT); +} + +/* IRQ handlers for individual states */ +static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, rt_uint32_t ipd) +{ + if (!(ipd & REG_INT_START)) + { + rk3x_i2c_stop(i2c, -RT_EIO); + LOG_W("Unexpected irq in START: 0x%x", ipd); + rk3x_i2c_clean_ipd(i2c); + + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_START, REG_IPD); + + /* disable start bit */ + i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON); + + /* enable appropriate interrupts and transition */ + if (i2c->mode == REG_CON_MOD_TX) + { + i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_WRITE; + rk3x_i2c_fill_transmit_buf(i2c); + } + else + { + /* in any other case, we are going to be reading. */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_READ; + rk3x_i2c_prepare_read(i2c); + } +} + +static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, rt_uint32_t ipd) +{ + if (!(ipd & REG_INT_MBTF)) + { + rk3x_i2c_stop(i2c, -RT_EIO); + LOG_E("Unexpected irq in WRITE: 0x%x", ipd); + rk3x_i2c_clean_ipd(i2c); + + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_MBTF, REG_IPD); + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + { + rk3x_i2c_stop(i2c, i2c->error); + } + else + { + rk3x_i2c_fill_transmit_buf(i2c); + } +} + +static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) +{ + rt_uint32_t val, len = i2c->msg->len - i2c->processed; + + /* we only care for MBRF here. */ + if (!(ipd & REG_INT_MBRF)) + { + return; + } + + /* ack interrupt (read also produces a spurious START flag, clear it too) */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD); + + /* Can only handle a maximum of 32 bytes at a time */ + if (len > 32) + { + len = 32; + } + + /* read the data from receive buffer */ + for (int i = 0; i < len; ++i) + { + rt_uint8_t byte; + + if (i % 4 == 0) + { + val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4); + } + + byte = (val >> ((i % 4) * 8)) & 0xff; + i2c->msg->buf[i2c->processed++] = byte; + } + + /* are we finished? */ + if (i2c->processed == i2c->msg->len) + { + rk3x_i2c_stop(i2c, i2c->error); + } + else + { + rk3x_i2c_prepare_read(i2c); + } +} + +static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, rt_uint32_t ipd) +{ + rt_uint32_t con; + + if (!(ipd & REG_INT_STOP)) + { + rk3x_i2c_stop(i2c, -RT_EIO); + LOG_E("Unexpected irq in STOP: 0x%x", ipd); + rk3x_i2c_clean_ipd(i2c); + + return; + } + + /* ack interrupt */ + i2c_writel(i2c, REG_INT_STOP, REG_IPD); + + /* disable STOP bit */ + con = i2c_readl(i2c, REG_CON); + con &= ~REG_CON_STOP; + i2c_writel(i2c, con, REG_CON); + + i2c->state = STATE_IDLE; + + /* signal rk3x_i2c_xfer that we are finished */ + rt_completion_done(&i2c->done); +} + +static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, rt_ubase_t clk_rate) +{ + rt_err_t err; + rt_ubase_t level; + rt_uint32_t val; + struct rk3x_i2c_calced_timings calc; + struct i2c_timings *timings = &i2c->timings; + + if ((err = i2c->soc_data->calc_timings(clk_rate, timings, &calc))) + { + LOG_W("Could not reach SCL freq %u", timings->bus_freq_hz); + } + + rt_clk_enable(i2c->pclk); + + level = rt_spin_lock_irqsave(&i2c->lock); + + val = i2c_readl(i2c, REG_CON); + val &= ~REG_CON_TUNING_MASK; + val |= calc.tuning; + i2c_writel(i2c, val, REG_CON); + i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), REG_CLKDIV); + + rt_spin_unlock_irqrestore(&i2c->lock, level); + + rt_clk_disable(i2c->pclk); +} + +static rt_err_t rk3x_i2c_clk_notifier(struct rt_clk_notifier *notifier, + rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate) +{ + struct rk3x_i2c_calced_timings calc; + struct rk3x_i2c *i2c = rt_container_of(notifier, struct rk3x_i2c, clk_notifier); + + switch (msg) + { + case RT_CLK_MSG_PRE_RATE_CHANGE: + /* + * Try the calculation (but don't store the result) ahead of + * time to see if we need to block the clock change. Timings + * shouldn't actually take effect until rk3x_i2c_adapt_div(). + */ + if (i2c->soc_data->calc_timings(new_rate, &i2c->timings, &calc) != 0) + { + return -RT_EIO; + } + + /* scale up */ + if (new_rate > old_rate) + { + rk3x_i2c_adapt_div(i2c, new_rate); + } + break; + + case RT_CLK_MSG_POST_RATE_CHANGE: + /* scale down */ + if (new_rate < old_rate) + { + rk3x_i2c_adapt_div(i2c, new_rate); + } + break; + + case RT_CLK_MSG_ABORT_RATE_CHANGE: + /* scale up */ + if (new_rate > old_rate) + { + rk3x_i2c_adapt_div(i2c, old_rate); + } + break; + + default: + break; + } + + return RT_EOK; +} + +static const struct i2c_spec_values *rk3x_i2c_get_spec(rt_uint32_t speed) +{ + if (speed <= I2C_MAX_STANDARD_MODE_FREQ) + { + return &standard_mode_spec; + } + else if (speed <= I2C_MAX_FAST_MODE_FREQ) + { + return &fast_mode_spec; + } + else + { + return &fast_mode_plus_spec; + } +} + +/** + * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + */ +static rt_err_t rk3x_i2c_v0_calc_timings(rt_ubase_t clk_rate, + struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc) +{ + rt_err_t err = RT_EOK; + rt_ubase_t min_low_ns, min_high_ns; + rt_ubase_t max_low_ns, min_total_ns; + rt_ubase_t clk_rate_khz, scl_rate_khz; + rt_ubase_t min_low_div, min_high_div; + rt_ubase_t max_low_div; + rt_ubase_t min_div_for_hold, min_total_div; + rt_ubase_t extra_div, extra_low_div, ideal_low_div; + rt_ubase_t data_hold_buffer_ns = 50; + const struct i2c_spec_values *spec; + + /* Only support standard-mode and fast-mode */ + if (t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) + { + t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; + } + + /* prevent scl_rate_khz from becoming 0 */ + if (t->bus_freq_hz < 1000) + { + t->bus_freq_hz = 1000; + } + + /* + * min_low_ns: The minimum number of ns we need to hold low to + * meet I2C specification, should include fall time. + * min_high_ns: The minimum number of ns we need to hold high to + * meet I2C specification, should include rise time. + * max_low_ns: The maximum number of ns we can hold low to meet + * I2C specification. + * + * Note: max_low_ns should be (maximum data hold time * 2 - buffer) + * This is because the i2c host on Rockchip holds the data line + * for half the low time. + */ + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + min_high_ns = t->scl_rise_ns + spec->min_high_ns; + + /* + * Timings for repeated start: + * - controller appears to drop SDA at .875x (7/8) programmed clk high. + * - controller appears to keep SCL high for 2x programmed clk high. + * + * We need to account for those rules in picking our "high" time so + * we meet tSU;STA and tHD;STA times. + */ + min_high_ns = rt_max(min_high_ns, RT_DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875)); + min_high_ns = rt_max(min_high_ns, RT_DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns + + spec->min_high_ns), 2)); + + min_low_ns = t->scl_fall_ns + spec->min_low_ns; + max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns; + min_total_ns = min_low_ns + min_high_ns; + + /* Adjust to avoid overflow */ + clk_rate_khz = RT_DIV_ROUND_UP(clk_rate, 1000); + scl_rate_khz = t->bus_freq_hz / 1000; + + /* + * We need the total div to be >= this number + * so we don't clock too fast. + */ + min_total_div = RT_DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); + + /* These are the min dividers needed for min hold times. */ + min_low_div = RT_DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); + min_high_div = RT_DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); + min_div_for_hold = (min_low_div + min_high_div); + + /* + * This is the maximum divider so we don't go over the maximum. + * We don't round up here (we round down) since this is a maximum. + */ + max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000); + + if (min_low_div > max_low_div) + { + max_low_div = min_low_div; + } + + if (min_div_for_hold > min_total_div) + { + /* Time needed to meet hold requirements is important. Just use that. */ + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; + } + else + { + /* + * We've got to distribute some time among the low and high + * so we don't run too fast. + */ + extra_div = min_total_div - min_div_for_hold; + + /* + * We'll try to split things up perfectly evenly, + * biasing slightly towards having a higher div + * for low (spend more time low). + */ + ideal_low_div = RT_DIV_ROUND_UP(clk_rate_khz * min_low_ns, + scl_rate_khz * 8 * min_total_ns); + + /* Don't allow it to go over the maximum */ + if (ideal_low_div > max_low_div) + { + ideal_low_div = max_low_div; + } + + /* Handle when the ideal low div is going to take up more than we have. */ + if (ideal_low_div > min_low_div + extra_div) + { + ideal_low_div = min_low_div + extra_div; + } + + /* Give low the "ideal" and give high whatever extra is left */ + extra_low_div = ideal_low_div - min_low_div; + t_calc->div_low = ideal_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); + } + + /* + * Adjust to the fact that the hardware has an implicit "+1". + * NOTE: Above calculations always produce div_low > 0 and div_high > 0. + */ + --t_calc->div_low; + --t_calc->div_high; + + /* Give the tuning value 0, that would not update con register */ + t_calc->tuning = 0; + + /* Maximum divider supported by hw is 0xffff */ + if (t_calc->div_low > 0xffff) + { + t_calc->div_low = 0xffff; + err = -RT_EINVAL; + } + + if (t_calc->div_high > 0xffff) + { + t_calc->div_high = 0xffff; + err = -RT_EINVAL; + } + + return err; +} + +/** + * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + * The following formulas are v1's method to calculate timings. + * + * l = divl + 1; + * h = divh + 1; + * s = sda_update_config + 1; + * u = start_setup_config + 1; + * p = stop_setup_config + 1; + * T = Tclk_i2c; + * + * tHigh = 8 * h * T; + * tLow = 8 * l * T; + * + * tHD;sda = (l * s + 1) * T; + * tSU;sda = [(8 - s) * l + 1] * T; + * tI2C = 8 * (l + h) * T; + * + * tSU;sta = (8h * u + 1) * T; + * tHD;sta = [8h * (u + 1) - 1] * T; + * tSU;sto = (8h * p + 1) * T; + */ +static rt_err_t rk3x_i2c_v1_calc_timings(rt_ubase_t clk_rate, + struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc) +{ + rt_err_t err = 0; + rt_ubase_t min_low_ns, min_high_ns; + rt_ubase_t min_setup_start_ns, min_setup_data_ns; + rt_ubase_t min_setup_stop_ns, max_hold_data_ns; + rt_ubase_t clk_rate_khz, scl_rate_khz; + rt_ubase_t min_low_div, min_high_div; + rt_ubase_t min_div_for_hold, min_total_div; + rt_ubase_t extra_div, extra_low_div; + rt_ubase_t sda_update_cfg, stp_sta_cfg, stp_sto_cfg; + const struct i2c_spec_values *spec; + + /* Support standard-mode, fast-mode and fast-mode plus */ + if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) + { + t->bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ; + } + + /* prevent scl_rate_khz from becoming 0 */ + if (t->bus_freq_hz < 1000) + { + t->bus_freq_hz = 1000; + } + + /* + * min_low_ns: The minimum number of ns we need to hold low to + * meet I2C specification, should include fall time. + * min_high_ns: The minimum number of ns we need to hold high to + * meet I2C specification, should include rise time. + */ + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + + /* calculate min-divh and min-divl */ + clk_rate_khz = RT_DIV_ROUND_UP(clk_rate, 1000); + scl_rate_khz = t->bus_freq_hz / 1000; + min_total_div = RT_DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); + + min_high_ns = t->scl_rise_ns + spec->min_high_ns; + min_high_div = RT_DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); + + min_low_ns = t->scl_fall_ns + spec->min_low_ns; + min_low_div = RT_DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); + + /* + * Final divh and divl must be greater than 0, otherwise the + * hardware would not output the i2c clk. + */ + min_high_div = (min_high_div < 1) ? 2 : min_high_div; + min_low_div = (min_low_div < 1) ? 2 : min_low_div; + + /* These are the min dividers needed for min hold times. */ + min_div_for_hold = (min_low_div + min_high_div); + + /* + * This is the maximum divider so we don't go over the maximum. + * We don't round up here (we round down) since this is a maximum. + */ + if (min_div_for_hold >= min_total_div) + { + /* + * Time needed to meet hold requirements is important. + * Just use that. + */ + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; + } + else + { + /* + * We've got to distribute some time among the low and high + * so we don't run too fast. + * We'll try to split things up by the scale of min_low_div and + * min_high_div, biasing slightly towards having a higher div + * for low (spend more time low). + */ + extra_div = min_total_div - min_div_for_hold; + extra_low_div = RT_DIV_ROUND_UP(min_low_div * extra_div, min_div_for_hold); + + t_calc->div_low = min_low_div + extra_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); + } + + /* + * calculate sda data hold count by the rules, data_upd_st:3 + * is a appropriate value to reduce calculated times. + */ + for (sda_update_cfg = 3; sda_update_cfg > 0; --sda_update_cfg) + { + max_hold_data_ns = RT_DIV_ROUND_UP((sda_update_cfg + * (t_calc->div_low) + 1) * 1000000, clk_rate_khz); + min_setup_data_ns = RT_DIV_ROUND_UP(((8 - sda_update_cfg) + * (t_calc->div_low) + 1) * 1000000, clk_rate_khz); + + if (max_hold_data_ns < spec->max_data_hold_ns && + min_setup_data_ns > spec->min_data_setup_ns) + { + break; + } + } + + /* calculate setup start config */ + min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns; + stp_sta_cfg = RT_DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns - 1000000, + 8 * 1000000 * (t_calc->div_high)); + + /* calculate setup stop config */ + min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns; + stp_sto_cfg = RT_DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns - 1000000, + 8 * 1000000 * (t_calc->div_high)); + + t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) | + REG_CON_STA_CFG(--stp_sta_cfg) | REG_CON_STO_CFG(--stp_sto_cfg); + + --t_calc->div_low; + --t_calc->div_high; + + /* Maximum divider supported by hw is 0xffff */ + if (t_calc->div_low > 0xffff) + { + t_calc->div_low = 0xffff; + err = -RT_EINVAL; + } + + if (t_calc->div_high > 0xffff) + { + t_calc->div_high = 0xffff; + err = -RT_EINVAL; + } + + return err; +} + +/* Setup I2C registers for an I2C operation specified by msgs, num */ +static rt_ssize_t rk3x_i2c_setup(struct rk3x_i2c *i2c, struct rt_i2c_msg *msgs, + int num) +{ + rt_ssize_t res = 0; + rt_uint32_t addr = (msgs[0].addr & 0x7f) << 1; + + /* + * The I2C adapter can issue a small (len < 4) write packet before + * reading. This speeds up SMBus-style register reads. + * The MRXADDR/MRXRADDR hold the slave address and the slave register + * address in this case. + */ + + if (num >= 2 && msgs[0].len < 4 && + !(msgs[0].flags & RT_I2C_RD) && (msgs[1].flags & RT_I2C_RD)) + { + rt_uint32_t reg_addr = 0; + + LOG_D("Combined write/read from addr 0x%x", addr >> 1); + + /* Fill MRXRADDR with the register address(es) */ + for (int i = 0; i < msgs[0].len; ++i) + { + reg_addr |= msgs[0].buf[i] << (i * 8); + reg_addr |= REG_MRXADDR_VALID(i); + } + + /* msgs[0] is handled by hw. */ + i2c->msg = &msgs[1]; + i2c->mode = REG_CON_MOD_REGISTER_TX; + + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); + i2c_writel(i2c, reg_addr, REG_MRXRADDR); + + res = 2; + } + else + { + /* We'll have to do it the boring way and process the msgs one-by-one. */ + if (msgs[0].flags & RT_I2C_RD) + { + /* set read bit */ + addr |= 1; + + /* + * We have to transmit the slave addr first. Use + * MOD_REGISTER_TX for that purpose. + */ + i2c->mode = REG_CON_MOD_REGISTER_TX; + i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); + i2c_writel(i2c, 0, REG_MRXRADDR); + } + else + { + i2c->mode = REG_CON_MOD_TX; + } + + i2c->msg = &msgs[0]; + + res = 1; + } + + i2c->addr = msgs[0].addr; + i2c->state = STATE_START; + i2c->processed = 0; + i2c->error = RT_EOK; + + rk3x_i2c_clean_ipd(i2c); + + return res; +} + +static rt_ssize_t rk3x_i2c_master_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], rt_uint32_t num) +{ + rt_ssize_t res = 0; + rt_uint32_t val; + rt_ubase_t level; + rt_err_t timeout_err; + struct rk3x_i2c *i2c = raw_to_rk3x_i2c(bus); + + level = rt_spin_lock_irqsave(&i2c->lock); + + rt_clk_enable(i2c->clk); + rt_clk_enable(i2c->pclk); + + i2c->is_last_msg = RT_FALSE; + + /* Process msgs */ + for (int i = 0; i < num; i += res) + { + res = rk3x_i2c_setup(i2c, msgs + i, num - i); + + if (res < 0) + { + LOG_E("%s setup failed", rt_dm_dev_get_name(&i2c->parent.parent)); + + break; + } + + if (i + res >= num) + { + i2c->is_last_msg = RT_TRUE; + } + + rt_spin_unlock_irqrestore(&i2c->lock, level); + + rk3x_i2c_start(i2c); + + timeout_err = rt_completion_wait(&i2c->done, rt_tick_from_millisecond(WAIT_TIMEOUT)); + + level = rt_spin_lock_irqsave(&i2c->lock); + + if (timeout_err) + { + LOG_E("timeout, ipd: 0x%02x, state: %d", i2c_readl(i2c, REG_IPD), i2c->state); + + /* Force a STOP condition without interrupt */ + i2c_writel(i2c, 0, REG_IEN); + val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + val |= REG_CON_EN | REG_CON_STOP; + i2c_writel(i2c, val, REG_CON); + + i2c->state = STATE_IDLE; + + res = timeout_err; + break; + } + + if (i2c->error) + { + res = i2c->error; + + break; + } + } + + rt_clk_disable(i2c->pclk); + rt_clk_disable(i2c->clk); + + rt_spin_unlock_irqrestore(&i2c->lock, level); + + return res < 0 ? res : num; +} + +static struct rt_i2c_bus_device_ops rk3x_i2c_ops = +{ + .master_xfer = rk3x_i2c_master_xfer, +}; + +static void rk3x_i2c_irq(int irqno, void *param) +{ + rt_uint32_t ipd; + struct rk3x_i2c *i2c = param; + + rt_spin_lock(&i2c->lock); + + ipd = i2c_readl(i2c, REG_IPD); + + if (i2c->state == STATE_IDLE) + { + LOG_W("IRQ in STATE_IDLE, ipd = 0x%x", ipd); + rk3x_i2c_clean_ipd(i2c); + + goto _out; + } + + LOG_D("IRQ: state %d, ipd: %x", i2c->state, ipd); + + /* Clean interrupt bits we don't care about */ + ipd &= ~(REG_INT_BRF | REG_INT_BTF); + + if (ipd & REG_INT_NAKRCV) + { + /* + * We got a NACK in the last operation. Depending on whether + * IGNORE_NAK is set, we have to stop the operation and report + * an error. + */ + i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD); + + ipd &= ~REG_INT_NAKRCV; + + if (!(i2c->msg->flags & RT_I2C_IGNORE_NACK)) + { + LOG_E("Flags error"); + + rk3x_i2c_stop(i2c, -RT_EIO); + } + } + + /* is there anything left to handle? */ + if ((ipd & REG_INT_ALL) == 0) + { + goto _out; + } + + switch (i2c->state) + { + case STATE_START: + rk3x_i2c_handle_start(i2c, ipd); + break; + + case STATE_WRITE: + rk3x_i2c_handle_write(i2c, ipd); + break; + + case STATE_READ: + rk3x_i2c_handle_read(i2c, ipd); + break; + + case STATE_STOP: + rk3x_i2c_handle_stop(i2c, ipd); + break; + + case STATE_IDLE: + break; + } + +_out: + rt_spin_unlock(&i2c->lock); +} + +static rt_err_t rk3x_i2c_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct rk3x_i2c *i2c = rt_calloc(1, sizeof(*i2c)); + + if (!i2c) + { + return -RT_ENOMEM; + } + + i2c->soc_data = pdev->id->data; + i2c_timings_ofw_parse(dev->ofw_node, &i2c->timings, RT_TRUE); + + i2c->regs = rt_dm_dev_iomap(dev, 0); + + if (!i2c->regs) + { + err = -RT_EIO; + + goto _fail; + } + + i2c->irq = rt_dm_dev_get_irq(dev, 0); + + if (i2c->irq < 0) + { + err = i2c->irq; + + goto _fail; + } + + if (i2c->soc_data->grf_offset >= 0) + { + rt_uint32_t value; + struct rt_syscon *grf; + struct rt_ofw_node *np = dev->ofw_node; + int id = rt_ofw_get_alias_id(np, "i2c"); + + if (id < 0) + { + LOG_E("alias id not found"); + + goto _fail; + } + + grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + + if (!grf) + { + err = -RT_EIO; + LOG_E("I2C%d %s not found", id, "rockchip,grf"); + + goto _fail; + } + + /* 27+i: write mask, 11+i: value */ + value = RT_BIT(27 + id) | RT_BIT(11 + id); + + if ((err = rt_syscon_write(grf, i2c->soc_data->grf_offset, value))) + { + LOG_E("Could not write to GRF: %s", rt_strerror(err)); + + goto _fail; + } + } + + if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) + { + i2c->clk = rt_clk_get_by_index(dev, 0); + i2c->pclk = i2c->clk; + } + else + { + i2c->clk = rt_clk_get_by_name(dev, "i2c"); + i2c->pclk = rt_clk_get_by_name(dev, "pclk"); + } + + if (!i2c->clk || rt_clk_prepare(i2c->clk)) + { + err = -RT_EIO; + + goto _fail; + } + + if (!i2c->pclk || rt_clk_prepare(i2c->pclk)) + { + err = -RT_EIO; + + goto _fail; + } + + i2c->clk_notifier.callback = rk3x_i2c_clk_notifier; + if ((err = rt_clk_notifier_register(i2c->clk, &i2c->clk_notifier))) + { + goto _fail; + } + + if ((err = rt_clk_enable(i2c->clk))) + { + LOG_E("Can't enable bus clk: %s", rt_strerror(err)); + + goto _fail; + } + + rk3x_i2c_adapt_div(i2c, rt_clk_get_rate(i2c->clk)); + rt_clk_disable(i2c->clk); + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + rt_spin_lock_init(&i2c->lock); + 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, rk3x_i2c_irq, i2c, dev_name); + rt_hw_interrupt_umask(i2c->irq); + + i2c->parent.ops = &rk3x_i2c_ops; + i2c->parent.parent.ofw_node = dev->ofw_node; + + rt_i2c_bus_device_register(&i2c->parent, dev_name); + + return RT_EOK; + +_fail: + if (i2c->regs) + { + rt_iounmap(i2c->regs); + } + if (i2c->clk) + { + rt_clk_unprepare(i2c->clk); + rt_clk_put(i2c->clk); + } + if (i2c->pclk && i2c->pclk != i2c->clk) + { + rt_clk_unprepare(i2c->pclk); + rt_clk_put(i2c->pclk); + } + if (i2c->clk_notifier.callback) + { + rt_clk_notifier_unregister(i2c->clk, &i2c->clk_notifier); + } + rt_free(i2c); + + return err; +} + +static const struct rk3x_i2c_soc_data rv1108_soc_data = +{ + .grf_offset = -1, + .calc_timings = rk3x_i2c_v1_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rv1126_soc_data = +{ + .grf_offset = 0x118, + .calc_timings = rk3x_i2c_v1_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3066_soc_data = +{ + .grf_offset = 0x154, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3188_soc_data = +{ + .grf_offset = 0x0a4, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3228_soc_data = +{ + .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3288_soc_data = +{ + .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3399_soc_data = +{ + .grf_offset = -1, + .calc_timings = rk3x_i2c_v1_calc_timings, +}; + +static const struct rt_ofw_node_id rk3x_i2c_ofw_ids[] = +{ + { .compatible = "rockchip,rv1108-i2c", .data = &rv1108_soc_data }, + { .compatible = "rockchip,rv1126-i2c", .data = &rv1126_soc_data }, + { .compatible = "rockchip,rk3066-i2c", .data = &rk3066_soc_data }, + { .compatible = "rockchip,rk3188-i2c", .data = &rk3188_soc_data }, + { .compatible = "rockchip,rk3228-i2c", .data = &rk3228_soc_data }, + { .compatible = "rockchip,rk3288-i2c", .data = &rk3288_soc_data }, + { .compatible = "rockchip,rk3399-i2c", .data = &rk3399_soc_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk3x_i2c_driver = +{ + .name = "rk3x-i2c", + .ids = rk3x_i2c_ofw_ids, + + .probe = rk3x_i2c_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rk3x_i2c_driver); diff --git a/components/drivers/i2c/i2c_bus.c b/components/drivers/i2c/i2c_bus.c new file mode 100644 index 000000000000..135acd410415 --- /dev/null +++ b/components/drivers/i2c/i2c_bus.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-12-06 GuEe-GUI first version + */ + +#include "i2c_dm.h" + +#define DBG_TAG "i2c.bus" +#define DBG_LVL DBG_INFO +#include + +static struct rt_bus i2c_bus; + +void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus) +{ +#ifdef RT_USING_OFW + if (bus->parent.ofw_node) + { + struct rt_ofw_node *np = bus->parent.ofw_node, *i2c_client_np; + + rt_ofw_foreach_available_child_node(np, i2c_client_np) + { + rt_uint32_t client_addr; + struct rt_i2c_client *client; + + if (!rt_ofw_prop_read_bool(i2c_client_np, "compatible")) + { + continue; + } + + client = rt_calloc(1, sizeof(*client)); + + if (!client) + { + LOG_E("Not memory to create i2c client: %s", + rt_ofw_node_full_name(i2c_client_np)); + + return; + } + + rt_ofw_prop_read_u32(i2c_client_np, "reg", &client_addr); + + client->parent.ofw_node = i2c_client_np; + client->name = rt_ofw_node_name(i2c_client_np); + client->bus = bus; + client->client_addr = client_addr; + + rt_i2c_device_register(client); + } + } +#endif /* RT_USING_OFW */ +} + +rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver) +{ + RT_ASSERT(driver != RT_NULL); + + driver->parent.bus = &i2c_bus; + + return rt_driver_register(&driver->parent); +} + +rt_err_t rt_i2c_device_register(struct rt_i2c_client *client) +{ + RT_ASSERT(client != RT_NULL); + + return rt_bus_add_device(&i2c_bus, &client->parent); +} + +static rt_bool_t i2c_match(rt_driver_t drv, rt_device_t dev) +{ + const struct rt_i2c_device_id *id; + struct rt_i2c_driver *driver = rt_container_of(drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if ((id = driver->ids)) + { + for (; id->name[0]; ++id) + { + if (!rt_strcmp(id->name, client->name)) + { + client->id = id; + client->ofw_id = RT_NULL; + + return RT_TRUE; + } + } + } + +#ifdef RT_USING_OFW + client->ofw_id = rt_ofw_node_match(client->parent.ofw_node, driver->ofw_ids); + + if (client->ofw_id) + { + client->id = RT_NULL; + + return RT_TRUE; + } +#endif + + return RT_FALSE; +} + +static rt_err_t i2c_probe(rt_device_t dev) +{ + rt_err_t err; + struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if (!client->bus) + { + return -RT_EINVAL; + } + + err = driver->probe(client); + + return err; +} + +static struct rt_bus i2c_bus = +{ + .name = "i2c", + .match = i2c_match, + .probe = i2c_probe, +}; + +static int i2c_bus_init(void) +{ + rt_bus_register(&i2c_bus); + + return 0; +} +INIT_CORE_EXPORT(i2c_bus_init); diff --git a/components/drivers/i2c/i2c_core.c b/components/drivers/i2c/i2c_core.c index 17671ea24182..324731f679f1 100644 --- a/components/drivers/i2c/i2c_core.c +++ b/components/drivers/i2c/i2c_core.c @@ -19,6 +19,10 @@ #endif #include +#ifdef RT_USING_DM +#include "i2c_dm.h" +#endif + rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, const char *bus_name) { @@ -32,6 +36,13 @@ rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, LOG_I("I2C bus [%s] registered", bus_name); +#ifdef RT_USING_DM + if (!res) + { + i2c_bus_scan_clients(bus); + } +#endif + return res; } diff --git a/components/drivers/i2c/i2c_dm.c b/components/drivers/i2c/i2c_dm.c new file mode 100644 index 000000000000..31e8e0e74161 --- /dev/null +++ b/components/drivers/i2c/i2c_dm.c @@ -0,0 +1,50 @@ +/* + * 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 "i2c_dm.h" + +#define DBG_TAG "i2c.dm" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_OFW +static void i2c_parse_timing(struct rt_ofw_node *dev_np, const char *propname, + rt_uint32_t *out_value, rt_uint32_t def_value, rt_bool_t use_defaults) +{ + if (rt_ofw_prop_read_u32(dev_np, propname, out_value) && use_defaults) + { + *out_value = def_value; + } +} + +rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults) +{ + rt_ubase_t def; + rt_bool_t udef = use_defaults; + struct i2c_timings *t = timings; + + i2c_parse_timing(dev_np, "clock-frequency", &t->bus_freq_hz, I2C_MAX_STANDARD_MODE_FREQ, udef); + + def = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 : t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev_np, "i2c-scl-rising-time-ns", &t->scl_rise_ns, def, udef); + + def = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev_np, "i2c-scl-falling-time-ns", &t->scl_fall_ns, def, udef); + + i2c_parse_timing(dev_np, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-sda-falling-time-ns", &t->sda_fall_ns, t->scl_fall_ns, udef); + i2c_parse_timing(dev_np, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-digital-filter-width-ns", &t->digital_filter_width_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-analog-filter-cutoff-frequency", &t->analog_filter_cutoff_freq_hz, 0, udef); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/i2c/i2c_dm.h b/components/drivers/i2c/i2c_dm.h new file mode 100644 index 000000000000..8b3ca59d3dc3 --- /dev/null +++ b/components/drivers/i2c/i2c_dm.h @@ -0,0 +1,51 @@ +/* + * 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 __I2C_DM_H__ +#define __I2C_DM_H__ + +#include +#include +#include + +/* I2C Frequency Modes */ +#define I2C_MAX_STANDARD_MODE_FREQ 100000 +#define I2C_MAX_FAST_MODE_FREQ 400000 +#define I2C_MAX_FAST_MODE_PLUS_FREQ 1000000 +#define I2C_MAX_TURBO_MODE_FREQ 1400000 +#define I2C_MAX_HIGH_SPEED_MODE_FREQ 3400000 +#define I2C_MAX_ULTRA_FAST_MODE_FREQ 5000000 + +struct i2c_timings +{ + rt_uint32_t bus_freq_hz; /* the bus frequency in Hz */ + rt_uint32_t scl_rise_ns; /* time SCL signal takes to rise in ns; t(r) in the I2C specification */ + rt_uint32_t scl_fall_ns; /* time SCL signal takes to fall in ns; t(f) in the I2C specification */ + rt_uint32_t scl_int_delay_ns; /* time IP core additionally needs to setup SCL in ns */ + rt_uint32_t sda_fall_ns; /* time SDA signal takes to fall in ns; t(f) in the I2C specification */ + rt_uint32_t sda_hold_ns; /* time IP core additionally needs to hold SDA in ns */ + rt_uint32_t digital_filter_width_ns; /* width in ns of spikes on i2c lines that the IP core digital filter can filter out */ + rt_uint32_t analog_filter_cutoff_freq_hz; /* threshold frequency for the low pass IP core analog filter */ +}; + +#ifdef RT_USING_OFW +rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults); +#else +rt_inline rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus); + +#endif /* __I2C_DM_H__ */ diff --git a/components/drivers/include/drivers/clk.h b/components/drivers/include/drivers/clk.h index 524fd6ebf694..b4bd74d3f56f 100644 --- a/components/drivers/include/drivers/clk.h +++ b/components/drivers/include/drivers/clk.h @@ -17,8 +17,9 @@ #include struct rt_clk_ops; +struct rt_reset_control_node; -struct rt_clk +struct rt_clk_node { rt_list_t list; rt_list_t children_nodes; @@ -26,26 +27,52 @@ struct rt_clk const char *name; const struct rt_clk_ops *ops; - struct rt_clk *parent; + struct rt_clk_node *parent; struct ref ref; rt_ubase_t rate; rt_ubase_t min_rate; rt_ubase_t max_rate; - void *sysdata; + rt_size_t notifier_count; + + void *priv; + + struct rt_clk *clk; }; struct rt_clk_fixed_rate { - struct rt_clk clk; + struct rt_clk_node clk; rt_ubase_t fixed_rate; rt_ubase_t fixed_accuracy; }; +struct rt_clk +{ + struct rt_clk_node *clk_np; + + const char *dev_id; + const char *con_id; + + rt_ubase_t rate; + + void *fw_node; + void *priv; +}; + +struct rt_clk_array +{ + rt_size_t count; + struct rt_clk *clks[]; +}; + struct rt_clk_ops { + rt_err_t (*init)(struct rt_clk *, void *fw_data); + rt_err_t (*finit)(struct rt_clk *); + /* API */ rt_err_t (*prepare)(struct rt_clk *); void (*unprepare)(struct rt_clk *); rt_bool_t (*is_prepared)(struct rt_clk *); @@ -53,13 +80,37 @@ struct rt_clk_ops void (*disable)(struct rt_clk *); rt_bool_t (*is_enabled)(struct rt_clk *); rt_err_t (*set_rate)(struct rt_clk *, rt_ubase_t rate, rt_ubase_t parent_rate); + rt_err_t (*set_parent)(struct rt_clk *, struct rt_clk *parent); + rt_err_t (*set_phase)(struct rt_clk *, int degrees); + rt_base_t (*get_phase)(struct rt_clk *); + rt_base_t (*round_rate)(struct rt_clk *, rt_ubase_t drate, rt_ubase_t *prate); }; -rt_err_t rt_clk_register(struct rt_clk *clk, struct rt_clk *parent); -rt_err_t rt_clk_unregister(struct rt_clk *clk); +struct rt_clk_notifier; -void rt_clk_put(struct rt_clk *clk); -struct rt_clk *rt_clk_get_parent(struct rt_clk *clk); +#define RT_CLK_MSG_PRE_RATE_CHANGE RT_BIT(0) +#define RT_CLK_MSG_POST_RATE_CHANGE RT_BIT(1) +#define RT_CLK_MSG_ABORT_RATE_CHANGE RT_BIT(2) + +typedef rt_err_t (*rt_clk_notifier_callback)(struct rt_clk_notifier *notifier, + rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate); + +struct rt_clk_notifier +{ + rt_list_t list; + + struct rt_clk *clk; + rt_clk_notifier_callback callback; + void *priv; +}; + +rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np); +rt_err_t rt_clk_unregister(struct rt_clk_node *clk_np); + +rt_err_t rt_clk_notifier_register(struct rt_clk *clk, struct rt_clk_notifier *notifier); +rt_err_t rt_clk_notifier_unregister(struct rt_clk *clk, struct rt_clk_notifier *notifier); + +rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent); rt_err_t rt_clk_prepare(struct rt_clk *clk); rt_err_t rt_clk_unprepare(struct rt_clk *clk); @@ -70,13 +121,36 @@ void rt_clk_disable(struct rt_clk *clk); rt_err_t rt_clk_prepare_enable(struct rt_clk *clk); void rt_clk_disable_unprepare(struct rt_clk *clk); +rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr); +rt_err_t rt_clk_array_unprepare(struct rt_clk_array *clk_arr); + +rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr); +void rt_clk_array_disable(struct rt_clk_array *clk_arr); + +rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr); +void rt_clk_array_disable_unprepare(struct rt_clk_array *clk_arr); + rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max); rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate); rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate); rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate); rt_ubase_t rt_clk_get_rate(struct rt_clk *clk); +rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees); +rt_base_t rt_clk_get_phase(struct rt_clk *clk); + +rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate); + +struct rt_clk *rt_clk_get_parent(struct rt_clk *clk); + +struct rt_clk_array *rt_clk_get_array(struct rt_device *dev); +struct rt_clk *rt_clk_get_by_index(struct rt_device *dev, int index); +struct rt_clk *rt_clk_get_by_name(struct rt_device *dev, const char *name); +void rt_clk_array_put(struct rt_clk_array *clk_arr); +void rt_clk_put(struct rt_clk *clk); + #ifdef RT_USING_OFW +struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np); struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index); struct rt_clk *rt_ofw_get_clk_by_name(struct rt_ofw_node *np, const char *name); #else diff --git a/components/drivers/include/drivers/core/bus.h b/components/drivers/include/drivers/core/bus.h index dd12cf6dbad5..42d26163a7b0 100644 --- a/components/drivers/include/drivers/core/bus.h +++ b/components/drivers/include/drivers/core/bus.h @@ -12,6 +12,7 @@ #define __BUS_H__ #include +#include #include #include @@ -29,6 +30,7 @@ struct rt_bus rt_list_t dev_list; rt_list_t drv_list; + rt_atomic_t exclusive; struct rt_spinlock spinlock; rt_bool_t (*match)(rt_driver_t drv, rt_device_t dev); @@ -37,6 +39,10 @@ struct rt_bus rt_bus_t rt_bus_root(void); +void rt_bus_lock(rt_bus_t bus); +rt_bool_t rt_bus_trylock(rt_bus_t bus); +void rt_bus_unlock(rt_bus_t bus); + rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev)); rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev)); diff --git a/components/drivers/include/drivers/core/rtdm.h b/components/drivers/include/drivers/core/rtdm.h index 95d3c259b8f1..56f30193d89e 100755 --- a/components/drivers/include/drivers/core/rtdm.h +++ b/components/drivers/include/drivers/core/rtdm.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -26,11 +27,140 @@ extern int rt_hw_cpu_id(void); void rt_dm_secondary_cpu_init(void); -int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix); -int rt_dm_get_dev_name_id(rt_device_t dev); +int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix); +int rt_dm_dev_get_name_id(rt_device_t dev); -int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...); -const char *rt_dm_get_dev_name(rt_device_t dev); +int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...); +const char *rt_dm_dev_get_name(rt_device_t dev); + +int rt_dm_dev_get_address_count(rt_device_t dev); +rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index, + rt_uint64_t *out_address, rt_uint64_t *out_size); +rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name, + rt_uint64_t *out_address, rt_uint64_t *out_size); +int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs); + +void *rt_dm_dev_iomap(rt_device_t dev, int index); +void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name); + +int rt_dm_dev_get_irq_count(rt_device_t dev); +int rt_dm_dev_get_irq(rt_device_t dev, int index); +int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name); + +void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data); +void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np); + +int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint8_t *out_values); +int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint16_t *out_values); +int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint32_t *out_values); +int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname, + int index, int nr, rt_uint64_t *out_values); +int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname, + int index, int nr, const char **out_strings); + +int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size); +int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string); + +rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname); + +rt_inline rt_err_t rt_dm_dev_prop_read_u8_index(rt_device_t dev, const char *propname, + int index, rt_uint8_t *out_value) +{ + int nr = rt_dm_dev_prop_read_u8_array_index(dev, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u16_index(rt_device_t dev, const char *propname, + int index, rt_uint16_t *out_value) +{ + int nr = rt_dm_dev_prop_read_u16_array_index(dev, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u32_index(rt_device_t dev, const char *propname, + int index, rt_uint32_t *out_value) +{ + int nr = rt_dm_dev_prop_read_u32_array_index(dev, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u64_index(rt_device_t dev, const char *propname, + int index, rt_uint64_t *out_value) +{ + int nr = rt_dm_dev_prop_read_u64_array_index(dev, propname, index, 1, out_value); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_dm_dev_prop_read_string_index(rt_device_t dev, const char *propname, + int index, const char **out_string) +{ + int nr = rt_dm_dev_prop_read_string_array_index(dev, propname, index, 1, out_string); + + return nr > 0 ? RT_EOK : (rt_err_t)nr; +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u8(rt_device_t dev, const char *propname, + rt_uint8_t *out_value) +{ + return rt_dm_dev_prop_read_u8_index(dev, propname, 0, out_value); +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u16(rt_device_t dev, const char *propname, + rt_uint16_t *out_value) +{ + return rt_dm_dev_prop_read_u16_index(dev, propname, 0, out_value); +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u32(rt_device_t dev, const char *propname, + rt_uint32_t *out_value) +{ + return rt_dm_dev_prop_read_u32_index(dev, propname, 0, out_value); +} + +rt_inline rt_err_t rt_dm_dev_prop_read_s32(rt_device_t dev, const char *propname, + rt_int32_t *out_value) +{ + return rt_dm_dev_prop_read_u32_index(dev, propname, 0, (rt_uint32_t *)out_value); +} + +rt_inline rt_err_t rt_dm_dev_prop_read_u64(rt_device_t dev, const char *propname, + rt_uint64_t *out_value) +{ + return rt_dm_dev_prop_read_u64_index(dev, propname, 0, out_value); +} + +rt_inline rt_err_t rt_dm_dev_prop_read_string(rt_device_t dev, const char *propname, + const char **out_string) +{ + return rt_dm_dev_prop_read_string_index(dev, propname, 0, out_string); +} + +rt_inline int rt_dm_dev_prop_count_of_u8(rt_device_t dev, const char *propname) +{ + return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint8_t)); +} + +rt_inline int rt_dm_dev_prop_count_of_u16(rt_device_t dev, const char *propname) +{ + return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint16_t)); +} + +rt_inline int rt_dm_dev_prop_count_of_u32(rt_device_t dev, const char *propname) +{ + return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint32_t)); +} + +rt_inline int rt_dm_dev_prop_count_of_u64(rt_device_t dev, const char *propname) +{ + return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint64_t)); +} /* init cpu, memory, interrupt-controller, bus... */ #define INIT_CORE_EXPORT(fn) INIT_EXPORT(fn, "1.0") @@ -40,8 +170,12 @@ const char *rt_dm_get_dev_name(rt_device_t dev); #define INIT_PLATFORM_EXPORT(fn) INIT_EXPORT(fn, "1.2") /* init sys-timer, clk, pinctrl... */ #define INIT_SUBSYS_EXPORT(fn) INIT_EXPORT(fn, "1.3") +/* init subsystem if depends more... */ +#define INIT_SUBSYS_LATER_EXPORT(fn) INIT_EXPORT(fn, "1.3.1") /* init early drivers */ #define INIT_DRIVER_EARLY_EXPORT(fn) INIT_EXPORT(fn, "1.4") +/* init early drivers */ +#define INIT_DRIVER_LATE_EXPORT(fn) INIT_EXPORT(fn, "3.0") /* init in secondary_cpu_c_start */ #define INIT_SECONDARY_CPU_EXPORT(fn) INIT_EXPORT(fn, "7") /* init after mount fs */ diff --git a/components/drivers/include/drivers/hwspinlock.h b/components/drivers/include/drivers/hwspinlock.h new file mode 100644 index 000000000000..4335f485a5cc --- /dev/null +++ b/components/drivers/include/drivers/hwspinlock.h @@ -0,0 +1,117 @@ +/* + * 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 + */ + +#ifndef __HWSPINLOCK_H__ +#define __HWSPINLOCK_H__ + +#include +#include +#include + +enum rt_hwspinlock_mode +{ + RT_HWSPINLOCK_NONE = 0, + RT_HWSPINLOCK_IRQSTATE, + RT_HWSPINLOCK_RAW, + RT_HWSPINLOCK_IN_ATOMIC, /* Called while in atomic context */ +}; + +struct rt_hwspinlock; +struct rt_hwspinlock_ops; +struct rt_hwspinlock_bank; + +rt_err_t rt_hwspinlock_bank_register(struct rt_hwspinlock_bank *bank); +rt_err_t rt_hwspinlock_bank_unregister(struct rt_hwspinlock_bank *bank); + +rt_err_t rt_hwspin_trylock_mode(struct rt_hwspinlock *hwlock, int mode, + rt_ubase_t *out_level); +rt_err_t rt_hwspin_lock_timeout_mode(struct rt_hwspinlock *hwlock, int mode, + rt_uint32_t timeout_ms, rt_ubase_t *out_level); +void rt_hwspin_unlock_mode(struct rt_hwspinlock *hwlock, int mode, + rt_ubase_t *out_level); + +rt_inline rt_err_t rt_hwspin_trylock(struct rt_hwspinlock *hwlock) +{ + return rt_hwspin_trylock_mode(hwlock, RT_HWSPINLOCK_NONE, RT_NULL); +} + +rt_inline rt_err_t rt_hwspin_trylock_irqsave(struct rt_hwspinlock *hwlock, + rt_ubase_t *out_level) +{ + return rt_hwspin_trylock_mode(hwlock, RT_HWSPINLOCK_IRQSTATE, out_level); +} + +rt_inline rt_err_t rt_hwspin_trylock_raw(struct rt_hwspinlock *hwlock) +{ + return rt_hwspin_trylock_mode(hwlock, RT_HWSPINLOCK_RAW, RT_NULL); +} + +rt_inline rt_err_t rt_hwspin_trylock_in_atomic(struct rt_hwspinlock *hwlock) +{ + return rt_hwspin_trylock_mode(hwlock, RT_HWSPINLOCK_IN_ATOMIC, RT_NULL); +} + +rt_inline rt_err_t rt_hwspin_lock_timeout(struct rt_hwspinlock *hwlock, + rt_uint32_t timeout_ms) +{ + return rt_hwspin_lock_timeout_mode(hwlock, RT_HWSPINLOCK_NONE, timeout_ms, + RT_NULL); +} + +rt_inline rt_err_t rt_hwspin_lock_timeout_irqsave(struct rt_hwspinlock *hwlock, + rt_uint32_t timeout_ms, rt_ubase_t *out_level) +{ + return rt_hwspin_lock_timeout_mode(hwlock, RT_HWSPINLOCK_IRQSTATE, + timeout_ms, out_level); +} + +rt_inline rt_err_t rt_hwspin_lock_timeout_raw(struct rt_hwspinlock *hwlock, + rt_uint32_t timeout_ms) +{ + return rt_hwspin_lock_timeout_mode(hwlock, RT_HWSPINLOCK_RAW, timeout_ms, + RT_NULL); +} + +rt_inline rt_err_t rt_hwspin_lock_timeout_in_atomic(struct rt_hwspinlock *hwlock, + rt_uint32_t timeout_ms) +{ + return rt_hwspin_lock_timeout_mode(hwlock, RT_HWSPINLOCK_IN_ATOMIC, + timeout_ms, RT_NULL); +} + +rt_inline void rt_hwspin_unlock(struct rt_hwspinlock *hwlock) +{ + rt_hwspin_unlock_mode(hwlock, RT_HWSPINLOCK_NONE, RT_NULL); +} + +rt_inline void rt_hwspin_unlock_irqsave(struct rt_hwspinlock *hwlock, + rt_ubase_t *out_level) +{ + rt_hwspin_unlock_mode(hwlock, RT_HWSPINLOCK_IRQSTATE, out_level); +} + +rt_inline void rt_hwspin_unlock_raw(struct rt_hwspinlock *hwlock) +{ + rt_hwspin_unlock_mode(hwlock, RT_HWSPINLOCK_RAW, RT_NULL); +} + +rt_inline void rt_hwspin_unlock_in_atomic(struct rt_hwspinlock *hwlock) +{ + rt_hwspin_unlock_mode(hwlock, RT_HWSPINLOCK_IN_ATOMIC, RT_NULL); +} + +struct rt_hwspinlock *rt_hwspinlock_request(void); +struct rt_hwspinlock *rt_hwspinlock_request_id(int id); +rt_err_t rt_hwspinlock_free(struct rt_hwspinlock *hwlock); + +int rt_ofw_get_hwspinlock_id(struct rt_ofw_node *np, int index); +int rt_ofw_get_hwspinlock_id_byname(struct rt_ofw_node *np, const char *name); + +#endif /* __HWSPINLOCK_H__ */ diff --git a/components/drivers/include/drivers/hwtimer.h b/components/drivers/include/drivers/hwtimer.h index 83f3d3ed9b56..6f11ff2c5456 100644 --- a/components/drivers/include/drivers/hwtimer.h +++ b/components/drivers/include/drivers/hwtimer.h @@ -78,7 +78,9 @@ typedef struct rt_hwtimer_device rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data); void rt_device_hwtimer_isr(rt_hwtimer_t *timer); +#ifdef RT_USING_DM extern void (*rt_device_hwtimer_us_delay)(rt_uint32_t us); +#endif #ifdef __cplusplus } diff --git a/components/drivers/include/drivers/i2c.h b/components/drivers/include/drivers/i2c.h index 2a900536dfc5..7badd8a480df 100644 --- a/components/drivers/include/drivers/i2c.h +++ b/components/drivers/include/drivers/i2c.h @@ -63,10 +63,41 @@ struct rt_i2c_bus_device struct rt_i2c_client { +#ifdef RT_USING_DM + struct rt_device parent; + + const char *name; + const struct rt_i2c_device_id *id; + const struct rt_ofw_node_id *ofw_id; +#endif + struct rt_i2c_bus_device *bus; rt_uint16_t client_addr; }; +#ifdef RT_USING_DM +struct rt_i2c_device_id +{ + char name[20]; + void *data; +}; + +struct rt_i2c_driver +{ + struct rt_driver parent; + + const struct rt_i2c_device_id *ids; + const struct rt_ofw_node_id *ofw_ids; + + rt_err_t (*probe)(struct rt_i2c_client *client); +}; + +rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver); +rt_err_t rt_i2c_device_register(struct rt_i2c_client *client); + +#define RT_I2C_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, i2c, BUILIN) +#endif /* RT_USING_DM */ + rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, const char *bus_name); struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name); diff --git a/components/drivers/include/drivers/mailbox.h b/components/drivers/include/drivers/mailbox.h new file mode 100644 index 000000000000..8bc713b7e3b7 --- /dev/null +++ b/components/drivers/include/drivers/mailbox.h @@ -0,0 +1,77 @@ +/* + * 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 + */ + +#ifndef __MAILBOX_H__ +#define __MAILBOX_H__ + +#include +#include + +struct rt_mbox_chan; +struct rt_mbox_client; +struct rt_mbox_controller_ops; + +struct rt_mbox_controller +{ + rt_list_t list; + + struct rt_device *dev; + + const struct rt_mbox_controller_ops *ops; + + rt_size_t num_chans; + struct rt_mbox_chan *chans; +}; + +struct rt_mbox_controller_ops +{ + rt_err_t (*request)(struct rt_mbox_chan *); + void (*free)(struct rt_mbox_chan *); + rt_err_t (*send)(struct rt_mbox_chan *, const void *data); + rt_err_t (*peek)(struct rt_mbox_chan *); + int (*ofw_parse)(struct rt_mbox_controller *, struct rt_ofw_cell_args *); +}; + +struct rt_mbox_chan +{ + struct rt_mbox_controller *ctrl; + struct rt_mbox_client *client; + + void *data; + rt_bool_t complete; + struct rt_timer timer; + struct rt_spinlock lock; + + void *priv; +}; + +struct rt_mbox_client +{ + struct rt_device *dev; + + void (*rx_callback)(struct rt_mbox_client *, void *data); + void (*tx_prepare)(struct rt_mbox_client *, const void *data); + void (*tx_done)(struct rt_mbox_client *, const void *data, rt_err_t err); +}; + +rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl); +rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl); + +rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data, + rt_uint32_t timeout_ms); +void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err); +rt_err_t rt_mbox_peek(struct rt_mbox_chan *chan); +rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data); + +struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index); +struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name); +rt_err_t rt_mbox_free(struct rt_mbox_chan *chan); + +#endif /* __MAILBOX_H__ */ diff --git a/components/drivers/include/drivers/misc.h b/components/drivers/include/drivers/misc.h index aa2b715512c7..1d894e96b3ea 100644 --- a/components/drivers/include/drivers/misc.h +++ b/components/drivers/include/drivers/misc.h @@ -12,6 +12,7 @@ #define __MISC_H__ #include +#include #ifdef ARCH_CPU_64BIT #define RT_BITS_PER_LONG 64 @@ -22,6 +23,10 @@ #define RT_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define RT_DIV_ROUND_DOWN_ULL(ll, d) ({ rt_uint64_t _tmp = (ll); rt_do_div(_tmp, d); _tmp; }) + +#define RT_DIV_ROUND_UP_ULL(ll, d) RT_DIV_ROUND_DOWN_ULL((rt_uint64_t)(ll) + (d) - 1, (d)) + #define RT_DIV_ROUND_CLOSEST(x, divisor) \ ({ \ typeof(x) __x = x; \ @@ -33,6 +38,18 @@ (((__x) - ((__d) / 2)) / (__d)); \ }) +#define RT_DIV_ROUND_CLOSEST_ULL(x, divisor) \ +({ \ + typeof(divisor) __d = divisor; \ + rt_uint64_t _tmp = (x) + (__d) / 2; \ + rt_do_div(_tmp, __d); \ + _tmp; \ +}) + +#define RT_FIELD_PREP(mask, val) (((rt_uint64_t)(val) << (__rt_ffsl((mask)) - 1)) & (mask)) +#define RT_FIELD_GET(mask, reg) (((reg) & (mask)) >> (__rt_ffsl((mask)) - 1)) +#define RT_FIELD_CLEAR(mask, reg) ((reg) & (~(mask))) + #define RT_BIT(n) (1UL << (n)) #define RT_BIT_ULL(n) (1ULL << (n)) #define RT_BIT_MASK(nr) (1UL << ((nr) % RT_BITS_PER_LONG)) @@ -48,6 +65,11 @@ #define RT_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define rt_upper_32_bits(n) ((rt_uint32_t)(((n) >> 16) >> 16)) +#define rt_lower_32_bits(n) ((rt_uint32_t)((n) & 0xffffffff)) +#define rt_upper_16_bits(n) ((rt_uint16_t)((n) >> 16)) +#define rt_lower_16_bits(n) ((rt_uint16_t)((n) & 0xffff)) + #define rt_min(x, y) \ ({ \ typeof(x) _x = (x); \ @@ -71,6 +93,13 @@ _x < _y ? _x: _y; \ }) +#define rt_max_t(type, x, y) \ +({ \ + type _x = (x); \ + type _y = (y); \ + _x > _y ? _x: _y; \ +}) + #define rt_clamp(val, lo, hi) rt_min((typeof(val))rt_max(val, lo), hi) #define rt_do_div(n, base) \ @@ -83,4 +112,48 @@ _rem; \ }) +#define rt_abs(x) \ +({ \ + long ret; \ + if (sizeof(x) == sizeof(long)) \ + { \ + long __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } \ + else \ + { \ + int __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } \ + ret; \ +}) + +#ifndef rt_ilog2 +rt_inline int rt_ilog2(rt_ubase_t v) +{ + int l = 0; + + while ((1UL << l) < v) + { + l++; + } + + return l; +} +#endif /* !rt_ilog2 */ + +#ifndef rt_bcd2bin +rt_inline rt_ubase_t rt_bcd2bin(rt_uint8_t val) +{ + return (val & 0x0f) + (val >> 4) * 10; +} +#endif /* !rt_bcd2bin */ + +#ifndef rt_bin2bcd +rt_inline rt_uint8_t rt_bin2bcd(rt_ubase_t val) +{ + return ((val / 10) << 4) + val % 10; +} +#endif /* !rt_bin2bcd */ + #endif /* __MISC_H__ */ diff --git a/components/drivers/include/drivers/mmcsd_cmd.h b/components/drivers/include/drivers/mmcsd_cmd.h index d47094281518..6fb9f37ae941 100644 --- a/components/drivers/include/drivers/mmcsd_cmd.h +++ b/components/drivers/include/drivers/mmcsd_cmd.h @@ -76,6 +76,7 @@ extern "C" { /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ #define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ +#define SD_SWITCH_VOLTAGE 11 /* ac R1 */ /* class 10 */ #define SD_SWITCH 6 /* adtc [31:0] See below R1 */ diff --git a/components/drivers/include/drivers/mmcsd_core.h b/components/drivers/include/drivers/mmcsd_core.h index 3a6ac13aa9fa..b4b0e2c2d098 100644 --- a/components/drivers/include/drivers/mmcsd_core.h +++ b/components/drivers/include/drivers/mmcsd_core.h @@ -242,6 +242,12 @@ void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width); void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing); void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card); rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage); +void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host); +rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host); +rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error); +rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode); void mmcsd_change(struct rt_mmcsd_host *host); void mmcsd_detect(void *param); void mmcsd_host_init(struct rt_mmcsd_host *host); diff --git a/components/drivers/include/drivers/mmcsd_host.h b/components/drivers/include/drivers/mmcsd_host.h index c6935c105630..e02ec76ff5fd 100644 --- a/components/drivers/include/drivers/mmcsd_host.h +++ b/components/drivers/include/drivers/mmcsd_host.h @@ -85,8 +85,23 @@ struct rt_mmcsd_host_ops rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host); void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en); rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode); + rt_bool_t (*card_busy)(struct rt_mmcsd_host *host); + rt_err_t (*signal_voltage_switch)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg); }; +#ifdef RT_USING_REGULATOR +struct rt_regulator; + +struct rt_mmcsd_supply +{ + rt_bool_t vqmmc_enabled; + rt_bool_t regulator_enabled; + + struct rt_regulator *vmmc; /* Card power supply */ + struct rt_regulator *vqmmc; /* Optional Vccq supply */ +}; +#endif /* RT_USING_REGULATOR */ + struct rt_mmcsd_host { char name[RT_NAME_MAX]; @@ -145,6 +160,10 @@ struct rt_mmcsd_host struct rt_semaphore *sdio_irq_sem; struct rt_thread *sdio_irq_thread; +#ifdef RT_USING_REGULATOR + struct rt_mmcsd_supply supply; +#endif + void *private_data; }; #ifdef __cplusplus diff --git a/components/drivers/include/drivers/ofw.h b/components/drivers/include/drivers/ofw.h index 3471726877a6..604c2134fda9 100644 --- a/components/drivers/include/drivers/ofw.h +++ b/components/drivers/include/drivers/ofw.h @@ -22,6 +22,10 @@ typedef rt_uint32_t rt_phandle; struct rt_ofw_prop { +#ifdef RT_USING_OFW_DIRECTFS + struct rt_object obj; +#endif + const char *name; int length; void *value; @@ -31,6 +35,10 @@ struct rt_ofw_prop struct rt_ofw_node { +#ifdef RT_USING_OFW_DIRECTFS + struct rt_object obj; +#endif + const char *name; /* full_name is 'path/tag' or 'path/tag@reg' */ const char *full_name; diff --git a/components/drivers/include/drivers/ofw_fdt.h b/components/drivers/include/drivers/ofw_fdt.h index a9c951ca40fb..4db4ecef6b28 100755 --- a/components/drivers/include/drivers/ofw_fdt.h +++ b/components/drivers/include/drivers/ofw_fdt.h @@ -20,6 +20,7 @@ struct rt_fdt_earlycon union { rt_ubase_t size, width; }; void *fdt; + char options[32]; long nodeoffset; void *data; @@ -41,8 +42,6 @@ struct rt_fdt_earlycon_id rt_err_t (*setup)(struct rt_fdt_earlycon *earlycon, const char *options); }; -#define RT_FDT_EARLYCON_OPTION_SIGNATURE '\n' - #define RT_FDT_EARLYCON_EXPORT(_name, _type, _compatible, _setup) \ static const struct rt_fdt_earlycon_id __rt_fdt_##_name##_earlycon \ rt_used RT_OFW_SYMBOL(earlycon, _) = \ diff --git a/components/drivers/include/drivers/ofw_io.h b/components/drivers/include/drivers/ofw_io.h index 5fdfe8f5e6f8..4ebfbe2c82ae 100755 --- a/components/drivers/include/drivers/ofw_io.h +++ b/components/drivers/include/drivers/ofw_io.h @@ -11,6 +11,7 @@ #ifndef __OFW_IO_H__ #define __OFW_IO_H__ +#include #include int rt_ofw_bus_addr_cells(struct rt_ofw_node *np); diff --git a/components/drivers/include/drivers/pci.h b/components/drivers/include/drivers/pci.h index 063d53ff53c8..526e5a7d78d0 100644 --- a/components/drivers/include/drivers/pci.h +++ b/components/drivers/include/drivers/pci.h @@ -6,4 +6,404 @@ * Change Logs: * Date Author Notes * 2022-08-25 GuEe-GUI first version - */ \ No newline at end of file + */ + +#ifndef __PCI_H__ +#define __PCI_H__ + +#include +#include +#include +#include +#include +#include + +#include "../../pci/pci_ids.h" +#include "../../pci/pci_regs.h" + +#define RT_PCI_INTX_PIN_MAX 4 +#define RT_PCI_BAR_NR_MAX 6 +#define RT_PCI_DEVICE_MAX 32 +#define RT_PCI_FUNCTION_MAX 8 + +#define RT_PCI_FIND_CAP_TTL 48 + +/* + * The PCI interface treats multi-function devices as independent + * devices. The slot/function address of each device is encoded + * in a single byte as follows: + * + * 7:3 = slot + * 2:0 = function + */ +#define RT_PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) +#define RT_PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) +#define RT_PCI_FUNC(devfn) ((devfn) & 0x07) + +struct rt_pci_bus_region +{ + rt_uint64_t phy_addr; + rt_uint64_t cpu_addr; + rt_uint64_t size; + + rt_uint64_t bus_start; + +#define PCI_BUS_REGION_F_NONE 0xffffffff /* PCI no memory */ +#define PCI_BUS_REGION_F_MEM 0x00000000 /* PCI memory space */ +#define PCI_BUS_REGION_F_IO 0x00000001 /* PCI IO space */ +#define PCI_BUS_REGION_F_PREFETCH 0x00000008 /* Prefetchable PCI memory */ + rt_ubase_t flags; +}; + +struct rt_pci_bus_resource +{ + rt_ubase_t base; + rt_size_t size; + + rt_ubase_t flags; +}; + +enum +{ + PCI_F_MULTI_FUNCTION, /* Multi-function device */ + PCI_F_NO_64BIT_MSI, /* May only use 32-bit MSIs */ + PCI_F_NO_MSI, /* May not use MSI */ + PCI_F_ARI, /* ARI forwarding */ + PCI_F_MSI, /* MSI enable */ + PCI_F_MSIX, /* MSIx enable */ + PCI_F_BROKEN_INTX_MASKING, /* INTx masking can't be used */ + + PCI_FLAGS_NR +}; + +/* + * PCI topology: + * + * +-----+-----+ +-------------+ PCI Bus 0 +------------+ PCI Bus 1 + * | RAM | CPU |---------| Host Bridge |--------+-----| PCI Bridge |-----+ + * +-----+-----+ +-------------+ | +------------+ | +-------------+ + * | +----| End Point 2 | + * +-------------+ +-------------+ | +-------------+ | +-------------+ + * | End Point 5 |----+ | End Point 0 |-------+ | End Point 3 |----+ + * +-------------+ | +-------------+ | +-------------+ | + * | | | + * +-------------+ | +-------------+ | +-------------+ | +-------------+ + * | End Point 6 |----+----| ISA Bridge |-------+-----| End Point 1 | +----| End Point 4 | + * +-------------+ +-------------+ | +-------------+ +-------------+ + * | + * +------+ +----------------+ | + * | Port |---------| CardBus Bridge |----+ + * +------+ +----------------+ + */ + +struct rt_pci_bus; + +struct rt_pci_device_id +{ +#define PCI_ANY_ID (~0) +#define RT_PCI_DEVICE_ID(vend, dev) \ + .vendor = (vend), \ + .device = (dev), \ + .subsystem_vendor = PCI_ANY_ID, \ + .subsystem_device = PCI_ANY_ID + + rt_uint32_t vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + rt_uint32_t subsystem_vendor; /* Subsystem ID's or PCI_ANY_ID */ + rt_uint32_t subsystem_device; /* Subsystem ID's or PCI_ANY_ID */ + rt_uint32_t class, class_mask; /* (class, subclass, prog-if) triplet */ + + void *data; +}; + +struct rt_pci_device +{ + struct rt_device parent; + const char *name; + + rt_list_t list; + rt_list_t list_in_bus; + struct rt_pci_bus *bus; + struct rt_pci_bus *subbus; /* In PCI-to-PCI bridge, 'End Point' or 'Port' is NULL */ + + const struct rt_pci_device_id *id; + + rt_uint32_t devfn; /* Encoded device & function index */ + rt_uint16_t vendor; + rt_uint16_t device; + rt_uint16_t subsystem_vendor; + rt_uint16_t subsystem_device; + rt_uint32_t class; /* 3 bytes: (base, sub, prog-if) */ + rt_uint8_t revision; + rt_uint8_t hdr_type; + rt_uint8_t max_latency; + rt_uint8_t min_grantl; + rt_uint8_t int_pin; + rt_uint8_t int_line; + + void *sysdata; + + int irq; + rt_uint8_t pin; + + struct rt_pci_bus_resource resource[RT_PCI_BAR_NR_MAX]; + + rt_uint8_t pcie_cap; + rt_uint8_t msi_cap; + rt_uint8_t msix_cap; + DECLARE_BITMAP(flags, PCI_FLAGS_NR); + +#ifdef RT_PCI_MSI + void *msix_base; + rt_list_t msi_desc_nodes; + struct rt_spinlock msi_lock; +#endif +}; + +struct rt_pci_host_bridge +{ + struct rt_device parent; + + rt_uint32_t busnr; + rt_uint32_t domain; + + struct rt_pci_bus *root_bus; + struct rt_pci_ops *ops; + + rt_uint32_t bus_range[2]; + rt_size_t bus_regions_nr; + struct rt_pci_bus_region *bus_regions; + + rt_uint8_t (*irq_slot)(struct rt_pci_device *pdev, rt_uint8_t *pinp); + int (*irq_map)(struct rt_pci_device *pdev, rt_uint8_t slot, rt_uint8_t pin); + + void *sysdata; + rt_uint8_t priv[0]; +}; +#define rt_device_to_pci_host_bridge(dev) rt_container_of(dev, struct rt_pci_host_bridge, parent) + +struct rt_pci_ops +{ + rt_err_t (*add)(struct rt_pci_bus *bus); + rt_err_t (*remove)(struct rt_pci_bus *bus); + + void *(*map)(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg); + + rt_err_t (*read)(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t *value); + rt_err_t (*write)(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t value); +}; + +struct rt_pci_bus +{ + rt_list_t list; + rt_list_t children_nodes; + rt_list_t devices_nodes; + struct rt_pci_bus *parent; + + union + { + /* In PCI-to-PCI bridge, parent is not NULL */ + struct rt_pci_device *self; + /* In Host bridge, this is Root bus ('PCI Bus 0') */ + struct rt_pci_host_bridge *host_bridge; + }; + + struct rt_pci_ops *ops; + + char name[48]; + char number; + + void *sysdata; +}; + +struct rt_pci_driver +{ + struct rt_driver parent; + + const char *name; + const struct rt_pci_device_id *ids; + + rt_err_t (*probe)(struct rt_pci_device *pdev); +}; + +struct rt_pci_msix_entry +{ + rt_uint32_t vector; /* Kernel uses to write allocated vector */ + rt_uint16_t entry; /* Driver uses to specify entry, OS writes */ +}; + +void rt_pci_msi_init(struct rt_pci_device *pdev); +void rt_pci_msix_init(struct rt_pci_device *pdev); + +rt_inline rt_bool_t rt_pci_device_test_flag(const struct rt_pci_device *pdev, int flag) +{ + return bitmap_test_bit((bitmap_t *)pdev->flags, flag); +} + +rt_inline void rt_pci_device_set_flag(struct rt_pci_device *pdev, int flag) +{ + bitmap_set_bit(pdev->flags, flag); +} + +rt_inline rt_bool_t rt_pci_device_test_and_set_flag(struct rt_pci_device *pdev, int flag) +{ + rt_bool_t res = rt_pci_device_test_flag(pdev, flag); + + rt_pci_device_set_flag(pdev, flag); + + return res; +} + +rt_inline void rt_pci_device_clear_flag(struct rt_pci_device *pdev, int flag) +{ + bitmap_clear_bit(pdev->flags, flag); +} + +struct rt_pci_host_bridge *rt_pci_host_bridge_alloc(rt_size_t priv_size); +rt_err_t rt_pci_host_bridge_init(struct rt_pci_host_bridge *host_bridge); +rt_err_t rt_pci_host_bridge_probe(struct rt_pci_host_bridge *host_bridge); + +struct rt_pci_device *rt_pci_alloc_device(struct rt_pci_bus *bus); +struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint32_t devfn); +rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev); +rt_size_t rt_pci_scan_slot(struct rt_pci_bus *bus, rt_uint32_t devfn); +rt_uint32_t rt_pci_scan_child_buses(struct rt_pci_bus *bus, rt_size_t buses); + +rt_err_t rt_pci_host_bridge_register(struct rt_pci_host_bridge *host_bridge); +rt_err_t rt_pci_scan_root_bus_bridge(struct rt_pci_host_bridge *host_bridge); + +rt_uint32_t rt_pci_domain(struct rt_pci_device *pdev); + +rt_uint8_t rt_pci_bus_find_capability(struct rt_pci_bus *bus, rt_uint32_t devfn, int cap); +rt_uint8_t rt_pci_find_capability(struct rt_pci_device *pdev, int cap); +rt_uint8_t rt_pci_find_next_capability(struct rt_pci_device *pdev, rt_uint8_t pos, int cap); + +struct rt_pci_bus *rt_pci_find_root_bus(struct rt_pci_bus *bus); +struct rt_pci_host_bridge *rt_pci_find_host_bridge(struct rt_pci_bus *bus); + +rt_inline rt_bool_t rt_pci_is_root_bus(struct rt_pci_bus *bus) +{ + return bus->parent ? RT_FALSE : RT_TRUE; +} + +rt_inline rt_bool_t rt_pci_is_bridge(struct rt_pci_device *pdev) +{ + return pdev->hdr_type == PCIM_HDRTYPE_BRIDGE || + pdev->hdr_type == PCIM_HDRTYPE_CARDBUS; +} + +#define rt_pci_foreach_bridge(pdev, bus) \ + rt_list_for_each_entry(pdev, &bus->devices_nodes, list_in_bus) \ + if (rt_pci_is_bridge(pdev)) + +rt_err_t rt_pci_bus_read_config_u8(struct rt_pci_bus *bus, rt_uint32_t devfn, int pos, rt_uint8_t *value); +rt_err_t rt_pci_bus_read_config_u16(struct rt_pci_bus *bus, rt_uint32_t devfn, int pos, rt_uint16_t *value); +rt_err_t rt_pci_bus_read_config_u32(struct rt_pci_bus *bus, rt_uint32_t devfn, int pos, rt_uint32_t *value); + +rt_err_t rt_pci_bus_write_config_u8(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, rt_uint8_t value); +rt_err_t rt_pci_bus_write_config_u16(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, rt_uint16_t value); +rt_err_t rt_pci_bus_write_config_u32(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, rt_uint32_t value); + +rt_err_t rt_pci_bus_read_config_uxx(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t *value); +rt_err_t rt_pci_bus_write_config_uxx(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t value); + +rt_inline rt_err_t rt_pci_read_config_u8(const struct rt_pci_device *pdev, int reg, rt_uint8_t *value) +{ + return rt_pci_bus_read_config_u8(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_err_t rt_pci_read_config_u16(const struct rt_pci_device *pdev, int reg, rt_uint16_t *value) +{ + return rt_pci_bus_read_config_u16(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_err_t rt_pci_read_config_u32(const struct rt_pci_device *pdev, int reg, rt_uint32_t *value) +{ + return rt_pci_bus_read_config_u32(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_err_t rt_pci_write_config_u8(const struct rt_pci_device *pdev, int reg, rt_uint8_t value) +{ + return rt_pci_bus_write_config_u8(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_err_t rt_pci_write_config_u16(const struct rt_pci_device *pdev, int reg, rt_uint16_t value) +{ + return rt_pci_bus_write_config_u16(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_err_t rt_pci_write_config_u32(const struct rt_pci_device *pdev, int reg, rt_uint32_t value) +{ + return rt_pci_bus_write_config_u32(pdev->bus, pdev->devfn, reg, value); +} + +rt_inline rt_bool_t rt_pci_enabled(struct rt_pci_device *pdev, int bit) +{ + return bitmap_test_bit(pdev->flags, bit); +} + +#ifdef RT_USING_OFW +int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev, rt_uint8_t slot, rt_uint8_t pin); +rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge); +rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge); +rt_err_t rt_pci_ofw_bus_init(struct rt_pci_bus *bus); +rt_err_t rt_pci_ofw_device_init(struct rt_pci_device *pdev); +#else +rt_inline rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge) +{ + return RT_EOK; +} +rt_inline rt_err_t rt_pci_ofw_bus_init(struct rt_pci_bus *bus) +{ + return RT_EOK; +} +rt_inline rt_err_t rt_pci_ofw_device_init(struct rt_pci_device *pdev) +{ + return RT_EOK; +} +rt_inline int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev, rt_uint8_t slot, rt_uint8_t pin) +{ + return -1; +} +rt_inline rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge) +{ + return -RT_ENOSYS; +} +#endif /* RT_USING_OFW */ + +rt_inline void *rt_pci_iomap(struct rt_pci_device *pdev, int bar_idx) +{ + struct rt_pci_bus_resource *res = &pdev->resource[bar_idx]; + + RT_ASSERT(bar_idx < RT_ARRAY_SIZE(pdev->resource)); + + return rt_ioremap((void *)res->base, res->size); +} + +rt_uint8_t rt_pci_irq_intx(struct rt_pci_device *pdev, rt_uint8_t pin); +rt_uint8_t rt_pci_irq_slot(struct rt_pci_device *pdev, rt_uint8_t *pinp); + +void rt_pci_assign_irq(struct rt_pci_device *pdev); + +void rt_pci_intx(struct rt_pci_device *pdev, rt_bool_t enable); +rt_bool_t rt_pci_check_and_mask_intx(struct rt_pci_device *pdev); +rt_bool_t rt_pci_check_and_unmask_intx(struct rt_pci_device *pdev); + +rt_err_t rt_pci_region_setup(struct rt_pci_host_bridge *host_bridge); +struct rt_pci_bus_region *rt_pci_region_alloc(struct rt_pci_host_bridge *host_bridge, + void **out_addr, rt_size_t size, rt_ubase_t flags, rt_bool_t mem64); + +rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge, struct rt_pci_device *pdev); + +void rt_pci_enum_device(struct rt_pci_bus *bus, rt_bool_t (callback(struct rt_pci_device *))); + +const struct rt_pci_device_id *rt_pci_match_id(struct rt_pci_device *pdev, const struct rt_pci_device_id *id); +const struct rt_pci_device_id *rt_pci_match_ids(struct rt_pci_device *pdev, const struct rt_pci_device_id *ids); + +rt_err_t rt_pci_driver_register(struct rt_pci_driver *pdrv); +rt_err_t rt_pci_device_register(struct rt_pci_device *pdev); + +#define RT_PCI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, pci, BUILIN) + +extern struct rt_spinlock rt_pci_lock; + +#endif /* __PCI_H__ */ diff --git a/components/drivers/include/drivers/pci_msi.h b/components/drivers/include/drivers/pci_msi.h index 063d53ff53c8..987888c028c8 100644 --- a/components/drivers/include/drivers/pci_msi.h +++ b/components/drivers/include/drivers/pci_msi.h @@ -6,4 +6,78 @@ * Change Logs: * Date Author Notes * 2022-08-25 GuEe-GUI first version - */ \ No newline at end of file + */ + +#ifndef __PCI_MSI_H__ +#define __PCI_MSI_H__ + +#include +#include + +struct rt_pci_msi_desc +{ + union + { + rt_uint32_t msi_mask; /* [PCI MSI] MSI cached mask bits */ + rt_uint32_t msix_ctrl; /* [PCI MSI-X] MSI-X cached per vector control bits */ + }; + struct + { + rt_uint8_t is_msix : 1; /* [PCI MSI/X] True if MSI-X */ + rt_uint8_t multiple : 3; /* [PCI MSI/X] log2 num of messages allocated */ + rt_uint8_t multi_cap : 3; /* [PCI MSI/X] log2 num of messages supported */ + rt_uint8_t can_mask : 1; /* [PCI MSI/X] Masking supported? */ + rt_uint8_t is_64 : 1; /* [PCI MSI/X] Address size is 64bit? */ + rt_uint8_t is_virtual : 1; + unsigned default_irq; /* [PCI MSI/X] The default pre-assigned non-MSI irq */ + } msi_attrib; + union + { + rt_uint8_t mask_pos; /* [PCI MSI] Mask register position */ + void *mask_base; /* [PCI MSI-X] Mask register base address */ + }; +}; + +struct rt_pci_msi_msg +{ + rt_uint32_t address_lo; + rt_uint32_t address_hi; + rt_uint32_t data; +}; + +struct rt_msi_desc +{ + rt_list_t list; + + /* Shared device/bus type independent data */ + int irq; + rt_size_t nvec_used; + struct rt_pci_device *pci_dev; + struct rt_pci_msi_msg msg; + DECLARE_BITMAP(affinity, RT_CPUS_NR); + + void (*write_msi_msg)(struct rt_pci_msi_desc *entry, void *data); + void *write_msi_msg_data; + + rt_uint16_t msi_index; + struct rt_pci_msi_desc pci; + + void *priv; +}; + +#define rt_msi_first_desc(dev) \ + rt_list_isempty(&dev->msi_desc_nodes) ? RT_NULL : rt_list_entry(dev->msi_desc_nodes.next, struct msi_desc, list) + +#define rt_msi_for_each_desc(desc, dev) \ + if (!rt_list_isempty(&dev->msi_desc_nodes) || (desc = RT_NULL, RT_FALSE)) \ + rt_list_for_each_entry(desc, &dev->msi_desc_nodes, list) + +#define rt_msix_table_size(flags) ((flags & PCIM_MSIXCTRL_TABLE_SIZE) + 1) + +void rt_pci_read_msi_msg(struct rt_pci_msi_msg *msg, struct rt_msi_desc *entry); +void rt_pci_write_msi_msg(struct rt_pci_msi_msg *msg, int irq); + +void rt_pci_msi_mask_irq(struct rt_pic_irq *pirq); +void rt_pci_msi_unmask_irq(struct rt_pic_irq *pirq); + +#endif /* __PCI_MSI_H__ */ diff --git a/components/drivers/include/drivers/phy.h b/components/drivers/include/drivers/phy.h index 862b711ff069..2bd16878b12f 100644 --- a/components/drivers/include/drivers/phy.h +++ b/components/drivers/include/drivers/phy.h @@ -54,16 +54,32 @@ typedef rt_int32_t rt_phy_status; struct rt_phy_ops { - rt_phy_status (*init)(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz); - rt_phy_status (*read)(rt_uint32_t reg, rt_uint32_t *data); - rt_phy_status (*write)(rt_uint32_t reg, rt_uint32_t data); - rt_phy_status (*loopback)(rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable); - rt_phy_status (*get_link_status)(rt_bool_t *status); - rt_phy_status (*get_link_speed_duplex)(rt_uint32_t *speed, rt_uint32_t *duplex); + rt_phy_status (*init)(struct rt_phy_device *, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz); + rt_phy_status (*exit)(struct rt_phy_device *, void *object, rt_uint32_t phy_addr); + rt_phy_status (*power_on)(struct rt_phy_device *); + rt_phy_status (*power_off)(struct rt_phy_device *); + rt_phy_status (*read)(struct rt_phy_device *, rt_uint32_t reg, rt_uint32_t *data); + rt_phy_status (*write)(struct rt_phy_device *, rt_uint32_t reg, rt_uint32_t data); + rt_phy_status (*loopback)(struct rt_phy_device *, rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable); + rt_phy_status (*get_link_status)(struct rt_phy_device *, rt_bool_t *status); + rt_phy_status (*get_link_speed_duplex)(struct rt_phy_device *, rt_uint32_t *speed, rt_uint32_t *duplex); +#ifdef RT_USING_DM + rt_err_t (*ofw_parse)(struct rt_phy_device *, struct rt_ofw_cell_args *phy_args); +#endif }; rt_err_t rt_hw_phy_register(struct rt_phy_device *phy, const char *name); +rt_phy_status rt_phy_init(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz); +rt_phy_status rt_phy_exit(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr); +rt_phy_status rt_phy_power_on(struct rt_phy_device *phy); +rt_phy_status rt_phy_power_off(struct rt_phy_device *phy); + +#ifdef RT_USING_DM +struct rt_phy_device *rt_phy_get_by_index(struct rt_device *dev, int index); +struct rt_phy_device *rt_phy_get_by_name(struct rt_device *dev, const char *id); +#endif /* RT_USING_DM */ + #ifdef __cplusplus } #endif diff --git a/components/drivers/include/drivers/pic.h b/components/drivers/include/drivers/pic.h index 8b02de69d4b9..492ef21ebec2 100755 --- a/components/drivers/include/drivers/pic.h +++ b/components/drivers/include/drivers/pic.h @@ -25,6 +25,19 @@ struct rt_pic_irq; struct rt_pic { + /* + * Other IC is not implemented with PIC but rt_device/object, we need to + * identify with this object: + * + * struct rt_ic_XYZ_device + * { + * struct rt_device parent; + * struct rt_pic pic; + * ... + * }; + */ + struct rt_object parent; + rt_list_t list; struct rt_pic_ops *ops; @@ -32,8 +45,6 @@ struct rt_pic void *priv_data; void *user_data; - struct rt_pic *parent; - int irq_start; rt_size_t irq_nr; struct rt_pic_irq *pirqs; @@ -102,8 +113,12 @@ struct rt_pic_irq struct rt_spinlock rw_lock; struct rt_pic *pic; + struct rt_pic_irq *parent; }; +void rt_pic_default_name(struct rt_pic *pic); +struct rt_pic *rt_pic_dynamic_cast(void *ptr); + rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr); int rt_pic_config_ipi(struct rt_pic *pic, int ipi_index, int hwirq); @@ -120,9 +135,10 @@ rt_inline struct rt_pic_irq *rt_pic_find_irq(struct rt_pic *pic, int irq_index) } struct rt_pic_irq *rt_pic_find_ipi(struct rt_pic *pic, int ipi_index); +struct rt_pic_irq *rt_pic_find_pirq(struct rt_pic *pic, int irq); -int rt_pic_cascade(struct rt_pic *pic, struct rt_pic *parent_pic, int hwirq, rt_uint32_t mode); -void rt_pic_uncascade(struct rt_pic *pic, int irq); +rt_err_t rt_pic_cascade(struct rt_pic_irq *pirq, int parent_irq); +rt_err_t rt_pic_uncascade(struct rt_pic_irq *pirq); rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, const char *name, int flags); rt_err_t rt_pic_detach_irq(int irq, void *uid); @@ -150,15 +166,15 @@ rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode); rt_uint32_t rt_pic_irq_get_triger_mode(int irq); void rt_pic_irq_send_ipi(int irq, bitmap_t *cpumask); -void rt_pic_irq_parent_enable(struct rt_pic *ppic, struct rt_pic_irq *pirq); -void rt_pic_irq_parent_disable(struct rt_pic *ppic, struct rt_pic_irq *pirq); -void rt_pic_irq_parent_ack(struct rt_pic *ppic, struct rt_pic_irq *pirq); -void rt_pic_irq_parent_mask(struct rt_pic *ppic, struct rt_pic_irq *pirq); -void rt_pic_irq_parent_unmask(struct rt_pic *ppic, struct rt_pic_irq *pirq); -void rt_pic_irq_parent_eoi(struct rt_pic *ppic, struct rt_pic_irq *pirq); -rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t priority); -rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic *ppic, struct rt_pic_irq *pirq, bitmap_t *affinity); -rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t mode); +void rt_pic_irq_parent_enable(struct rt_pic_irq *pirq); +void rt_pic_irq_parent_disable(struct rt_pic_irq *pirq); +void rt_pic_irq_parent_ack(struct rt_pic_irq *pirq); +void rt_pic_irq_parent_mask(struct rt_pic_irq *pirq); +void rt_pic_irq_parent_unmask(struct rt_pic_irq *pirq); +void rt_pic_irq_parent_eoi(struct rt_pic_irq *pirq); +rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority); +rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic_irq *pirq, bitmap_t *affinity); +rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode); #define RT_PIC_OFW_DECLARE(name, ids, handler) RT_OFW_STUB_EXPORT(name, ids, pic, handler) diff --git a/components/drivers/include/drivers/pin.h b/components/drivers/include/drivers/pin.h index 4b369d5b8d3f..1ec035bad3dd 100644 --- a/components/drivers/include/drivers/pin.h +++ b/components/drivers/include/drivers/pin.h @@ -7,6 +7,7 @@ * Date Author Notes * 2015-01-20 Bernard the first version * 2017-10-20 ZYH add mode open drain and input pull down + * 2022-11-26 GuEe-GUI add pic for pin in dm, support pinctrl */ #ifndef PIN_H__ @@ -18,10 +19,26 @@ extern "C" { #endif +#ifdef RT_USING_DM +#include + +struct rt_pin_irqchip +{ + struct rt_pic parent; + + int irq; + rt_base_t pin_range[2]; +}; +#endif /* RT_USING_DM */ + /* pin device and operations for RT-Thread */ struct rt_device_pin { struct rt_device parent; +#ifdef RT_USING_DM + /* MUST keep the order member after parent */ + struct rt_pin_irqchip irqchip; +#endif /* RT_USING_DM */ const struct rt_pin_ops *ops; }; @@ -36,6 +53,39 @@ struct rt_device_pin #define PIN_MODE_INPUT_PULLDOWN 0x03 #define PIN_MODE_OUTPUT_OD 0x04 +#ifdef RT_USING_PINCTRL +enum +{ + PIN_CONFIG_BIAS_BUS_HOLD, + PIN_CONFIG_BIAS_DISABLE, + PIN_CONFIG_BIAS_HIGH_IMPEDANCE, + PIN_CONFIG_BIAS_PULL_DOWN, + PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, + PIN_CONFIG_BIAS_PULL_UP, + PIN_CONFIG_DRIVE_OPEN_DRAIN, + PIN_CONFIG_DRIVE_OPEN_SOURCE, + PIN_CONFIG_DRIVE_PUSH_PULL, + PIN_CONFIG_DRIVE_STRENGTH, + PIN_CONFIG_DRIVE_STRENGTH_UA, + PIN_CONFIG_INPUT_DEBOUNCE, + PIN_CONFIG_INPUT_ENABLE, + PIN_CONFIG_INPUT_SCHMITT, + PIN_CONFIG_INPUT_SCHMITT_ENABLE, + PIN_CONFIG_MODE_LOW_POWER, + PIN_CONFIG_MODE_PWM, + PIN_CONFIG_OUTPUT, + PIN_CONFIG_OUTPUT_ENABLE, + PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, + PIN_CONFIG_PERSIST_STATE, + PIN_CONFIG_POWER_SOURCE, + PIN_CONFIG_SKEW_DELAY, + PIN_CONFIG_SLEEP_HARDWARE_STATE, + PIN_CONFIG_SLEW_RATE, + PIN_CONFIG_END = 0x7f, + PIN_CONFIG_MAX = 0xff, +}; +#endif /* RT_USING_PINCTRL */ + #define PIN_IRQ_MODE_RISING 0x00 #define PIN_IRQ_MODE_FALLING 0x01 #define PIN_IRQ_MODE_RISING_FALLING 0x02 @@ -66,6 +116,16 @@ struct rt_pin_irq_hdr void (*hdr)(void *args); void *args; }; + +#ifdef RT_USING_PINCTRL +struct rt_pin_ctrl_conf_params +{ + const char *propname; + rt_uint32_t param; + rt_uint32_t default_value; +}; +#endif /* RT_USING_PINCTRL */ + struct rt_pin_ops { void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); @@ -76,6 +136,13 @@ struct rt_pin_ops rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin); rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled); rt_base_t (*pin_get)(const char *name); +#ifdef RT_USING_DM + rt_err_t (*pin_irq_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); + rt_ssize_t (*pin_parse)(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags); +#endif +#ifdef RT_USING_PINCTRL + rt_err_t (*pin_ctrl_confs_apply)(struct rt_device *device, void *fw_conf_np); +#endif /* RT_USING_PINCTRL */ }; int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data); @@ -88,6 +155,23 @@ rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode, rt_err_t rt_pin_detach_irq(rt_base_t pin); rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled); +#ifdef RT_USING_DM +rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value); +rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname); + +#ifdef RT_USING_OFW +rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value); +rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname); +#endif +#endif /* RT_USING_DM */ + +#ifdef RT_USING_PINCTRL +rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index); +rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name); +#endif /* RT_USING_PINCTRL */ + #ifdef __cplusplus } #endif diff --git a/components/drivers/include/drivers/platform.h b/components/drivers/include/drivers/platform.h index 3caccabd2d40..d1343a2efa45 100644 --- a/components/drivers/include/drivers/platform.h +++ b/components/drivers/include/drivers/platform.h @@ -39,6 +39,8 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name); rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv); rt_err_t rt_platform_device_register(struct rt_platform_device *pdev); +rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np); + #define RT_PLATFORM_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, platform, BUILIN) #endif /* __PLATFORM_H__ */ diff --git a/components/drivers/include/drivers/pm.h b/components/drivers/include/drivers/pm.h index 6d5961b2fa27..69e525d0e237 100644 --- a/components/drivers/include/drivers/pm.h +++ b/components/drivers/include/drivers/pm.h @@ -199,8 +199,8 @@ void rt_pm_release(rt_uint8_t sleep_mode); void rt_pm_release_all(rt_uint8_t sleep_mode); int rt_pm_run_enter(rt_uint8_t run_mode); -extern void (*rt_pm_shutdown)(void); -extern void (*rt_pm_reset)(void); +extern void (*rt_pm_machine_shutdown)(void); +extern void (*rt_pm_machine_reset)(void); void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops); void rt_pm_device_unregister(struct rt_device *device); diff --git a/components/drivers/include/drivers/regulator.h b/components/drivers/include/drivers/regulator.h new file mode 100644 index 000000000000..923c20d9bb09 --- /dev/null +++ b/components/drivers/include/drivers/regulator.h @@ -0,0 +1,139 @@ +/* + * 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 + */ + +#ifndef __REGULATOR_H__ +#define __REGULATOR_H__ + +#include +#include +#include + +#include + +#define RT_REGULATOR_UVOLT_INVALID (((int)(RT_UINT32_MAX >> 1))) + +struct rt_regulator_param +{ + const char *name; + + int min_uvolt; /* In uV */ + int max_uvolt; /* In uV */ + int min_uamp; /* In uA */ + int max_uamp; /* In uA */ + int ramp_delay; /* In uV/usec */ + int enable_delay; /* In usec */ + + rt_uint32_t enable_active_high:1; + rt_uint32_t boot_on:1; /* Is enabled on boot */ + rt_uint32_t always_on:1; /* Must be enabled */ + rt_uint32_t soft_start:1; /* Ramp voltage slowly */ + rt_uint32_t pull_down:1; /* Pull down resistor when regulator off */ + rt_uint32_t over_current_protection:1; /* Auto disable on over current */ +}; + +struct rt_regulator_ops; + +struct rt_regulator_node +{ + rt_list_t list; + rt_list_t children_nodes; + + struct rt_device *dev; + struct rt_regulator_node *parent; + + const char *supply_name; + const struct rt_regulator_ops *ops; + + struct ref ref; + rt_bool_t is_enabled; + + const struct rt_regulator_param *param; + + rt_list_t notifier_nodes; + + void *priv; +}; + +/* + * NOTE: Power regulator control is dangerous work. We don't want non-internal + * consumer could access the power regulator tree without regulator's API. So + * we defined the `rt_regulator` member in core instead of here. + */ +struct rt_regulator; + +struct rt_regulator_ops +{ + rt_err_t (*enable)(struct rt_regulator_node *); + rt_err_t (*disable)(struct rt_regulator_node *); + rt_bool_t (*is_enabled)(struct rt_regulator_node *); + rt_err_t (*set_voltage)(struct rt_regulator_node *, int min_uvolt, int max_uvolt); + int (*get_voltage)(struct rt_regulator_node *); +}; + +struct rt_regulator_notifier; + +#define RT_REGULATOR_MSG_ENABLE RT_BIT(0) +#define RT_REGULATOR_MSG_DISABLE RT_BIT(1) +#define RT_REGULATOR_MSG_VOLTAGE_CHANGE RT_BIT(2) +#define RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR RT_BIT(3) + +union rt_regulator_notifier_args +{ + struct + { + int old_uvolt; + int min_uvolt; + int max_uvolt; + }; +}; + +typedef rt_err_t (*rt_regulator_notifier_callback)(struct rt_regulator_notifier *notifier, + rt_ubase_t msg, void *data); + +struct rt_regulator_notifier +{ + rt_list_t list; + + struct rt_regulator *regulator; + rt_regulator_notifier_callback callback; + void *priv; +}; + +rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np); +rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np); + +rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier); +rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier); + +struct rt_regulator *rt_regulator_get_optional(struct rt_device *dev, const char *id); +void rt_regulator_put(struct rt_regulator *reg); + +rt_err_t rt_regulator_enable(struct rt_regulator *reg); +rt_err_t rt_regulator_disable(struct rt_regulator *reg); +rt_bool_t rt_regulator_is_enabled(struct rt_regulator *reg); + +rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt); +rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt); +int rt_regulator_get_voltage(struct rt_regulator *reg); + +rt_inline rt_err_t rt_regulator_set_voltage_triplet(struct rt_regulator *reg, + int min_uvolt, int target_uvolt, int max_uvolt) +{ + if (!rt_regulator_set_voltage(reg, target_uvolt, max_uvolt)) + { + return RT_EOK; + } + + return rt_regulator_set_voltage(reg, min_uvolt, max_uvolt); +} + +#endif /* __REGULATOR_H__ */ diff --git a/components/drivers/include/drivers/reset.h b/components/drivers/include/drivers/reset.h new file mode 100644 index 000000000000..bb5776db7c9c --- /dev/null +++ b/components/drivers/include/drivers/reset.h @@ -0,0 +1,92 @@ +/* + * 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 __RESET_H__ +#define __RESET_H__ + +#include +#include +#include +#include + +struct rt_reset_control_ops; + +struct rt_reset_controller +{ + rt_list_t list; + rt_list_t rstc_nodes; + + const char *name; + const struct rt_reset_control_ops *ops; + + struct rt_ofw_node *ofw_node; + void *priv; + + struct rt_spinlock spinlock; +}; + +/* + * It seems that most reset controllers are coupled to CLK. + * So we need a generic extends object. + */ +struct rt_reset_controller_clk_node +{ + struct rt_clk_node parent; + + struct rt_reset_controller rstcer; +}; + +struct rt_reset_control +{ + rt_list_t list; + + struct rt_reset_controller *rstcer; + + int id; + const char *con_id; + rt_bool_t is_array; + rt_bool_t deassert; + + void *priv; +}; + +struct rt_reset_control_ops +{ + /* + * rt_ofw_cell_args return: + * args[0] = rstc.id + */ + rt_err_t (*ofw_parse)(struct rt_reset_control *, struct rt_ofw_cell_args *args); + /* API */ + rt_err_t (*reset)(struct rt_reset_control *rstc); + rt_err_t (*assert)(struct rt_reset_control *rstc); + rt_err_t (*deassert)(struct rt_reset_control *rstc); + int (*status)(struct rt_reset_control *rstc); +}; + +rt_err_t rt_reset_controller_register(struct rt_reset_controller *rstcer); +rt_err_t rt_reset_controller_unregister(struct rt_reset_controller *rstcer); + +rt_err_t rt_reset_control_reset(struct rt_reset_control *rstc); +rt_err_t rt_reset_control_assert(struct rt_reset_control *rstc); +rt_err_t rt_reset_control_deassert(struct rt_reset_control *rstc); +int rt_reset_control_status(struct rt_reset_control *rstc); + +rt_ssize_t rt_reset_control_get_count(struct rt_device *dev); +struct rt_reset_control *rt_reset_control_get_array(struct rt_device *dev); +struct rt_reset_control *rt_reset_control_get_by_index(struct rt_device *dev, int index); +struct rt_reset_control *rt_reset_control_get_by_name(struct rt_device *dev, const char *name); +void rt_reset_control_put(struct rt_reset_control *rstc); + +struct rt_reset_control *rt_ofw_get_reset_control_array(struct rt_ofw_node *np); +struct rt_reset_control *rt_ofw_get_reset_control_by_index(struct rt_ofw_node *np, int index); +struct rt_reset_control *rt_ofw_get_reset_control_by_name(struct rt_ofw_node *np, const char *name); + +#endif /* __RESET_H__ */ diff --git a/components/drivers/include/drivers/spi.h b/components/drivers/include/drivers/spi.h index 7f7c2cedccdc..ad537a668672 100644 --- a/components/drivers/include/drivers/spi.h +++ b/components/drivers/include/drivers/spi.h @@ -78,7 +78,12 @@ struct rt_spi_configuration { rt_uint8_t mode; rt_uint8_t data_width; +#ifdef RT_USING_DM + rt_uint8_t data_width_tx; + rt_uint8_t data_width_rx; +#else rt_uint16_t reserved; +#endif rt_uint32_t max_hz; }; @@ -90,6 +95,12 @@ struct rt_spi_bus rt_uint8_t mode; const struct rt_spi_ops *ops; +#ifdef RT_USING_DM + rt_base_t *pins; + rt_bool_t slave; + int num_chipselect; +#endif /* RT_USING_DM */ + struct rt_mutex lock; struct rt_spi_device *owner; }; @@ -103,6 +114,17 @@ struct rt_spi_ops rt_ssize_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message); }; +#ifdef RT_USING_DM +struct rt_spi_delay +{ +#define RT_SPI_DELAY_UNIT_USECS 0 +#define RT_SPI_DELAY_UNIT_NSECS 1 +#define RT_SPI_DELAY_UNIT_SCK 2 + rt_uint16_t value; + rt_uint8_t unit; +}; +#endif /* RT_USING_DM */ + /** * SPI Virtual BUS, one device must connected to a virtual BUS */ @@ -111,6 +133,17 @@ struct rt_spi_device struct rt_device parent; struct rt_spi_bus *bus; +#ifdef RT_USING_DM + const char *name; + const struct rt_spi_device_id *id; + const struct rt_ofw_node_id *ofw_id; + + rt_uint8_t chip_select; + struct rt_spi_delay cs_setup; + struct rt_spi_delay cs_hold; + struct rt_spi_delay cs_inactive; +#endif + struct rt_spi_configuration config; rt_base_t cs_pin; void *user_data; @@ -166,6 +199,29 @@ struct rt_qspi_device #define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev)) +#ifdef RT_USING_DM +struct rt_spi_device_id +{ + char name[20]; + void *data; +}; + +struct rt_spi_driver +{ + struct rt_driver parent; + + const struct rt_spi_device_id *ids; + const struct rt_ofw_node_id *ofw_ids; + + rt_err_t (*probe)(struct rt_spi_device *device); +}; + +rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver); +rt_err_t rt_spi_device_register(struct rt_spi_device *device); + +#define RT_SPI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, spi, BUILIN) +#endif /* RT_USING_DM */ + /* register a SPI bus */ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, const char *name, diff --git a/components/drivers/include/drivers/syscon.h b/components/drivers/include/drivers/syscon.h index 672449570791..2ab597c7703b 100755 --- a/components/drivers/include/drivers/syscon.h +++ b/components/drivers/include/drivers/syscon.h @@ -30,7 +30,7 @@ rt_err_t rt_syscon_write(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t rt_err_t rt_syscon_update_bits(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t mask, rt_uint32_t val); struct rt_syscon *rt_syscon_find_by_ofw_node(struct rt_ofw_node *np); -struct rt_syscon *rt_syscon_find_by_compatible(const char *compatible); -struct rt_syscon *rt_syscon_find_by_phandle(struct rt_ofw_node *np, const char *propname); +struct rt_syscon *rt_syscon_find_by_ofw_compatible(const char *compatible); +struct rt_syscon *rt_syscon_find_by_ofw_phandle(struct rt_ofw_node *np, const char *propname); #endif /* __SYSCON_H__ */ diff --git a/components/drivers/include/drivers/virtio.h b/components/drivers/include/drivers/virtio.h index 95f490121e90..5b93a2e06163 100644 --- a/components/drivers/include/drivers/virtio.h +++ b/components/drivers/include/drivers/virtio.h @@ -19,6 +19,8 @@ #include #include +#include "../../virtio/virtio_ids.h" + #define VIRTIO_STATUS_ACKNOWLEDGE RT_BIT(0) #define VIRTIO_STATUS_DRIVER RT_BIT(1) #define VIRTIO_STATUS_DRIVER_OK RT_BIT(2) @@ -43,69 +45,6 @@ #define VIRTIO_TRANSPORT_F_START VIRTIO_F_RING_INDIRECT_DESC #define VIRTIO_TRANSPORT_F_END VIRTIO_F_RING_RESET -enum -{ - /* virtio 1.0 */ - VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */ - VIRTIO_DEVICE_ID_NET = 1, /* Net */ - VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */ - VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */ - VIRTIO_DEVICE_ID_RNG = 4, /* Rng */ - VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */ - VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */ - VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */ - VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */ - VIRTIO_DEVICE_ID_9P = 9, /* 9p console */ - VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */ - VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */ - VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */ - VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */ - VIRTIO_DEVICE_ID_GPU = 16, /* GPU */ - VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */ - VIRTIO_DEVICE_ID_INPUT = 18, /* Input */ - /* virtio 1.1 */ - VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */ - VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */ - VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */ - VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */ - VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */ - VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */ - /* virtio 1.2 */ - VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */ - VIRTIO_DEVICE_ID_FS = 26, /* File system device */ - VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */ - VIRTIO_DEVICE_ID_RPMB = 28, /* RPMB device */ - VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */ - VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */ - VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */ - VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */ - VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */ - VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */ - VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */ - VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */ - VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */ - VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */ - VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */ - VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */ - VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */ - VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */ - - VIRTIO_DEVICE_ID_MAX -}; - -enum -{ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_NET = 0x1000, /* Network card */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BLOCK = 0x1001, /* Block device */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BALLOON = 0x1002, /* Memory ballooning (traditional) */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_CONSOLE = 0x1003, /* Console */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_SCSI = 0x1004, /* SCSI host */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_RNG = 0x1005, /* Entropy source */ - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_9P = 0x1009, /* 9P transport */ - - VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_MAX -}; - struct rt_virtio_device_id { #define VIRTIO_DEVICE_ANY_ID 0xffffffff diff --git a/components/drivers/include/dt-bindings/clock/rk3308-cru.h b/components/drivers/include/dt-bindings/clock/rk3308-cru.h new file mode 100644 index 000000000000..3967932d2d1a --- /dev/null +++ b/components/drivers/include/dt-bindings/clock/rk3308-cru.h @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLK_ROCKCHIP_RK3308_H__ +#define __DT_BINDINGS_CLK_ROCKCHIP_RK3308_H__ + +/* core clocks */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_VPLL0 3 +#define PLL_VPLL1 4 +#define ARMCLK 5 + +/* sclk (special clocks) */ +#define USB480M 14 +#define SCLK_RTC32K 15 +#define SCLK_PVTM_CORE 16 +#define SCLK_UART0 17 +#define SCLK_UART1 18 +#define SCLK_UART2 19 +#define SCLK_UART3 20 +#define SCLK_UART4 21 +#define SCLK_I2C0 22 +#define SCLK_I2C1 23 +#define SCLK_I2C2 24 +#define SCLK_I2C3 25 +#define SCLK_PWM0 26 +#define SCLK_SPI0 27 +#define SCLK_SPI1 28 +#define SCLK_SPI2 29 +#define SCLK_TIMER0 30 +#define SCLK_TIMER1 31 +#define SCLK_TIMER2 32 +#define SCLK_TIMER3 33 +#define SCLK_TIMER4 34 +#define SCLK_TIMER5 35 +#define SCLK_TSADC 36 +#define SCLK_SARADC 37 +#define SCLK_OTP 38 +#define SCLK_OTP_USR 39 +#define SCLK_CPU_BOOST 40 +#define SCLK_CRYPTO 41 +#define SCLK_CRYPTO_APK 42 +#define SCLK_NANDC_DIV 43 +#define SCLK_NANDC_DIV50 44 +#define SCLK_NANDC 45 +#define SCLK_SDMMC_DIV 46 +#define SCLK_SDMMC_DIV50 47 +#define SCLK_SDMMC 48 +#define SCLK_SDMMC_DRV 49 +#define SCLK_SDMMC_SAMPLE 50 +#define SCLK_SDIO_DIV 51 +#define SCLK_SDIO_DIV50 52 +#define SCLK_SDIO 53 +#define SCLK_SDIO_DRV 54 +#define SCLK_SDIO_SAMPLE 55 +#define SCLK_EMMC_DIV 56 +#define SCLK_EMMC_DIV50 57 +#define SCLK_EMMC 58 +#define SCLK_EMMC_DRV 59 +#define SCLK_EMMC_SAMPLE 60 +#define SCLK_SFC 61 +#define SCLK_OTG_ADP 62 +#define SCLK_MAC_SRC 63 +#define SCLK_MAC 64 +#define SCLK_MAC_REF 65 +#define SCLK_MAC_RX_TX 66 +#define SCLK_MAC_RMII 67 +#define SCLK_DDR_MON_TIMER 68 +#define SCLK_DDR_MON 69 +#define SCLK_DDRCLK 70 +#define SCLK_PMU 71 +#define SCLK_USBPHY_REF 72 +#define SCLK_WIFI 73 +#define SCLK_PVTM_PMU 74 +#define SCLK_PDM 75 +#define SCLK_I2S0_8CH_TX 76 +#define SCLK_I2S0_8CH_TX_OUT 77 +#define SCLK_I2S0_8CH_RX 78 +#define SCLK_I2S0_8CH_RX_OUT 79 +#define SCLK_I2S1_8CH_TX 80 +#define SCLK_I2S1_8CH_TX_OUT 81 +#define SCLK_I2S1_8CH_RX 82 +#define SCLK_I2S1_8CH_RX_OUT 83 +#define SCLK_I2S2_8CH_TX 84 +#define SCLK_I2S2_8CH_TX_OUT 85 +#define SCLK_I2S2_8CH_RX 86 +#define SCLK_I2S2_8CH_RX_OUT 87 +#define SCLK_I2S3_8CH_TX 88 +#define SCLK_I2S3_8CH_TX_OUT 89 +#define SCLK_I2S3_8CH_RX 90 +#define SCLK_I2S3_8CH_RX_OUT 91 +#define SCLK_I2S0_2CH 92 +#define SCLK_I2S0_2CH_OUT 93 +#define SCLK_I2S1_2CH 94 +#define SCLK_I2S1_2CH_OUT 95 +#define SCLK_SPDIF_TX_DIV 96 +#define SCLK_SPDIF_TX_DIV50 97 +#define SCLK_SPDIF_TX 98 +#define SCLK_SPDIF_RX_DIV 99 +#define SCLK_SPDIF_RX_DIV50 100 +#define SCLK_SPDIF_RX 101 +#define SCLK_I2S0_8CH_TX_MUX 102 +#define SCLK_I2S0_8CH_RX_MUX 103 +#define SCLK_I2S1_8CH_TX_MUX 104 +#define SCLK_I2S1_8CH_RX_MUX 105 +#define SCLK_I2S2_8CH_TX_MUX 106 +#define SCLK_I2S2_8CH_RX_MUX 107 +#define SCLK_I2S3_8CH_TX_MUX 108 +#define SCLK_I2S3_8CH_RX_MUX 109 +#define SCLK_I2S0_8CH_TX_SRC 110 +#define SCLK_I2S0_8CH_RX_SRC 111 +#define SCLK_I2S1_8CH_TX_SRC 112 +#define SCLK_I2S1_8CH_RX_SRC 113 +#define SCLK_I2S2_8CH_TX_SRC 114 +#define SCLK_I2S2_8CH_RX_SRC 115 +#define SCLK_I2S3_8CH_TX_SRC 116 +#define SCLK_I2S3_8CH_RX_SRC 117 +#define SCLK_I2S0_2CH_SRC 118 +#define SCLK_I2S1_2CH_SRC 119 +#define SCLK_PWM1 120 +#define SCLK_PWM2 121 +#define SCLK_OWIRE 122 + +/* dclk */ +#define DCLK_VOP 125 + +/* aclk */ +#define ACLK_BUS_SRC 130 +#define ACLK_BUS 131 +#define ACLK_PERI_SRC 132 +#define ACLK_PERI 133 +#define ACLK_MAC 134 +#define ACLK_CRYPTO 135 +#define ACLK_VOP 136 +#define ACLK_GIC 137 +#define ACLK_DMAC0 138 +#define ACLK_DMAC1 139 + +/* hclk */ +#define HCLK_BUS 150 +#define HCLK_PERI 151 +#define HCLK_AUDIO 152 +#define HCLK_NANDC 153 +#define HCLK_SDMMC 154 +#define HCLK_SDIO 155 +#define HCLK_EMMC 156 +#define HCLK_SFC 157 +#define HCLK_OTG 158 +#define HCLK_HOST 159 +#define HCLK_HOST_ARB 160 +#define HCLK_PDM 161 +#define HCLK_SPDIFTX 162 +#define HCLK_SPDIFRX 163 +#define HCLK_I2S0_8CH 164 +#define HCLK_I2S1_8CH 165 +#define HCLK_I2S2_8CH 166 +#define HCLK_I2S3_8CH 167 +#define HCLK_I2S0_2CH 168 +#define HCLK_I2S1_2CH 169 +#define HCLK_VAD 170 +#define HCLK_CRYPTO 171 +#define HCLK_VOP 172 + +/* pclk */ +#define PCLK_BUS 190 +#define PCLK_DDR 191 +#define PCLK_PERI 192 +#define PCLK_PMU 193 +#define PCLK_AUDIO 194 +#define PCLK_MAC 195 +#define PCLK_ACODEC 196 +#define PCLK_UART0 197 +#define PCLK_UART1 198 +#define PCLK_UART2 199 +#define PCLK_UART3 200 +#define PCLK_UART4 201 +#define PCLK_I2C0 202 +#define PCLK_I2C1 203 +#define PCLK_I2C2 204 +#define PCLK_I2C3 205 +#define PCLK_PWM0 206 +#define PCLK_SPI0 207 +#define PCLK_SPI1 208 +#define PCLK_SPI2 209 +#define PCLK_SARADC 210 +#define PCLK_TSADC 211 +#define PCLK_TIMER 212 +#define PCLK_OTP_NS 213 +#define PCLK_WDT 214 +#define PCLK_GPIO0 215 +#define PCLK_GPIO1 216 +#define PCLK_GPIO2 217 +#define PCLK_GPIO3 218 +#define PCLK_GPIO4 219 +#define PCLK_SGRF 220 +#define PCLK_GRF 221 +#define PCLK_USBSD_DET 222 +#define PCLK_DDR_UPCTL 223 +#define PCLK_DDR_MON 224 +#define PCLK_DDRPHY 225 +#define PCLK_DDR_STDBY 226 +#define PCLK_USB_GRF 227 +#define PCLK_CRU 228 +#define PCLK_OTP_PHY 229 +#define PCLK_CPU_BOOST 230 +#define PCLK_PWM1 231 +#define PCLK_PWM2 232 +#define PCLK_CAN 233 +#define PCLK_OWIRE 234 + +#define CLK_NR_CLKS (PCLK_OWIRE + 1) + +/* soft-reset indices */ + +/* cru_softrst_con0 */ +#define SRST_CORE0_PO 0 +#define SRST_CORE1_PO 1 +#define SRST_CORE2_PO 2 +#define SRST_CORE3_PO 3 +#define SRST_CORE0 4 +#define SRST_CORE1 5 +#define SRST_CORE2 6 +#define SRST_CORE3 7 +#define SRST_CORE0_DBG 8 +#define SRST_CORE1_DBG 9 +#define SRST_CORE2_DBG 10 +#define SRST_CORE3_DBG 11 +#define SRST_TOPDBG 12 +#define SRST_CORE_NOC 13 +#define SRST_STRC_A 14 +#define SRST_L2C 15 + +/* cru_softrst_con1 */ +#define SRST_DAP 16 +#define SRST_CORE_PVTM 17 +#define SRST_CORE_PRF 18 +#define SRST_CORE_GRF 19 +#define SRST_DDRUPCTL 20 +#define SRST_DDRUPCTL_P 22 +#define SRST_MSCH 23 +#define SRST_DDRMON_P 25 +#define SRST_DDRSTDBY_P 26 +#define SRST_DDRSTDBY 27 +#define SRST_DDRPHY 28 +#define SRST_DDRPHY_DIV 29 +#define SRST_DDRPHY_P 30 + +/* cru_softrst_con2 */ +#define SRST_BUS_NIU_H 32 +#define SRST_USB_NIU_P 33 +#define SRST_CRYPTO_A 34 +#define SRST_CRYPTO_H 35 +#define SRST_CRYPTO 36 +#define SRST_CRYPTO_APK 37 +#define SRST_VOP_A 38 +#define SRST_VOP_H 39 +#define SRST_VOP_D 40 +#define SRST_INTMEM_A 41 +#define SRST_ROM_H 42 +#define SRST_GIC_A 43 +#define SRST_UART0_P 44 +#define SRST_UART0 45 +#define SRST_UART1_P 46 +#define SRST_UART1 47 + +/* cru_softrst_con3 */ +#define SRST_UART2_P 48 +#define SRST_UART2 49 +#define SRST_UART3_P 50 +#define SRST_UART3 51 +#define SRST_UART4_P 52 +#define SRST_UART4 53 +#define SRST_I2C0_P 54 +#define SRST_I2C0 55 +#define SRST_I2C1_P 56 +#define SRST_I2C1 57 +#define SRST_I2C2_P 58 +#define SRST_I2C2 59 +#define SRST_I2C3_P 60 +#define SRST_I2C3 61 +#define SRST_PWM0_P 62 +#define SRST_PWM0 63 + +/* cru_softrst_con4 */ +#define SRST_SPI0_P 64 +#define SRST_SPI0 65 +#define SRST_SPI1_P 66 +#define SRST_SPI1 67 +#define SRST_SPI2_P 68 +#define SRST_SPI2 69 +#define SRST_SARADC_P 70 +#define SRST_TSADC_P 71 +#define SRST_TSADC 72 +#define SRST_TIMER0_P 73 +#define SRST_TIMER0 74 +#define SRST_TIMER1 75 +#define SRST_TIMER2 76 +#define SRST_TIMER3 77 +#define SRST_TIMER4 78 +#define SRST_TIMER5 79 + +/* cru_softrst_con5 */ +#define SRST_OTP_NS_P 80 +#define SRST_OTP_NS_SBPI 81 +#define SRST_OTP_NS_USR 82 +#define SRST_OTP_PHY_P 83 +#define SRST_OTP_PHY 84 +#define SRST_GPIO0_P 86 +#define SRST_GPIO1_P 87 +#define SRST_GPIO2_P 88 +#define SRST_GPIO3_P 89 +#define SRST_GPIO4_P 90 +#define SRST_GRF_P 91 +#define SRST_USBSD_DET_P 92 +#define SRST_PMU 93 +#define SRST_PMU_PVTM 94 +#define SRST_USB_GRF_P 95 + +/* cru_softrst_con6 */ +#define SRST_CPU_BOOST 96 +#define SRST_CPU_BOOST_P 97 +#define SRST_PWM1_P 98 +#define SRST_PWM1 99 +#define SRST_PWM2_P 100 +#define SRST_PWM2 101 +#define SRST_PERI_NIU_A 104 +#define SRST_PERI_NIU_H 105 +#define SRST_PERI_NIU_p 106 +#define SRST_USB2OTG_H 107 +#define SRST_USB2OTG 108 +#define SRST_USB2OTG_ADP 109 +#define SRST_USB2HOST_H 110 +#define SRST_USB2HOST_ARB_H 111 + +/* cru_softrst_con7 */ +#define SRST_USB2HOST_AUX_H 112 +#define SRST_USB2HOST_EHCI 113 +#define SRST_USB2HOST 114 +#define SRST_USBPHYPOR 115 +#define SRST_UTMI0 116 +#define SRST_UTMI1 117 +#define SRST_SDIO_H 118 +#define SRST_EMMC_H 119 +#define SRST_SFC_H 120 +#define SRST_SFC 121 +#define SRST_SD_H 122 +#define SRST_NANDC_H 123 +#define SRST_NANDC_N 124 +#define SRST_MAC_A 125 +#define SRST_CAN_P 126 +#define SRST_OWIRE_P 127 + +/* cru_softrst_con8 */ +#define SRST_AUDIO_NIU_H 128 +#define SRST_AUDIO_NIU_P 129 +#define SRST_PDM_H 130 +#define SRST_PDM_M 131 +#define SRST_SPDIFTX_H 132 +#define SRST_SPDIFTX_M 133 +#define SRST_SPDIFRX_H 134 +#define SRST_SPDIFRX_M 135 +#define SRST_I2S0_8CH_H 136 +#define SRST_I2S0_8CH_TX_M 137 +#define SRST_I2S0_8CH_RX_M 138 +#define SRST_I2S1_8CH_H 139 +#define SRST_I2S1_8CH_TX_M 140 +#define SRST_I2S1_8CH_RX_M 141 +#define SRST_I2S2_8CH_H 142 +#define SRST_I2S2_8CH_TX_M 143 + +/* cru_softrst_con9 */ +#define SRST_I2S2_8CH_RX_M 144 +#define SRST_I2S3_8CH_H 145 +#define SRST_I2S3_8CH_TX_M 146 +#define SRST_I2S3_8CH_RX_M 147 +#define SRST_I2S0_2CH_H 148 +#define SRST_I2S0_2CH_M 149 +#define SRST_I2S1_2CH_H 150 +#define SRST_I2S1_2CH_M 151 +#define SRST_VAD_H 152 +#define SRST_ACODEC_P 153 + +#endif /* __DT_BINDINGS_CLK_ROCKCHIP_RK3308_H__ */ diff --git a/components/drivers/include/dt-bindings/clock/rk3568-cru.h b/components/drivers/include/dt-bindings/clock/rk3568-cru.h new file mode 100755 index 000000000000..cc57edf1f064 --- /dev/null +++ b/components/drivers/include/dt-bindings/clock/rk3568-cru.h @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_CLK_ROCKCHIP_RK3568_H__ +#define __DT_BINDINGS_CLK_ROCKCHIP_RK3568_H__ + +/* pmucru-clocks indices */ + +/* pmucru plls */ +#define PLL_PPLL 1 +#define PLL_HPLL 2 + +/* pmucru clocks */ +#define XIN_OSC0_DIV 4 +#define CLK_RTC_32K 5 +#define CLK_PMU 6 +#define CLK_I2C0 7 +#define CLK_RTC32K_FRAC 8 +#define CLK_UART0_DIV 9 +#define CLK_UART0_FRAC 10 +#define SCLK_UART0 11 +#define DBCLK_GPIO0 12 +#define CLK_PWM0 13 +#define CLK_CAPTURE_PWM0_NDFT 14 +#define CLK_PMUPVTM 15 +#define CLK_CORE_PMUPVTM 16 +#define CLK_REF24M 17 +#define XIN_OSC0_USBPHY0_G 18 +#define CLK_USBPHY0_REF 19 +#define XIN_OSC0_USBPHY1_G 20 +#define CLK_USBPHY1_REF 21 +#define XIN_OSC0_MIPIDSIPHY0_G 22 +#define CLK_MIPIDSIPHY0_REF 23 +#define XIN_OSC0_MIPIDSIPHY1_G 24 +#define CLK_MIPIDSIPHY1_REF 25 +#define CLK_WIFI_DIV 26 +#define CLK_WIFI_OSC0 27 +#define CLK_WIFI 28 +#define CLK_PCIEPHY0_DIV 29 +#define CLK_PCIEPHY0_OSC0 30 +#define CLK_PCIEPHY0_REF 31 +#define CLK_PCIEPHY1_DIV 32 +#define CLK_PCIEPHY1_OSC0 33 +#define CLK_PCIEPHY1_REF 34 +#define CLK_PCIEPHY2_DIV 35 +#define CLK_PCIEPHY2_OSC0 36 +#define CLK_PCIEPHY2_REF 37 +#define CLK_PCIE30PHY_REF_M 38 +#define CLK_PCIE30PHY_REF_N 39 +#define CLK_HDMI_REF 40 +#define XIN_OSC0_EDPPHY_G 41 +#define PCLK_PDPMU 42 +#define PCLK_PMU 43 +#define PCLK_UART0 44 +#define PCLK_I2C0 45 +#define PCLK_GPIO0 46 +#define PCLK_PMUPVTM 47 +#define PCLK_PWM0 48 +#define CLK_PDPMU 49 +#define SCLK_32K_IOE 50 + +#define CLKPMU_NR_CLKS (SCLK_32K_IOE + 1) + +/* cru-clocks indices */ + +/* cru plls */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_GPLL 4 +#define PLL_VPLL 5 +#define PLL_NPLL 6 + +/* cru clocks */ +#define CPLL_333M 9 +#define ARMCLK 10 +#define USB480M 11 +#define ACLK_CORE_NIU2BUS 18 +#define CLK_CORE_PVTM 19 +#define CLK_CORE_PVTM_CORE 20 +#define CLK_CORE_PVTPLL 21 +#define CLK_GPU_SRC 22 +#define CLK_GPU_PRE_NDFT 23 +#define CLK_GPU_PRE_MUX 24 +#define ACLK_GPU_PRE 25 +#define PCLK_GPU_PRE 26 +#define CLK_GPU 27 +#define CLK_GPU_NP5 28 +#define PCLK_GPU_PVTM 29 +#define CLK_GPU_PVTM 30 +#define CLK_GPU_PVTM_CORE 31 +#define CLK_GPU_PVTPLL 32 +#define CLK_NPU_SRC 33 +#define CLK_NPU_PRE_NDFT 34 +#define CLK_NPU 35 +#define CLK_NPU_NP5 36 +#define HCLK_NPU_PRE 37 +#define PCLK_NPU_PRE 38 +#define ACLK_NPU_PRE 39 +#define ACLK_NPU 40 +#define HCLK_NPU 41 +#define PCLK_NPU_PVTM 42 +#define CLK_NPU_PVTM 43 +#define CLK_NPU_PVTM_CORE 44 +#define CLK_NPU_PVTPLL 45 +#define CLK_DDRPHY1X_SRC 46 +#define CLK_DDRPHY1X_HWFFC_SRC 47 +#define CLK_DDR1X 48 +#define CLK_MSCH 49 +#define CLK24_DDRMON 50 +#define ACLK_GIC_AUDIO 51 +#define HCLK_GIC_AUDIO 52 +#define HCLK_SDMMC_BUFFER 53 +#define DCLK_SDMMC_BUFFER 54 +#define ACLK_GIC600 55 +#define ACLK_SPINLOCK 56 +#define HCLK_I2S0_8CH 57 +#define HCLK_I2S1_8CH 58 +#define HCLK_I2S2_2CH 59 +#define HCLK_I2S3_2CH 60 +#define CLK_I2S0_8CH_TX_SRC 61 +#define CLK_I2S0_8CH_TX_FRAC 62 +#define MCLK_I2S0_8CH_TX 63 +#define I2S0_MCLKOUT_TX 64 +#define CLK_I2S0_8CH_RX_SRC 65 +#define CLK_I2S0_8CH_RX_FRAC 66 +#define MCLK_I2S0_8CH_RX 67 +#define I2S0_MCLKOUT_RX 68 +#define CLK_I2S1_8CH_TX_SRC 69 +#define CLK_I2S1_8CH_TX_FRAC 70 +#define MCLK_I2S1_8CH_TX 71 +#define I2S1_MCLKOUT_TX 72 +#define CLK_I2S1_8CH_RX_SRC 73 +#define CLK_I2S1_8CH_RX_FRAC 74 +#define MCLK_I2S1_8CH_RX 75 +#define I2S1_MCLKOUT_RX 76 +#define CLK_I2S2_2CH_SRC 77 +#define CLK_I2S2_2CH_FRAC 78 +#define MCLK_I2S2_2CH 79 +#define I2S2_MCLKOUT 80 +#define CLK_I2S3_2CH_TX_SRC 81 +#define CLK_I2S3_2CH_TX_FRAC 82 +#define MCLK_I2S3_2CH_TX 83 +#define I2S3_MCLKOUT_TX 84 +#define CLK_I2S3_2CH_RX_SRC 85 +#define CLK_I2S3_2CH_RX_FRAC 86 +#define MCLK_I2S3_2CH_RX 87 +#define I2S3_MCLKOUT_RX 88 +#define HCLK_PDM 89 +#define MCLK_PDM 90 +#define HCLK_VAD 91 +#define HCLK_SPDIF_8CH 92 +#define MCLK_SPDIF_8CH_SRC 93 +#define MCLK_SPDIF_8CH_FRAC 94 +#define MCLK_SPDIF_8CH 95 +#define HCLK_AUDPWM 96 +#define SCLK_AUDPWM_SRC 97 +#define SCLK_AUDPWM_FRAC 98 +#define SCLK_AUDPWM 99 +#define HCLK_ACDCDIG 100 +#define CLK_ACDCDIG_I2C 101 +#define CLK_ACDCDIG_DAC 102 +#define CLK_ACDCDIG_ADC 103 +#define ACLK_SECURE_FLASH 104 +#define HCLK_SECURE_FLASH 105 +#define ACLK_CRYPTO_NS 106 +#define HCLK_CRYPTO_NS 107 +#define CLK_CRYPTO_NS_CORE 108 +#define CLK_CRYPTO_NS_PKA 109 +#define CLK_CRYPTO_NS_RNG 110 +#define HCLK_TRNG_NS 111 +#define CLK_TRNG_NS 112 +#define PCLK_OTPC_NS 113 +#define CLK_OTPC_NS_SBPI 114 +#define CLK_OTPC_NS_USR 115 +#define HCLK_NANDC 116 +#define NCLK_NANDC 117 +#define HCLK_SFC 118 +#define HCLK_SFC_XIP 119 +#define SCLK_SFC 120 +#define ACLK_EMMC 121 +#define HCLK_EMMC 122 +#define BCLK_EMMC 123 +#define CCLK_EMMC 124 +#define TCLK_EMMC 125 +#define ACLK_PIPE 126 +#define PCLK_PIPE 127 +#define PCLK_PIPE_GRF 128 +#define ACLK_PCIE20_MST 129 +#define ACLK_PCIE20_SLV 130 +#define ACLK_PCIE20_DBI 131 +#define PCLK_PCIE20 132 +#define CLK_PCIE20_AUX_NDFT 133 +#define CLK_PCIE20_AUX_DFT 134 +#define CLK_PCIE20_PIPE_DFT 135 +#define ACLK_PCIE30X1_MST 136 +#define ACLK_PCIE30X1_SLV 137 +#define ACLK_PCIE30X1_DBI 138 +#define PCLK_PCIE30X1 139 +#define CLK_PCIE30X1_AUX_NDFT 140 +#define CLK_PCIE30X1_AUX_DFT 141 +#define CLK_PCIE30X1_PIPE_DFT 142 +#define ACLK_PCIE30X2_MST 143 +#define ACLK_PCIE30X2_SLV 144 +#define ACLK_PCIE30X2_DBI 145 +#define PCLK_PCIE30X2 146 +#define CLK_PCIE30X2_AUX_NDFT 147 +#define CLK_PCIE30X2_AUX_DFT 148 +#define CLK_PCIE30X2_PIPE_DFT 149 +#define ACLK_SATA0 150 +#define CLK_SATA0_PMALIVE 151 +#define CLK_SATA0_RXOOB 152 +#define CLK_SATA0_PIPE_NDFT 153 +#define CLK_SATA0_PIPE_DFT 154 +#define ACLK_SATA1 155 +#define CLK_SATA1_PMALIVE 156 +#define CLK_SATA1_RXOOB 157 +#define CLK_SATA1_PIPE_NDFT 158 +#define CLK_SATA1_PIPE_DFT 159 +#define ACLK_SATA2 160 +#define CLK_SATA2_PMALIVE 161 +#define CLK_SATA2_RXOOB 162 +#define CLK_SATA2_PIPE_NDFT 163 +#define CLK_SATA2_PIPE_DFT 164 +#define ACLK_USB3OTG0 165 +#define CLK_USB3OTG0_REF 166 +#define CLK_USB3OTG0_SUSPEND 167 +#define ACLK_USB3OTG1 168 +#define CLK_USB3OTG1_REF 169 +#define CLK_USB3OTG1_SUSPEND 170 +#define CLK_XPCS_EEE 171 +#define PCLK_XPCS 172 +#define ACLK_PHP 173 +#define HCLK_PHP 174 +#define PCLK_PHP 175 +#define HCLK_SDMMC0 176 +#define CLK_SDMMC0 177 +#define HCLK_SDMMC1 178 +#define CLK_SDMMC1 179 +#define ACLK_GMAC0 180 +#define PCLK_GMAC0 181 +#define CLK_MAC0_2TOP 182 +#define CLK_MAC0_OUT 183 +#define CLK_MAC0_REFOUT 184 +#define CLK_GMAC0_PTP_REF 185 +#define ACLK_USB 186 +#define HCLK_USB 187 +#define PCLK_USB 188 +#define HCLK_USB2HOST0 189 +#define HCLK_USB2HOST0_ARB 190 +#define HCLK_USB2HOST1 191 +#define HCLK_USB2HOST1_ARB 192 +#define HCLK_SDMMC2 193 +#define CLK_SDMMC2 194 +#define ACLK_GMAC1 195 +#define PCLK_GMAC1 196 +#define CLK_MAC1_2TOP 197 +#define CLK_MAC1_OUT 198 +#define CLK_MAC1_REFOUT 199 +#define CLK_GMAC1_PTP_REF 200 +#define ACLK_PERIMID 201 +#define HCLK_PERIMID 202 +#define ACLK_VI 203 +#define HCLK_VI 204 +#define PCLK_VI 205 +#define ACLK_VICAP 206 +#define HCLK_VICAP 207 +#define DCLK_VICAP 208 +#define ICLK_VICAP_G 209 +#define ACLK_ISP 210 +#define HCLK_ISP 211 +#define CLK_ISP 212 +#define PCLK_CSI2HOST1 213 +#define CLK_CIF_OUT 214 +#define CLK_CAM0_OUT 215 +#define CLK_CAM1_OUT 216 +#define ACLK_VO 217 +#define HCLK_VO 218 +#define PCLK_VO 219 +#define ACLK_VOP_PRE 220 +#define ACLK_VOP 221 +#define HCLK_VOP 222 +#define DCLK_VOP0 223 +#define DCLK_VOP1 224 +#define DCLK_VOP2 225 +#define CLK_VOP_PWM 226 +#define ACLK_HDCP 227 +#define HCLK_HDCP 228 +#define PCLK_HDCP 229 +#define PCLK_HDMI_HOST 230 +#define CLK_HDMI_SFR 231 +#define PCLK_DSITX_0 232 +#define PCLK_DSITX_1 233 +#define PCLK_EDP_CTRL 234 +#define CLK_EDP_200M 235 +#define ACLK_VPU_PRE 236 +#define HCLK_VPU_PRE 237 +#define ACLK_VPU 238 +#define HCLK_VPU 239 +#define ACLK_RGA_PRE 240 +#define HCLK_RGA_PRE 241 +#define PCLK_RGA_PRE 242 +#define ACLK_RGA 243 +#define HCLK_RGA 244 +#define CLK_RGA_CORE 245 +#define ACLK_IEP 246 +#define HCLK_IEP 247 +#define CLK_IEP_CORE 248 +#define HCLK_EBC 249 +#define DCLK_EBC 250 +#define ACLK_JDEC 251 +#define HCLK_JDEC 252 +#define ACLK_JENC 253 +#define HCLK_JENC 254 +#define PCLK_EINK 255 +#define HCLK_EINK 256 +#define ACLK_RKVENC_PRE 257 +#define HCLK_RKVENC_PRE 258 +#define ACLK_RKVENC 259 +#define HCLK_RKVENC 260 +#define CLK_RKVENC_CORE 261 +#define ACLK_RKVDEC_PRE 262 +#define HCLK_RKVDEC_PRE 263 +#define ACLK_RKVDEC 264 +#define HCLK_RKVDEC 265 +#define CLK_RKVDEC_CA 266 +#define CLK_RKVDEC_CORE 267 +#define CLK_RKVDEC_HEVC_CA 268 +#define ACLK_BUS 269 +#define PCLK_BUS 270 +#define PCLK_TSADC 271 +#define CLK_TSADC_TSEN 272 +#define CLK_TSADC 273 +#define PCLK_SARADC 274 +#define CLK_SARADC 275 +#define PCLK_SCR 276 +#define PCLK_WDT_NS 277 +#define TCLK_WDT_NS 278 +#define ACLK_DMAC0 279 +#define ACLK_DMAC1 280 +#define ACLK_MCU 281 +#define PCLK_INTMUX 282 +#define PCLK_MAILBOX 283 +#define PCLK_UART1 284 +#define CLK_UART1_SRC 285 +#define CLK_UART1_FRAC 286 +#define SCLK_UART1 287 +#define PCLK_UART2 288 +#define CLK_UART2_SRC 289 +#define CLK_UART2_FRAC 290 +#define SCLK_UART2 291 +#define PCLK_UART3 292 +#define CLK_UART3_SRC 293 +#define CLK_UART3_FRAC 294 +#define SCLK_UART3 295 +#define PCLK_UART4 296 +#define CLK_UART4_SRC 297 +#define CLK_UART4_FRAC 298 +#define SCLK_UART4 299 +#define PCLK_UART5 300 +#define CLK_UART5_SRC 301 +#define CLK_UART5_FRAC 302 +#define SCLK_UART5 303 +#define PCLK_UART6 304 +#define CLK_UART6_SRC 305 +#define CLK_UART6_FRAC 306 +#define SCLK_UART6 307 +#define PCLK_UART7 308 +#define CLK_UART7_SRC 309 +#define CLK_UART7_FRAC 310 +#define SCLK_UART7 311 +#define PCLK_UART8 312 +#define CLK_UART8_SRC 313 +#define CLK_UART8_FRAC 314 +#define SCLK_UART8 315 +#define PCLK_UART9 316 +#define CLK_UART9_SRC 317 +#define CLK_UART9_FRAC 318 +#define SCLK_UART9 319 +#define PCLK_CAN0 320 +#define CLK_CAN0 321 +#define PCLK_CAN1 322 +#define CLK_CAN1 323 +#define PCLK_CAN2 324 +#define CLK_CAN2 325 +#define CLK_I2C 326 +#define PCLK_I2C1 327 +#define CLK_I2C1 328 +#define PCLK_I2C2 329 +#define CLK_I2C2 330 +#define PCLK_I2C3 331 +#define CLK_I2C3 332 +#define PCLK_I2C4 333 +#define CLK_I2C4 334 +#define PCLK_I2C5 335 +#define CLK_I2C5 336 +#define PCLK_SPI0 337 +#define CLK_SPI0 338 +#define PCLK_SPI1 339 +#define CLK_SPI1 340 +#define PCLK_SPI2 341 +#define CLK_SPI2 342 +#define PCLK_SPI3 343 +#define CLK_SPI3 344 +#define PCLK_PWM1 345 +#define CLK_PWM1 346 +#define CLK_PWM1_CAPTURE 347 +#define PCLK_PWM2 348 +#define CLK_PWM2 349 +#define CLK_PWM2_CAPTURE 350 +#define PCLK_PWM3 351 +#define CLK_PWM3 352 +#define CLK_PWM3_CAPTURE 353 +#define DBCLK_GPIO 354 +#define PCLK_GPIO1 355 +#define DBCLK_GPIO1 356 +#define PCLK_GPIO2 357 +#define DBCLK_GPIO2 358 +#define PCLK_GPIO3 359 +#define DBCLK_GPIO3 360 +#define PCLK_GPIO4 361 +#define DBCLK_GPIO4 362 +#define OCC_SCAN_CLK_GPIO 363 +#define PCLK_TIMER 364 +#define CLK_TIMER0 365 +#define CLK_TIMER1 366 +#define CLK_TIMER2 367 +#define CLK_TIMER3 368 +#define CLK_TIMER4 369 +#define CLK_TIMER5 370 +#define ACLK_TOP_HIGH 371 +#define ACLK_TOP_LOW 372 +#define HCLK_TOP 373 +#define PCLK_TOP 374 +#define PCLK_PCIE30PHY 375 +#define CLK_OPTC_ARB 376 +#define PCLK_MIPICSIPHY 377 +#define PCLK_MIPIDSIPHY0 378 +#define PCLK_MIPIDSIPHY1 379 +#define PCLK_PIPEPHY0 380 +#define PCLK_PIPEPHY1 381 +#define PCLK_PIPEPHY2 382 +#define PCLK_CPU_BOOST 383 +#define CLK_CPU_BOOST 384 +#define PCLK_OTPPHY 385 +#define SCLK_GMAC0 386 +#define SCLK_GMAC0_RGMII_SPEED 387 +#define SCLK_GMAC0_RMII_SPEED 388 +#define SCLK_GMAC0_RX_TX 389 +#define SCLK_GMAC1 390 +#define SCLK_GMAC1_RGMII_SPEED 391 +#define SCLK_GMAC1_RMII_SPEED 392 +#define SCLK_GMAC1_RX_TX 393 +#define SCLK_SDMMC0_DRV 394 +#define SCLK_SDMMC0_SAMPLE 395 +#define SCLK_SDMMC1_DRV 396 +#define SCLK_SDMMC1_SAMPLE 397 +#define SCLK_SDMMC2_DRV 398 +#define SCLK_SDMMC2_SAMPLE 399 +#define SCLK_EMMC_DRV 400 +#define SCLK_EMMC_SAMPLE 401 +#define PCLK_EDPPHY_GRF 402 +#define CLK_HDMI_CEC 403 +#define CLK_I2S0_8CH_TX 404 +#define CLK_I2S0_8CH_RX 405 +#define CLK_I2S1_8CH_TX 406 +#define CLK_I2S1_8CH_RX 407 +#define CLK_I2S2_2CH 408 +#define CLK_I2S3_2CH_TX 409 +#define CLK_I2S3_2CH_RX 410 +#define CPLL_500M 411 +#define CPLL_250M 412 +#define CPLL_125M 413 +#define CPLL_62P5M 414 +#define CPLL_50M 415 +#define CPLL_25M 416 +#define CPLL_100M 417 +#define SCLK_DDRCLK 418 + +#define PCLK_CORE_PVTM 450 + +#define CLK_NR_CLKS (PCLK_CORE_PVTM + 1) + +/* pmu soft-reset indices */ +/* pmucru_softrst_con0 */ +#define SRST_P_PDPMU_NIU 0 +#define SRST_P_PMUCRU 1 +#define SRST_P_PMUGRF 2 +#define SRST_P_I2C0 3 +#define SRST_I2C0 4 +#define SRST_P_UART0 5 +#define SRST_S_UART0 6 +#define SRST_P_PWM0 7 +#define SRST_PWM0 8 +#define SRST_P_GPIO0 9 +#define SRST_GPIO0 10 +#define SRST_P_PMUPVTM 11 +#define SRST_PMUPVTM 12 + +/* soft-reset indices */ + +/* cru_softrst_con0 */ +#define SRST_NCORERESET0 0 +#define SRST_NCORERESET1 1 +#define SRST_NCORERESET2 2 +#define SRST_NCORERESET3 3 +#define SRST_NCPUPORESET0 4 +#define SRST_NCPUPORESET1 5 +#define SRST_NCPUPORESET2 6 +#define SRST_NCPUPORESET3 7 +#define SRST_NSRESET 8 +#define SRST_NSPORESET 9 +#define SRST_NATRESET 10 +#define SRST_NGICRESET 11 +#define SRST_NPRESET 12 +#define SRST_NPERIPHRESET 13 + +/* cru_softrst_con1 */ +#define SRST_A_CORE_NIU2DDR 16 +#define SRST_A_CORE_NIU2BUS 17 +#define SRST_P_DBG_NIU 18 +#define SRST_P_DBG 19 +#define SRST_P_DBG_DAPLITE 20 +#define SRST_DAP 21 +#define SRST_A_ADB400_CORE2GIC 22 +#define SRST_A_ADB400_GIC2CORE 23 +#define SRST_P_CORE_GRF 24 +#define SRST_P_CORE_PVTM 25 +#define SRST_CORE_PVTM 26 +#define SRST_CORE_PVTPLL 27 + +/* cru_softrst_con2 */ +#define SRST_GPU 32 +#define SRST_A_GPU_NIU 33 +#define SRST_P_GPU_NIU 34 +#define SRST_P_GPU_PVTM 35 +#define SRST_GPU_PVTM 36 +#define SRST_GPU_PVTPLL 37 +#define SRST_A_NPU_NIU 40 +#define SRST_H_NPU_NIU 41 +#define SRST_P_NPU_NIU 42 +#define SRST_A_NPU 43 +#define SRST_H_NPU 44 +#define SRST_P_NPU_PVTM 45 +#define SRST_NPU_PVTM 46 +#define SRST_NPU_PVTPLL 47 + +/* cru_softrst_con3 */ +#define SRST_A_MSCH 51 +#define SRST_HWFFC_CTRL 52 +#define SRST_DDR_ALWAYSON 53 +#define SRST_A_DDRSPLIT 54 +#define SRST_DDRDFI_CTL 55 +#define SRST_A_DMA2DDR 57 + +/* cru_softrst_con4 */ +#define SRST_A_PERIMID_NIU 64 +#define SRST_H_PERIMID_NIU 65 +#define SRST_A_GIC_AUDIO_NIU 66 +#define SRST_H_GIC_AUDIO_NIU 67 +#define SRST_A_GIC600 68 +#define SRST_A_GIC600_DEBUG 69 +#define SRST_A_GICADB_CORE2GIC 70 +#define SRST_A_GICADB_GIC2CORE 71 +#define SRST_A_SPINLOCK 72 +#define SRST_H_SDMMC_BUFFER 73 +#define SRST_D_SDMMC_BUFFER 74 +#define SRST_H_I2S0_8CH 75 +#define SRST_H_I2S1_8CH 76 +#define SRST_H_I2S2_2CH 77 +#define SRST_H_I2S3_2CH 78 + +/* cru_softrst_con5 */ +#define SRST_M_I2S0_8CH_TX 80 +#define SRST_M_I2S0_8CH_RX 81 +#define SRST_M_I2S1_8CH_TX 82 +#define SRST_M_I2S1_8CH_RX 83 +#define SRST_M_I2S2_2CH 84 +#define SRST_M_I2S3_2CH_TX 85 +#define SRST_M_I2S3_2CH_RX 86 +#define SRST_H_PDM 87 +#define SRST_M_PDM 88 +#define SRST_H_VAD 89 +#define SRST_H_SPDIF_8CH 90 +#define SRST_M_SPDIF_8CH 91 +#define SRST_H_AUDPWM 92 +#define SRST_S_AUDPWM 93 +#define SRST_H_ACDCDIG 94 +#define SRST_ACDCDIG 95 + +/* cru_softrst_con6 */ +#define SRST_A_SECURE_FLASH_NIU 96 +#define SRST_H_SECURE_FLASH_NIU 97 +#define SRST_A_CRYPTO_NS 103 +#define SRST_H_CRYPTO_NS 104 +#define SRST_CRYPTO_NS_CORE 105 +#define SRST_CRYPTO_NS_PKA 106 +#define SRST_CRYPTO_NS_RNG 107 +#define SRST_H_TRNG_NS 108 +#define SRST_TRNG_NS 109 + +/* cru_softrst_con7 */ +#define SRST_H_NANDC 112 +#define SRST_N_NANDC 113 +#define SRST_H_SFC 114 +#define SRST_H_SFC_XIP 115 +#define SRST_S_SFC 116 +#define SRST_A_EMMC 117 +#define SRST_H_EMMC 118 +#define SRST_B_EMMC 119 +#define SRST_C_EMMC 120 +#define SRST_T_EMMC 121 + +/* cru_softrst_con8 */ +#define SRST_A_PIPE_NIU 128 +#define SRST_P_PIPE_NIU 130 +#define SRST_P_PIPE_GRF 133 +#define SRST_A_SATA0 134 +#define SRST_SATA0_PIPE 135 +#define SRST_SATA0_PMALIVE 136 +#define SRST_SATA0_RXOOB 137 +#define SRST_A_SATA1 138 +#define SRST_SATA1_PIPE 139 +#define SRST_SATA1_PMALIVE 140 +#define SRST_SATA1_RXOOB 141 + +/* cru_softrst_con9 */ +#define SRST_A_SATA2 144 +#define SRST_SATA2_PIPE 145 +#define SRST_SATA2_PMALIVE 146 +#define SRST_SATA2_RXOOB 147 +#define SRST_USB3OTG0 148 +#define SRST_USB3OTG1 149 +#define SRST_XPCS 150 +#define SRST_XPCS_TX_DIV10 151 +#define SRST_XPCS_RX_DIV10 152 +#define SRST_XPCS_XGXS_RX 153 + +/* cru_softrst_con10 */ +#define SRST_P_PCIE20 160 +#define SRST_PCIE20_POWERUP 161 +#define SRST_MSTR_ARESET_PCIE20 162 +#define SRST_SLV_ARESET_PCIE20 163 +#define SRST_DBI_ARESET_PCIE20 164 +#define SRST_BRESET_PCIE20 165 +#define SRST_PERST_PCIE20 166 +#define SRST_CORE_RST_PCIE20 167 +#define SRST_NSTICKY_RST_PCIE20 168 +#define SRST_STICKY_RST_PCIE20 169 +#define SRST_PWR_RST_PCIE20 170 + +/* cru_softrst_con11 */ +#define SRST_P_PCIE30X1 176 +#define SRST_PCIE30X1_POWERUP 177 +#define SRST_M_ARESET_PCIE30X1 178 +#define SRST_S_ARESET_PCIE30X1 179 +#define SRST_D_ARESET_PCIE30X1 180 +#define SRST_BRESET_PCIE30X1 181 +#define SRST_PERST_PCIE30X1 182 +#define SRST_CORE_RST_PCIE30X1 183 +#define SRST_NSTC_RST_PCIE30X1 184 +#define SRST_STC_RST_PCIE30X1 185 +#define SRST_PWR_RST_PCIE30X1 186 + +/* cru_softrst_con12 */ +#define SRST_P_PCIE30X2 192 +#define SRST_PCIE30X2_POWERUP 193 +#define SRST_M_ARESET_PCIE30X2 194 +#define SRST_S_ARESET_PCIE30X2 195 +#define SRST_D_ARESET_PCIE30X2 196 +#define SRST_BRESET_PCIE30X2 197 +#define SRST_PERST_PCIE30X2 198 +#define SRST_CORE_RST_PCIE30X2 199 +#define SRST_NSTC_RST_PCIE30X2 200 +#define SRST_STC_RST_PCIE30X2 201 +#define SRST_PWR_RST_PCIE30X2 202 + +/* cru_softrst_con13 */ +#define SRST_A_PHP_NIU 208 +#define SRST_H_PHP_NIU 209 +#define SRST_P_PHP_NIU 210 +#define SRST_H_SDMMC0 211 +#define SRST_SDMMC0 212 +#define SRST_H_SDMMC1 213 +#define SRST_SDMMC1 214 +#define SRST_A_GMAC0 215 +#define SRST_GMAC0_TIMESTAMP 216 + +/* cru_softrst_con14 */ +#define SRST_A_USB_NIU 224 +#define SRST_H_USB_NIU 225 +#define SRST_P_USB_NIU 226 +#define SRST_P_USB_GRF 227 +#define SRST_H_USB2HOST0 228 +#define SRST_H_USB2HOST0_ARB 229 +#define SRST_USB2HOST0_UTMI 230 +#define SRST_H_USB2HOST1 231 +#define SRST_H_USB2HOST1_ARB 232 +#define SRST_USB2HOST1_UTMI 233 +#define SRST_H_SDMMC2 234 +#define SRST_SDMMC2 235 +#define SRST_A_GMAC1 236 +#define SRST_GMAC1_TIMESTAMP 237 + +/* cru_softrst_con15 */ +#define SRST_A_VI_NIU 240 +#define SRST_H_VI_NIU 241 +#define SRST_P_VI_NIU 242 +#define SRST_A_VICAP 247 +#define SRST_H_VICAP 248 +#define SRST_D_VICAP 249 +#define SRST_I_VICAP 250 +#define SRST_P_VICAP 251 +#define SRST_H_ISP 252 +#define SRST_ISP 253 +#define SRST_P_CSI2HOST1 255 + +/* cru_softrst_con16 */ +#define SRST_A_VO_NIU 256 +#define SRST_H_VO_NIU 257 +#define SRST_P_VO_NIU 258 +#define SRST_A_VOP_NIU 259 +#define SRST_A_VOP 260 +#define SRST_H_VOP 261 +#define SRST_VOP0 262 +#define SRST_VOP1 263 +#define SRST_VOP2 264 +#define SRST_VOP_PWM 265 +#define SRST_A_HDCP 266 +#define SRST_H_HDCP 267 +#define SRST_P_HDCP 268 +#define SRST_P_HDMI_HOST 270 +#define SRST_HDMI_HOST 271 + +/* cru_softrst_con17 */ +#define SRST_P_DSITX_0 272 +#define SRST_P_DSITX_1 273 +#define SRST_P_EDP_CTRL 274 +#define SRST_EDP_24M 275 +#define SRST_A_VPU_NIU 280 +#define SRST_H_VPU_NIU 281 +#define SRST_A_VPU 282 +#define SRST_H_VPU 283 +#define SRST_H_EINK 286 +#define SRST_P_EINK 287 + +/* cru_softrst_con18 */ +#define SRST_A_RGA_NIU 288 +#define SRST_H_RGA_NIU 289 +#define SRST_P_RGA_NIU 290 +#define SRST_A_RGA 292 +#define SRST_H_RGA 293 +#define SRST_RGA_CORE 294 +#define SRST_A_IEP 295 +#define SRST_H_IEP 296 +#define SRST_IEP_CORE 297 +#define SRST_H_EBC 298 +#define SRST_D_EBC 299 +#define SRST_A_JDEC 300 +#define SRST_H_JDEC 301 +#define SRST_A_JENC 302 +#define SRST_H_JENC 303 + +/* cru_softrst_con19 */ +#define SRST_A_VENC_NIU 304 +#define SRST_H_VENC_NIU 305 +#define SRST_A_RKVENC 307 +#define SRST_H_RKVENC 308 +#define SRST_RKVENC_CORE 309 + +/* cru_softrst_con20 */ +#define SRST_A_RKVDEC_NIU 320 +#define SRST_H_RKVDEC_NIU 321 +#define SRST_A_RKVDEC 322 +#define SRST_H_RKVDEC 323 +#define SRST_RKVDEC_CA 324 +#define SRST_RKVDEC_CORE 325 +#define SRST_RKVDEC_HEVC_CA 326 + +/* cru_softrst_con21 */ +#define SRST_A_BUS_NIU 336 +#define SRST_P_BUS_NIU 338 +#define SRST_P_CAN0 340 +#define SRST_CAN0 341 +#define SRST_P_CAN1 342 +#define SRST_CAN1 343 +#define SRST_P_CAN2 344 +#define SRST_CAN2 345 +#define SRST_P_GPIO1 346 +#define SRST_GPIO1 347 +#define SRST_P_GPIO2 348 +#define SRST_GPIO2 349 +#define SRST_P_GPIO3 350 +#define SRST_GPIO3 351 + +/* cru_softrst_con22 */ +#define SRST_P_GPIO4 352 +#define SRST_GPIO4 353 +#define SRST_P_I2C1 354 +#define SRST_I2C1 355 +#define SRST_P_I2C2 356 +#define SRST_I2C2 357 +#define SRST_P_I2C3 358 +#define SRST_I2C3 359 +#define SRST_P_I2C4 360 +#define SRST_I2C4 361 +#define SRST_P_I2C5 362 +#define SRST_I2C5 363 +#define SRST_P_OTPC_NS 364 +#define SRST_OTPC_NS_SBPI 365 +#define SRST_OTPC_NS_USR 366 + +/* cru_softrst_con23 */ +#define SRST_P_PWM1 368 +#define SRST_PWM1 369 +#define SRST_P_PWM2 370 +#define SRST_PWM2 371 +#define SRST_P_PWM3 372 +#define SRST_PWM3 373 +#define SRST_P_SPI0 374 +#define SRST_SPI0 375 +#define SRST_P_SPI1 376 +#define SRST_SPI1 377 +#define SRST_P_SPI2 378 +#define SRST_SPI2 379 +#define SRST_P_SPI3 380 +#define SRST_SPI3 381 + +/* cru_softrst_con24 */ +#define SRST_P_SARADC 384 +#define SRST_P_TSADC 385 +#define SRST_TSADC 386 +#define SRST_P_TIMER 387 +#define SRST_TIMER0 388 +#define SRST_TIMER1 389 +#define SRST_TIMER2 390 +#define SRST_TIMER3 391 +#define SRST_TIMER4 392 +#define SRST_TIMER5 393 +#define SRST_P_UART1 394 +#define SRST_S_UART1 395 + +/* cru_softrst_con25 */ +#define SRST_P_UART2 400 +#define SRST_S_UART2 401 +#define SRST_P_UART3 402 +#define SRST_S_UART3 403 +#define SRST_P_UART4 404 +#define SRST_S_UART4 405 +#define SRST_P_UART5 406 +#define SRST_S_UART5 407 +#define SRST_P_UART6 408 +#define SRST_S_UART6 409 +#define SRST_P_UART7 410 +#define SRST_S_UART7 411 +#define SRST_P_UART8 412 +#define SRST_S_UART8 413 +#define SRST_P_UART9 414 +#define SRST_S_UART9 415 + +/* cru_softrst_con26 */ +#define SRST_P_GRF 416 +#define SRST_P_GRF_VCCIO12 417 +#define SRST_P_GRF_VCCIO34 418 +#define SRST_P_GRF_VCCIO567 419 +#define SRST_P_SCR 420 +#define SRST_P_WDT_NS 421 +#define SRST_T_WDT_NS 422 +#define SRST_P_DFT2APB 423 +#define SRST_A_MCU 426 +#define SRST_P_INTMUX 427 +#define SRST_P_MAILBOX 428 + +/* cru_softrst_con27 */ +#define SRST_A_TOP_HIGH_NIU 432 +#define SRST_A_TOP_LOW_NIU 433 +#define SRST_H_TOP_NIU 434 +#define SRST_P_TOP_NIU 435 +#define SRST_P_TOP_CRU 438 +#define SRST_P_DDRPHY 439 +#define SRST_DDRPHY 440 +#define SRST_P_MIPICSIPHY 442 +#define SRST_P_MIPIDSIPHY0 443 +#define SRST_P_MIPIDSIPHY1 444 +#define SRST_P_PCIE30PHY 445 +#define SRST_PCIE30PHY 446 +#define SRST_P_PCIE30PHY_GRF 447 + +/* cru_softrst_con28 */ +#define SRST_P_APB2ASB_LEFT 448 +#define SRST_P_APB2ASB_BOTTOM 449 +#define SRST_P_ASB2APB_LEFT 450 +#define SRST_P_ASB2APB_BOTTOM 451 +#define SRST_P_PIPEPHY0 452 +#define SRST_PIPEPHY0 453 +#define SRST_P_PIPEPHY1 454 +#define SRST_PIPEPHY1 455 +#define SRST_P_PIPEPHY2 456 +#define SRST_PIPEPHY2 457 +#define SRST_P_USB2PHY0_GRF 458 +#define SRST_P_USB2PHY1_GRF 459 +#define SRST_P_CPU_BOOST 460 +#define SRST_CPU_BOOST 461 +#define SRST_P_OTPPHY 462 +#define SRST_OTPPHY 463 + +/* cru_softrst_con29 */ +#define SRST_USB2PHY0_POR 464 +#define SRST_USB2PHY0_USB3OTG0 465 +#define SRST_USB2PHY0_USB3OTG1 466 +#define SRST_USB2PHY1_POR 467 +#define SRST_USB2PHY1_USB2HOST0 468 +#define SRST_USB2PHY1_USB2HOST1 469 +#define SRST_P_EDPPHY_GRF 470 +#define SRST_TSADCPHY 471 +#define SRST_GMAC0_DELAYLINE 472 +#define SRST_GMAC1_DELAYLINE 473 +#define SRST_OTPC_ARB 474 +#define SRST_P_PIPEPHY0_GRF 475 +#define SRST_P_PIPEPHY1_GRF 476 +#define SRST_P_PIPEPHY2_GRF 477 + +#endif /* __DT_BINDINGS_CLK_ROCKCHIP_RK3568_H__ */ diff --git a/components/drivers/include/dt-bindings/interrupt-controller/irq.h b/components/drivers/include/dt-bindings/interrupt-controller/irq.h index 6252787f4d61..4ca8b237ddc8 100644 --- a/components/drivers/include/dt-bindings/interrupt-controller/irq.h +++ b/components/drivers/include/dt-bindings/interrupt-controller/irq.h @@ -7,11 +7,11 @@ #ifndef __DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H__ #define __DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H__ -#define IRQ_TYPE_NONE 0 -#define IRQ_TYPE_EDGE_RISING 1 -#define IRQ_TYPE_EDGE_FALLING 2 -#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) -#define IRQ_TYPE_LEVEL_HIGH 4 -#define IRQ_TYPE_LEVEL_LOW 8 +#define IRQ_TYPE_NONE 0 +#define IRQ_TYPE_EDGE_RISING 1 +#define IRQ_TYPE_EDGE_FALLING 2 +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) +#define IRQ_TYPE_LEVEL_HIGH 4 +#define IRQ_TYPE_LEVEL_LOW 8 #endif /* __DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H__ */ \ No newline at end of file diff --git a/components/drivers/include/dt-bindings/phy/phy-snps-pcie3.h b/components/drivers/include/dt-bindings/phy/phy-snps-pcie3.h new file mode 100644 index 000000000000..81d4ba92cb53 --- /dev/null +++ b/components/drivers/include/dt-bindings/phy/phy-snps-pcie3.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PHY_SNPS_PCIE3_H__ +#define __DT_BINDINGS_PHY_SNPS_PCIE3_H__ + +/* + * pcie30_phy_mode[2:0] + * bit2: aggregation + * bit1: bifurcation for port 1 + * bit0: bifurcation for port 0 + */ +#define PHY_MODE_PCIE_AGGREGATION 4 /* PCIe3x4 */ +#define PHY_MODE_PCIE_NANBNB 0 /* P1:PCIe3x2 + P0:PCIe3x2 */ +#define PHY_MODE_PCIE_NANBBI 1 /* P1:PCIe3x2 + P0:PCIe3x1*2 */ +#define PHY_MODE_PCIE_NABINB 2 /* P1:PCIe3x1*2 + P0:PCIe3x2 */ +#define PHY_MODE_PCIE_NABIBI 3 /* P1:PCIe3x1*2 + P0:PCIe3x1*2 */ + +#endif /* __DT_BINDINGS_PHY_SNPS_PCIE3_H__ */ diff --git a/components/drivers/include/dt-bindings/phy/phy.h b/components/drivers/include/dt-bindings/phy/phy.h new file mode 100644 index 000000000000..3d92bf919807 --- /dev/null +++ b/components/drivers/include/dt-bindings/phy/phy.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PHY_H__ +#define __DT_BINDINGS_PHY_H__ + +#define PHY_NONE 0 +#define PHY_TYPE_SATA 1 +#define PHY_TYPE_PCIE 2 +#define PHY_TYPE_USB2 3 +#define PHY_TYPE_USB3 4 +#define PHY_TYPE_UFS 5 +#define PHY_TYPE_DP 6 +#define PHY_TYPE_XPCS 7 +#define PHY_TYPE_SGMII 8 +#define PHY_TYPE_QSGMII 9 +#define PHY_TYPE_DPHY 10 +#define PHY_TYPE_CPHY 11 +#define PHY_TYPE_USXGMII 12 + +#endif /* __DT_BINDINGS_PHY_H__ */ diff --git a/components/drivers/include/dt-bindings/pin/pin.h b/components/drivers/include/dt-bindings/pin/pin.h new file mode 100644 index 000000000000..3e72289d225d --- /dev/null +++ b/components/drivers/include/dt-bindings/pin/pin.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PIN_PIN_H__ +#define __DT_BINDINGS_PIN_PIN_H__ + +/* Bit 0 express polarity */ +#define PIN_ACTIVE_HIGH 0 +#define PIN_ACTIVE_LOW 1 + +/* Bit 1 express single-endedness */ +#define PIN_PUSH_PULL 0 +#define PIN_SINGLE_ENDED 2 + +/* Bit 2 express Open drain or open source */ +#define PIN_LINE_OPEN_SOURCE 0 +#define PIN_LINE_OPEN_DRAIN 4 + +/* + * Open Drain/Collector is the combination of single-ended open drain interface. + * Open Source/Emitter is the combination of single-ended open source interface. + */ +#define PIN_OPEN_DRAIN (PIN_SINGLE_ENDED | PIN_LINE_OPEN_DRAIN) +#define PIN_OPEN_SOURCE (PIN_SINGLE_ENDED | PIN_LINE_OPEN_SOURCE) + +/* Bit 3 express PIN suspend/resume and reset persistence */ +#define PIN_PERSISTENT 0 +#define PIN_TRANSITORY 8 + +/* Bit 4 express pull up */ +#define PIN_PULL_UP 16 + +/* Bit 5 express pull down */ +#define PIN_PULL_DOWN 32 + +/* Bit 6 express pull disable */ +#define PIN_PULL_DISABLE 64 + +#endif /* __DT_BINDINGS_PIN_PIN_H__ */ \ No newline at end of file diff --git a/components/drivers/include/dt-bindings/pin/state.h b/components/drivers/include/dt-bindings/pin/state.h new file mode 100644 index 000000000000..40af55b783ff --- /dev/null +++ b/components/drivers/include/dt-bindings/pin/state.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PIN_STATE_H__ +#define __DT_BINDINGS_PIN_STATE_H__ + +#define PIND_FLAGS_BIT_DIR_SET (1 << 0) +#define PIND_FLAGS_BIT_DIR_OUT (1 << 1) +#define PIND_FLAGS_BIT_DIR_VAL (1 << 2) +#define PIND_FLAGS_BIT_OPEN_DRAIN (1 << 3) +#define PIND_FLAGS_BIT_NONEXCLUSIVE (1 << 4) + +/* Don't change anything */ +#define PIND_ASIS 0 +/* Set lines to input mode */ +#define PIND_IN PIND_FLAGS_BIT_DIR_SET +/* Set lines to output and drive them low */ +#define PIND_OUT_LOW (PIND_FLAGS_BIT_DIR_SET | PIND_FLAGS_BIT_DIR_OUT) +/* Set lines to output and drive them high */ +#define PIND_OUT_HIGH (PIND_FLAGS_BIT_DIR_SET | PIND_FLAGS_BIT_DIR_OUT | PIND_FLAGS_BIT_DIR_VAL) +/* Set lines to open-drain output and drive them low */ +#define PIND_OUT_LOW_OPEN_DRAIN (PIND_OUT_LOW | PIND_FLAGS_BIT_OPEN_DRAIN) +/* Set lines to open-drain output and drive them high */ +#define PIND_OUT_HIGH_OPEN_DRAIN (PIND_OUT_HIGH | PIND_FLAGS_BIT_OPEN_DRAIN) + +#endif /* __DT_BINDINGS_PIN_STATE_H__ */ \ No newline at end of file diff --git a/components/drivers/include/dt-bindings/pinctrl/rockchip.h b/components/drivers/include/dt-bindings/pinctrl/rockchip.h new file mode 100644 index 000000000000..7cee4123eba1 --- /dev/null +++ b/components/drivers/include/dt-bindings/pinctrl/rockchip.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PINCTRL_ROCKCHIP_H__ +#define __DT_BINDINGS_PINCTRL_ROCKCHIP_H__ + +#define RK_GPIO0 0 +#define RK_GPIO1 1 +#define RK_GPIO2 2 +#define RK_GPIO3 3 +#define RK_GPIO4 4 + +#define RK_PA0 0 +#define RK_PA1 1 +#define RK_PA2 2 +#define RK_PA3 3 +#define RK_PA4 4 +#define RK_PA5 5 +#define RK_PA6 6 +#define RK_PA7 7 +#define RK_PB0 8 +#define RK_PB1 9 +#define RK_PB2 10 +#define RK_PB3 11 +#define RK_PB4 12 +#define RK_PB5 13 +#define RK_PB6 14 +#define RK_PB7 15 +#define RK_PC0 16 +#define RK_PC1 17 +#define RK_PC2 18 +#define RK_PC3 19 +#define RK_PC4 20 +#define RK_PC5 21 +#define RK_PC6 22 +#define RK_PC7 23 +#define RK_PD0 24 +#define RK_PD1 25 +#define RK_PD2 26 +#define RK_PD3 27 +#define RK_PD4 28 +#define RK_PD5 29 +#define RK_PD6 30 +#define RK_PD7 31 + +#define RK_FUNC_GPIO 0 +#define RK_FUNC_0 0 +#define RK_FUNC_1 1 +#define RK_FUNC_2 2 +#define RK_FUNC_3 3 +#define RK_FUNC_4 4 +#define RK_FUNC_5 5 +#define RK_FUNC_6 6 +#define RK_FUNC_7 7 +#define RK_FUNC_8 8 +#define RK_FUNC_9 9 +#define RK_FUNC_10 10 +#define RK_FUNC_11 11 +#define RK_FUNC_12 12 +#define RK_FUNC_13 13 +#define RK_FUNC_14 14 +#define RK_FUNC_15 15 + +#define RK_GPIO0_A0 0 +#define RK_GPIO0_A1 1 +#define RK_GPIO0_A2 2 +#define RK_GPIO0_A3 3 +#define RK_GPIO0_A4 4 +#define RK_GPIO0_A5 5 +#define RK_GPIO0_A6 6 +#define RK_GPIO0_A7 7 +#define RK_GPIO0_B0 8 +#define RK_GPIO0_B1 9 +#define RK_GPIO0_B2 10 +#define RK_GPIO0_B3 11 +#define RK_GPIO0_B4 12 +#define RK_GPIO0_B5 13 +#define RK_GPIO0_B6 14 +#define RK_GPIO0_B7 15 +#define RK_GPIO0_C0 16 +#define RK_GPIO0_C1 17 +#define RK_GPIO0_C2 18 +#define RK_GPIO0_C3 19 +#define RK_GPIO0_C4 20 +#define RK_GPIO0_C5 21 +#define RK_GPIO0_C6 22 +#define RK_GPIO0_C7 23 +#define RK_GPIO0_D0 24 +#define RK_GPIO0_D1 25 +#define RK_GPIO0_D2 26 +#define RK_GPIO0_D3 27 +#define RK_GPIO0_D4 28 +#define RK_GPIO0_D5 29 +#define RK_GPIO0_D6 30 +#define RK_GPIO0_D7 31 + +#define RK_GPIO1_A0 32 +#define RK_GPIO1_A1 33 +#define RK_GPIO1_A2 34 +#define RK_GPIO1_A3 35 +#define RK_GPIO1_A4 36 +#define RK_GPIO1_A5 37 +#define RK_GPIO1_A6 38 +#define RK_GPIO1_A7 39 +#define RK_GPIO1_B0 40 +#define RK_GPIO1_B1 41 +#define RK_GPIO1_B2 42 +#define RK_GPIO1_B3 43 +#define RK_GPIO1_B4 44 +#define RK_GPIO1_B5 45 +#define RK_GPIO1_B6 46 +#define RK_GPIO1_B7 47 +#define RK_GPIO1_C0 48 +#define RK_GPIO1_C1 49 +#define RK_GPIO1_C2 50 +#define RK_GPIO1_C3 51 +#define RK_GPIO1_C4 52 +#define RK_GPIO1_C5 53 +#define RK_GPIO1_C6 54 +#define RK_GPIO1_C7 55 +#define RK_GPIO1_D0 56 +#define RK_GPIO1_D1 57 +#define RK_GPIO1_D2 58 +#define RK_GPIO1_D3 59 +#define RK_GPIO1_D4 60 +#define RK_GPIO1_D5 61 +#define RK_GPIO1_D6 62 +#define RK_GPIO1_D7 63 + +#define RK_GPIO2_A0 64 +#define RK_GPIO2_A1 65 +#define RK_GPIO2_A2 66 +#define RK_GPIO2_A3 67 +#define RK_GPIO2_A4 68 +#define RK_GPIO2_A5 69 +#define RK_GPIO2_A6 70 +#define RK_GPIO2_A7 71 +#define RK_GPIO2_B0 72 +#define RK_GPIO2_B1 73 +#define RK_GPIO2_B2 74 +#define RK_GPIO2_B3 75 +#define RK_GPIO2_B4 76 +#define RK_GPIO2_B5 77 +#define RK_GPIO2_B6 78 +#define RK_GPIO2_B7 79 +#define RK_GPIO2_C0 80 +#define RK_GPIO2_C1 81 +#define RK_GPIO2_C2 82 +#define RK_GPIO2_C3 83 +#define RK_GPIO2_C4 84 +#define RK_GPIO2_C5 85 +#define RK_GPIO2_C6 86 +#define RK_GPIO2_C7 87 +#define RK_GPIO2_D0 88 +#define RK_GPIO2_D1 89 +#define RK_GPIO2_D2 90 +#define RK_GPIO2_D3 91 +#define RK_GPIO2_D4 92 +#define RK_GPIO2_D5 93 +#define RK_GPIO2_D6 94 +#define RK_GPIO2_D7 95 + +#define RK_GPIO3_A0 96 +#define RK_GPIO3_A1 97 +#define RK_GPIO3_A2 98 +#define RK_GPIO3_A3 99 +#define RK_GPIO3_A4 100 +#define RK_GPIO3_A5 101 +#define RK_GPIO3_A6 102 +#define RK_GPIO3_A7 103 +#define RK_GPIO3_B0 104 +#define RK_GPIO3_B1 105 +#define RK_GPIO3_B2 106 +#define RK_GPIO3_B3 107 +#define RK_GPIO3_B4 108 +#define RK_GPIO3_B5 109 +#define RK_GPIO3_B6 110 +#define RK_GPIO3_B7 111 +#define RK_GPIO3_C0 112 +#define RK_GPIO3_C1 113 +#define RK_GPIO3_C2 114 +#define RK_GPIO3_C3 115 +#define RK_GPIO3_C4 116 +#define RK_GPIO3_C5 117 +#define RK_GPIO3_C6 118 +#define RK_GPIO3_C7 119 +#define RK_GPIO3_D0 120 +#define RK_GPIO3_D1 121 +#define RK_GPIO3_D2 122 +#define RK_GPIO3_D3 123 +#define RK_GPIO3_D4 124 +#define RK_GPIO3_D5 125 +#define RK_GPIO3_D6 126 +#define RK_GPIO3_D7 127 + +#define RK_GPIO4_A0 128 +#define RK_GPIO4_A1 129 +#define RK_GPIO4_A2 130 +#define RK_GPIO4_A3 131 +#define RK_GPIO4_A4 132 +#define RK_GPIO4_A5 133 +#define RK_GPIO4_A6 134 +#define RK_GPIO4_A7 135 +#define RK_GPIO4_B0 136 +#define RK_GPIO4_B1 137 +#define RK_GPIO4_B2 138 +#define RK_GPIO4_B3 139 +#define RK_GPIO4_B4 140 +#define RK_GPIO4_B5 141 +#define RK_GPIO4_B6 142 +#define RK_GPIO4_B7 143 +#define RK_GPIO4_C0 144 +#define RK_GPIO4_C1 145 +#define RK_GPIO4_C2 146 +#define RK_GPIO4_C3 147 +#define RK_GPIO4_C4 148 +#define RK_GPIO4_C5 149 +#define RK_GPIO4_C6 150 +#define RK_GPIO4_C7 151 +#define RK_GPIO4_D0 152 +#define RK_GPIO4_D1 153 +#define RK_GPIO4_D2 154 +#define RK_GPIO4_D3 155 +#define RK_GPIO4_D4 156 +#define RK_GPIO4_D5 157 +#define RK_GPIO4_D6 158 +#define RK_GPIO4_D7 159 + +#endif /* __DT_BINDINGS_PINCTRL_ROCKCHIP_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index c5f8f8c1448a..d64b09c31c2f 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -174,12 +174,20 @@ extern "C" { #include "drivers/clk.h" #endif +#ifdef RT_USING_HWSPINLOCK +#include "drivers/hwspinlock.h" +#endif + #ifdef RT_USING_FIRMWARE #ifdef RT_FIRMWARE_PSCI #include "drivers/psci.h" #endif #endif /* RT_USING_FIRMWARE */ +#ifdef RT_USING_MBOX +#include "drivers/mailbox.h" +#endif + #ifdef RT_USING_OFW #include "drivers/ofw.h" #include "drivers/ofw_fdt.h" @@ -192,6 +200,25 @@ extern "C" { #include "drivers/pic.h" #endif +#ifdef RT_USING_PCI +#include "drivers/pci.h" +#ifdef RT_PCI_MSI +#include "drivers/pci_msi.h" +#endif +#endif + +#ifdef RT_USING_REGULATOR +#include "drivers/regulator.h" +#endif + +#ifdef RT_USING_RESET +#include "drivers/reset.h" +#endif + +#ifdef RT_MFD_SYSCON +#include "drivers/syscon.h" +#endif + #ifdef RT_USING_VIRTIO #include "drivers/virtio.h" #include "drivers/virtq.h" diff --git a/components/drivers/mailbox/Kconfig b/components/drivers/mailbox/Kconfig new file mode 100644 index 000000000000..47dbeec06b68 --- /dev/null +++ b/components/drivers/mailbox/Kconfig @@ -0,0 +1,15 @@ +menuconfig RT_USING_MBOX + bool "Using Hardware Mailbox drivers" + depends on RT_USING_DM + select RT_USING_OFW + default n + +config RT_MBOX_BCM2835 + bool "BCM2835 Mailbox" + depends on RT_USING_MBOX + default n + +config RT_MBOX_ROCKCHIP + bool "Rockchip Soc Integrated Mailbox Support" + depends on RT_USING_MBOX + default n diff --git a/components/drivers/mailbox/SConscript b/components/drivers/mailbox/SConscript new file mode 100755 index 000000000000..89ddb7d511ff --- /dev/null +++ b/components/drivers/mailbox/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_MBOX']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['mailbox.c'] + +if GetDepend(['RT_MBOX_BCM2835']): + src += ['mailbox-bcm2835.c'] + +if GetDepend(['RT_MBOX_ROCKCHIP']): + src += ['mailbox-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/mailbox/mailbox-bcm2835.c b/components/drivers/mailbox/mailbox-bcm2835.c new file mode 100644 index 000000000000..f64d7877f7d2 --- /dev/null +++ b/components/drivers/mailbox/mailbox-bcm2835.c @@ -0,0 +1,189 @@ +/* + * 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 + +/* 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_free(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_uint32_t msg = *(rt_uint32_t *)data; + struct bcm2835_mbox *bcm_mbox = raw_to_bcm2835_mbox(chan->ctrl); + + rt_spin_lock(&bcm_mbox->lock); + + bcm2835_mbox_writel(bcm_mbox, MAIL1_WRT, msg); + + rt_spin_unlock(&bcm_mbox->lock); + + return RT_EOK; +} + +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, + .free = bcm2835_mbox_free, + .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; + } + + 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: + return err; +} + +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, +}; + +static int bcm2835_mbox_drv_register(void) +{ + rt_platform_driver_register(&bcm2835_mbox_driver); + + return 0; +} +INIT_FRAMEWORK_EXPORT(bcm2835_mbox_drv_register); diff --git a/components/drivers/mailbox/mailbox-rockchip.c b/components/drivers/mailbox/mailbox-rockchip.c new file mode 100644 index 000000000000..1eda5db0c6b8 --- /dev/null +++ b/components/drivers/mailbox/mailbox-rockchip.c @@ -0,0 +1,313 @@ +/* + * 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 + +#define DBG_TAG "mailbox.rockchip" +#define DBG_LVL DBG_INFO +#include + +#define MAILBOX_A2B_INTEN 0x00 +#define MAILBOX_A2B_STATUS 0x04 +#define MAILBOX_A2B_CMD(x) (0x08 + (x) * 8) +#define MAILBOX_A2B_DAT(x) (0x0c + (x) * 8) + +#define MAILBOX_B2A_INTEN 0x28 +#define MAILBOX_B2A_STATUS 0x2c +#define MAILBOX_B2A_CMD(x) (0x30 + (x) * 8) +#define MAILBOX_B2A_DAT(x) (0x34 + (x) * 8) + +struct rockchip_mbox_msg +{ + rt_uint32_t cmd; + int rx_size; +}; + +struct rockchip_mbox_soc_data +{ + int num_chans; +}; + +struct rockchip_mbox_chan +{ + int idx; + int irq; + struct rockchip_mbox_msg *msg; + struct rockchip_mbox *rk_mbox; +}; + +struct rockchip_mbox +{ + struct rt_mbox_controller parent; + + void *regs; + struct rt_clk *pclk; + struct rt_thread *irq_thread; + + rt_uint32_t buf_size; + struct rockchip_mbox_chan chans[]; +}; + +#define raw_to_rockchip_mbox(raw) rt_container_of(raw, struct rockchip_mbox, parent) + +rt_inline rt_uint32_t rockchip_mbox_readl(struct rockchip_mbox *rk_mbox, int offset) +{ + return HWREG32(rk_mbox->regs + offset); +} + +rt_inline void rockchip_mbox_writel(struct rockchip_mbox *rk_mbox, int offset, + rt_uint32_t value) +{ + HWREG32(rk_mbox->regs + offset) = value; +} + +static rt_err_t rockchip_mbox_request(struct rt_mbox_chan *chan) +{ + struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl); + + /* Enable all B2A interrupts */ + rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, + (1 << rk_mbox->parent.num_chans) - 1); + + return RT_EOK; +} + +static void rockchip_mbox_free(struct rt_mbox_chan *chan) +{ + int index; + struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl); + + /* Disable all B2A interrupts */ + rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, 0); + + index = chan - rk_mbox->parent.chans; + rk_mbox->chans[index].msg = RT_NULL; +} + +static rt_err_t rockchip_mbox_send(struct rt_mbox_chan *chan, const void *data) +{ + int index; + struct rockchip_mbox_msg *msg = (void *)data; + struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl); + + if (msg->rx_size > rk_mbox->buf_size) + { + LOG_E("Transmit size over buf size(%d)", rk_mbox->buf_size); + + return -RT_EINVAL; + } + + index = chan - rk_mbox->parent.chans; + rk_mbox->chans[index].msg = msg; + + rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_CMD(index), msg->cmd); + rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_DAT(index), msg->rx_size); + + return RT_EOK; +} + +static const struct rt_mbox_controller_ops rk_mbox_ops = +{ + .request = rockchip_mbox_request, + .free = rockchip_mbox_free, + .send = rockchip_mbox_send, +}; + +static void rockchip_mbox_thread_isr(void *param) +{ + struct rockchip_mbox_msg *msg; + struct rockchip_mbox *rk_mbox = param; + + while (RT_TRUE) + { + rt_thread_suspend(rk_mbox->irq_thread); + rt_schedule(); + + for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx) + { + msg = rk_mbox->chans[idx].msg; + + if (!msg) + { + LOG_E("Chan[%d]: B2A message is NULL", idx); + + break; + } + + rt_mbox_recv(&rk_mbox->parent.chans[idx], msg); + rk_mbox->chans[idx].msg = RT_NULL; + } + } +} + +static void rockchip_mbox_isr(int irqno, void *param) +{ + rt_uint32_t status; + struct rockchip_mbox *rk_mbox = param; + + status = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_STATUS); + + for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx) + { + if ((status & RT_BIT(idx)) && (irqno == rk_mbox->chans[idx].irq)) + { + /* Clear mbox interrupt */ + rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_STATUS, RT_BIT(idx)); + + rt_thread_resume(rk_mbox->irq_thread); + + return; + } + } + + return; +} + +static rt_err_t rockchip_mbox_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + char chan_name[RT_NAME_MAX]; + rt_uint64_t io_addr, io_size; + struct rockchip_mbox *rk_mbox; + struct rockchip_mbox_chan *chan; + struct rt_device *dev = &pdev->parent; + const struct rockchip_mbox_soc_data *soc_data = pdev->id->data; + + rk_mbox = rt_calloc(1, sizeof(*rk_mbox) + + soc_data->num_chans * sizeof(struct rockchip_mbox_chan)); + + if (!rk_mbox) + { + return -RT_ENOMEM; + } + + if ((err = rt_dm_dev_get_address(dev, 0, &io_addr, &io_size))) + { + goto _fail; + } + + rk_mbox->regs = rt_ioremap((void *)io_addr, (size_t)io_size); + + if (!rk_mbox->regs) + { + err = -RT_EIO; + goto _fail; + } + + rk_mbox->pclk = rt_clk_get_by_name(dev, "pclk_mailbox"); + + if (!rk_mbox->pclk) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rk_mbox->pclk))) + { + goto _fail; + } + + rk_mbox->irq_thread = rt_thread_create("rk_mbox", &rockchip_mbox_thread_isr, + rk_mbox, SYSTEM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!rk_mbox->irq_thread) + { + LOG_E("Create Mailbox IRQ thread fail"); + goto _fail; + } + + rt_thread_startup(rk_mbox->irq_thread); + + chan = &rk_mbox->chans[0]; + + for (int i = 0; i < soc_data->num_chans; ++i, ++chan) + { + int irq = rt_dm_dev_get_irq(dev, i); + + if (irq < 0) + { + err = irq; + + goto _fail; + } + + rt_snprintf(chan_name, sizeof(chan_name), "rk_mbox-%d", i); + + rt_hw_interrupt_install(irq, rockchip_mbox_isr, rk_mbox, chan_name); + rt_hw_interrupt_umask(irq); + + chan->idx = i; + chan->irq = irq; + chan->rk_mbox = rk_mbox; + } + + rk_mbox->buf_size = io_size / (soc_data->num_chans * 2); + + rk_mbox->parent.dev = dev; + rk_mbox->parent.num_chans = soc_data->num_chans; + rk_mbox->parent.ops = &rk_mbox_ops; + + if ((err = rt_mbox_controller_register(&rk_mbox->parent))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rk_mbox->regs) + { + rt_iounmap(rk_mbox->regs); + } + + if (rk_mbox->pclk) + { + rt_clk_disable_unprepare(rk_mbox->pclk); + rt_clk_put(rk_mbox->pclk); + } + + if (rk_mbox->irq_thread) + { + rt_thread_delete(rk_mbox->irq_thread); + } + + rt_free(rk_mbox); + + return err; +} + +static const struct rockchip_mbox_soc_data rk3368_data = +{ + .num_chans = 4, +}; + +static const struct rt_ofw_node_id rockchip_mbox_ofw_ids[] = +{ + { .compatible = "rockchip,rk3368-mailbox", .data = &rk3368_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_mbox_driver = +{ + .name = "mailbox-rockchip", + .ids = rockchip_mbox_ofw_ids, + + .probe = rockchip_mbox_probe, +}; + +static int rockchip_mbox_drv_register(void) +{ + rt_platform_driver_register(&rockchip_mbox_driver); + + return 0; +} +INIT_FRAMEWORK_EXPORT(rockchip_mbox_drv_register); diff --git a/components/drivers/mailbox/mailbox.c b/components/drivers/mailbox/mailbox.c new file mode 100644 index 000000000000..231f846a1002 --- /dev/null +++ b/components/drivers/mailbox/mailbox.c @@ -0,0 +1,336 @@ +/* + * 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 + +#define DBG_TAG "rtdm.mailbox" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +static struct rt_spinlock mbox_ops_lock = {}; +static rt_list_t mbox_nodes = RT_LIST_OBJECT_INIT(mbox_nodes); + +static void mbox_chan_timeout(void *param); + +rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl) +{ + int len; + struct rt_mbox_chan *chan; + char timer_name[RT_NAME_MAX]; + + if (!ctrl || !ctrl->dev || !ctrl->ops || !ctrl->num_chans) + { + return -RT_EINVAL; + } + + ctrl->chans = rt_calloc(ctrl->num_chans, sizeof(struct rt_mbox_chan)); + + if (!ctrl->chans) + { + return -RT_ENOMEM; + } + + len = rt_snprintf(timer_name, sizeof(timer_name), "%s-", + rt_dm_dev_get_name(ctrl->dev)); + + RT_ASSERT(len < sizeof(timer_name)); + + chan = &ctrl->chans[0]; + + for (int i = 0; i < ctrl->num_chans; ++i, ++chan) + { + chan->ctrl = ctrl; + rt_spin_lock_init(&chan->lock); + + rt_snprintf(&timer_name[len], sizeof(timer_name) - len, "%d", i); + rt_timer_init(&chan->timer, timer_name, mbox_chan_timeout, chan, + 0, RT_TIMER_FLAG_PERIODIC); + } + + rt_list_init(&ctrl->list); + rt_dm_dev_bind_fwdata(ctrl->dev, RT_NULL, ctrl); + + rt_spin_lock(&mbox_ops_lock); + + rt_list_insert_after(&mbox_nodes, &ctrl->list); + + rt_spin_unlock(&mbox_ops_lock); + + return RT_EOK; +} + +rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl) +{ + struct rt_mbox_chan *chan; + + if (!ctrl) + { + return -RT_EINVAL; + } + + rt_spin_lock(&mbox_ops_lock); + + rt_dm_dev_unbind_fwdata(ctrl->dev, RT_NULL); + rt_list_remove(&ctrl->list); + + rt_spin_unlock(&mbox_ops_lock); + + chan = &ctrl->chans[0]; + + for (int i = ctrl->num_chans - 1; i >= 0; --i, ++chan) + { + rt_mbox_free(&ctrl->chans[i]); + } + + rt_free(ctrl->chans); + + return RT_EOK; +} + +rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data, + rt_uint32_t timeout_ms) +{ + rt_err_t err; + rt_ubase_t level; + rt_bool_t timer_go = RT_FALSE; + struct rt_mbox_client *client; + struct rt_mbox_controller *ctrl; + + if (!chan || !data) + { + return -RT_EINVAL; + } + + ctrl = chan->ctrl; + client = chan->client; + + level = rt_spin_lock_irqsave(&chan->lock); + + if (client->tx_prepare) + { + client->tx_prepare(client, data); + } + + chan->complete = RT_FALSE; + err = ctrl->ops->send(chan, data); + + if (!err) + { + chan->data = (void *)data; + + if (timeout_ms != RT_WAITING_FOREVER) + { + rt_tick_t tick = rt_tick_from_millisecond(timeout_ms); + + rt_timer_control(&chan->timer, RT_TIMER_CTRL_SET_TIME, &tick); + + timer_go = RT_TRUE; + } + } + else + { + chan->complete = RT_TRUE; + } + + rt_spin_unlock_irqrestore(&chan->lock, level); + + if (timer_go) + { + rt_timer_start(&chan->timer); + } + + return err; +} + +void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err) +{ + void *data; + rt_ubase_t level; + + level = rt_spin_lock_irqsave(&chan->lock); + + data = chan->data; + chan->data = RT_NULL; + + rt_spin_unlock_irqrestore(&chan->lock, level); + + if (chan->client->tx_done) + { + chan->client->tx_done(chan->client, data, err); + } + + chan->complete = RT_TRUE; +} + +static void mbox_chan_timeout(void *param) +{ + rt_err_t err = RT_EOK; + struct rt_mbox_chan *chan = param; + + rt_timer_stop(&chan->timer); + + if (!chan->complete) + { + err = -RT_ETIMEOUT; + } + + rt_mbox_send_done(chan, err); +} + +rt_err_t rt_mbox_peek(struct rt_mbox_chan *chan) +{ + if (!chan) + { + return -RT_EINVAL; + } + + if (chan->ctrl->ops->peek) + { + return chan->ctrl->ops->peek(chan); + } + + return -RT_ENOSYS; +} + +rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data) +{ + if (!chan || !data) + { + return -RT_EINVAL; + } + + if (chan->client->rx_callback) + { + chan->client->rx_callback(chan->client, data); + } + + return RT_EOK; +} + +static int mbox_controller_ofw_parse_default(struct rt_mbox_controller *ctrl, + struct rt_ofw_cell_args *args) +{ + if (args->args_count != 1) + { + return -RT_EINVAL; + } + + return args->args[0]; +} + +struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index) +{ + rt_err_t err; + struct rt_ofw_node *np; + struct rt_ofw_cell_args args; + struct rt_mbox_controller *ctrl; + struct rt_mbox_chan *chan = RT_NULL; + + if (!client && index < 0) + { + return RT_NULL; + } + + np = client->dev->ofw_node; + + rt_spin_lock(&mbox_ops_lock); + + err = rt_ofw_parse_phandle_cells(np, "mboxes", "#mbox-cells", index, &args); + + if (err) + { + goto _out_lock; + } + + ctrl = rt_ofw_data(args.data); + rt_ofw_node_put(args.data); + + if (ctrl) + { + int index; + + if (ctrl->ops->ofw_parse) + { + index = ctrl->ops->ofw_parse(ctrl, &args); + } + else + { + index = mbox_controller_ofw_parse_default(ctrl, &args); + } + + if (index >= 0) + { + chan = &ctrl->chans[index]; + } + else + { + LOG_E("Parse chan from %s error = %s", + rt_dm_dev_get_name(ctrl->dev), rt_strerror(index)); + + goto _out_lock; + } + + if (ctrl->ops->request) + { + rt_err_t err = ctrl->ops->request(chan); + + if (err) + { + LOG_E("Request chan[%d] from %s error = %s", + index, rt_dm_dev_get_name(ctrl->dev), rt_strerror(err)); + } + } + } + +_out_lock: + rt_spin_unlock(&mbox_ops_lock); + + return chan; +} + +struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name) +{ + int index; + struct rt_ofw_node *np; + + if (!client || !name) + { + return RT_NULL; + } + + np = client->dev->ofw_node; + index = rt_ofw_prop_index_of_string(np, "mbox-names", name); + + if (index < 0) + { + return RT_NULL; + } + + return rt_mbox_request_by_index(client, index); +} + +rt_err_t rt_mbox_free(struct rt_mbox_chan *chan) +{ + if (chan) + { + chan->ctrl->ops->free(chan); + } + else + { + return -RT_EINVAL; + } + + return RT_EOK; +} diff --git a/components/drivers/mfd/Kconfig b/components/drivers/mfd/Kconfig index dbd72a98cc0e..efa0106d2db8 100644 --- a/components/drivers/mfd/Kconfig +++ b/components/drivers/mfd/Kconfig @@ -1,9 +1,33 @@ menuconfig RT_USING_MFD - bool "Using Multifunction Device Drivers" + bool "Using Multifunction device drivers" depends on RT_USING_DM default n config RT_MFD_SYSCON bool "System Controller Register R/W" depends on RT_USING_MFD + select RT_USING_OFW default y + +config RT_MFD_RK8XX + bool + depends on RT_USING_MFD + default n + +config RT_MFD_RK8XX_I2C + bool "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip" + depends on RT_USING_MFD + select RT_MFD_RK8XX + select RT_USING_OFW + select RT_USING_I2C + select RT_MFD_SYSCON + default n + +config RT_MFD_RK8XX_SPI + bool "Rockchip RK806 Power Management Chip" + depends on RT_USING_MFD + select RT_MFD_RK8XX + select RT_USING_OFW + select RT_USING_SPI + select RT_MFD_SYSCON + default n diff --git a/components/drivers/mfd/SConscript b/components/drivers/mfd/SConscript index e9206158a646..ddef18cc464e 100755 --- a/components/drivers/mfd/SConscript +++ b/components/drivers/mfd/SConscript @@ -7,10 +7,17 @@ if not GetDepend(['RT_USING_MFD']): cwd = GetCurrentDir() CPPPATH = [cwd + '/../include'] +src = [] if GetDepend(['RT_MFD_SYSCON']): src += ['mfd-syscon.c'] +if GetDepend(['RT_MFD_RK8XX_I2C']): + src += ['rk8xx-i2c.c'] + +if GetDepend(['RT_MFD_RK8XX_SPI']): + src += ['rk8xx-spi.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/mfd/mfd-syscon.c b/components/drivers/mfd/mfd-syscon.c index f4894b321e82..e059094f9c41 100644 --- a/components/drivers/mfd/mfd-syscon.c +++ b/components/drivers/mfd/mfd-syscon.c @@ -15,6 +15,7 @@ #include #include #include +#include static struct rt_spinlock _syscon_nodes_lock = { 0 }; static rt_list_t _syscon_nodes = RT_LIST_OBJECT_INIT(_syscon_nodes); @@ -28,6 +29,8 @@ rt_err_t rt_syscon_read(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t * *out_val = HWREG32(syscon->iomem_base + offset); rt_spin_unlock_irqrestore(&syscon->rw_lock, level); + + return RT_EOK; } else { @@ -44,6 +47,8 @@ rt_err_t rt_syscon_write(struct rt_syscon *syscon, rt_off_t offset, rt_uint32_t HWREG32(syscon->iomem_base + offset) = val; rt_spin_unlock_irqrestore(&syscon->rw_lock, level); + + return RT_EOK; } else { @@ -76,10 +81,20 @@ rt_err_t rt_syscon_update_bits(struct rt_syscon *syscon, rt_off_t offset, rt_uin return err; } +static rt_err_t syscon_probe(struct rt_platform_device *pdev); + struct rt_syscon *rt_syscon_find_by_ofw_node(struct rt_ofw_node *np) { - struct rt_syscon *syscon; - rt_ubase_t level = rt_spin_lock_irqsave(&_syscon_nodes_lock); + rt_ubase_t level; + struct rt_syscon *syscon = RT_NULL; + struct rt_platform_device syscon_pdev; + + if (!np) + { + goto _exit; + } + + level = rt_spin_lock_irqsave(&_syscon_nodes_lock); /* ofw_data is not safety */ rt_list_for_each_entry(syscon, &_syscon_nodes, list) @@ -92,10 +107,30 @@ struct rt_syscon *rt_syscon_find_by_ofw_node(struct rt_ofw_node *np) rt_spin_unlock_irqrestore(&_syscon_nodes_lock, level); + if (syscon) + { + goto _exit; + } + + /* Not found, try probe this node */ + if (!rt_ofw_node_is_compatible(np, "syscon") && + !rt_ofw_node_is_compatible(np, "simple-mfd")) + { + goto _exit; + } + + syscon_pdev.parent.ofw_node = np; + + if (!syscon_probe(&syscon_pdev)) + { + syscon = rt_ofw_data(np); + } + +_exit: return syscon; } -struct rt_syscon *rt_syscon_find_by_compatible(const char *compatible) +struct rt_syscon *rt_syscon_find_by_ofw_compatible(const char *compatible) { struct rt_syscon *syscon; struct rt_ofw_node *syscon_np = rt_ofw_find_node_by_compatible(RT_NULL, compatible); @@ -110,7 +145,7 @@ struct rt_syscon *rt_syscon_find_by_compatible(const char *compatible) return syscon; } -struct rt_syscon *rt_syscon_find_by_phandle(struct rt_ofw_node *np, const char *propname) +struct rt_syscon *rt_syscon_find_by_ofw_phandle(struct rt_ofw_node *np, const char *propname) { struct rt_syscon *syscon; struct rt_ofw_node *syscon_np = rt_ofw_parse_phandle(np, propname, 0); @@ -130,7 +165,7 @@ static rt_err_t syscon_probe(struct rt_platform_device *pdev) rt_err_t err; struct rt_ofw_node *np; rt_uint64_t iomem_range[2]; - struct syscon *syscon = rt_malloc(sizeof(*syscon)); + struct rt_syscon *syscon = rt_calloc(1, sizeof(*syscon)); if (!syscon) { @@ -152,6 +187,9 @@ static rt_err_t syscon_probe(struct rt_platform_device *pdev) goto _fail; } + rt_list_init(&syscon->list); + rt_list_insert_after(&_syscon_nodes, &syscon->list); + rt_spin_lock_init(&syscon->rw_lock); syscon->np = pdev->parent.ofw_node; @@ -185,4 +223,4 @@ static int syscon_drv_register(void) return 0; } -INIT_SUBSYS_EXPORT(syscon_drv_register); +INIT_FRAMEWORK_EXPORT(syscon_drv_register); diff --git a/components/drivers/mfd/rk8xx-i2c.c b/components/drivers/mfd/rk8xx-i2c.c new file mode 100644 index 000000000000..086510e3092b --- /dev/null +++ b/components/drivers/mfd/rk8xx-i2c.c @@ -0,0 +1,229 @@ +/* + * 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 "mfd.rk8xx-i2c" +#define DBG_LVL DBG_INFO +#include + +#include "rk8xx.h" + +struct rk8xx_i2c_soc_data +{ + int variant; +}; + +static rt_uint32_t rk8xx_i2c_read(struct rk8xx *rk8xx, rt_uint16_t reg) +{ + rt_uint8_t data = 0; + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg[2]; + struct rt_i2c_client *client = rk8xx_to_i2c_client(rk8xx); + + send_buf[0] = (reg & 0xff); + + msg[0].addr = client->client_addr; + msg[0].flags = RT_I2C_WR; + msg[0].len = 1; + msg[0].buf = send_buf; + + msg[1].addr = client->client_addr; + msg[1].flags = RT_I2C_RD; + msg[1].len = 1; + msg[1].buf = &data; + + if (rt_i2c_transfer(client->bus, msg, 2) == 2) + { + return data; + } + else + { + return (rt_uint32_t)-RT_ERROR; + } +} + +static rt_err_t rk8xx_i2c_write(struct rk8xx *rk8xx, rt_uint16_t reg, + rt_uint8_t data) +{ + rt_uint8_t send_buf[2]; + struct rt_i2c_msg msg; + struct rt_i2c_client *client = rk8xx_to_i2c_client(rk8xx); + + send_buf[0] = reg & 0xff; + send_buf[1] = data; + + msg.addr = client->client_addr; + msg.flags = RT_I2C_WR; + msg.len = 2; + msg.buf = send_buf; + + if (rt_i2c_transfer(client->bus, &msg, 1) == 1) + { + return RT_EOK; + } + else + { + return -RT_ERROR; + } +} + +static rt_err_t rk8xx_i2c_update_bits(struct rk8xx *rk8xx, rt_uint16_t reg, + rt_uint8_t mask, rt_uint8_t data) +{ + rt_uint32_t old, tmp; + + old = rk8xx_i2c_read(rk8xx, reg); + + if (old < 0) + { + return old; + } + + tmp = old & ~mask; + tmp |= (data & mask); + + return rk8xx_i2c_write(rk8xx, reg, tmp); +} + +static rt_err_t create_rk8xx_i2c_platform_device(rt_bus_t platform_bus, + struct rt_i2c_client *client, + const struct rk8xx_i2c_soc_data *soc_data, + const char *name, + int irq, + void *priv) +{ + rt_err_t err; + struct rk8xx *rk8xx; + struct rt_platform_device *pdev = rt_platform_device_alloc(name); + + if (!pdev) + { + return -RT_ENOMEM; + } + + rk8xx = rt_malloc(sizeof(*rk8xx)); + + if (!rk8xx) + { + rt_free(pdev); + + return -RT_ENOMEM; + } + + rk8xx->variant = soc_data->variant; + rk8xx->irq = irq; + rk8xx->dev = &client->parent; + rk8xx->read = rk8xx_i2c_read; + rk8xx->write = rk8xx_i2c_write; + rk8xx->update_bits = rk8xx_i2c_update_bits; + rk8xx->priv = priv; + + pdev->priv = rk8xx; + + err = rt_bus_add_device(platform_bus, &pdev->parent); + + if (err && err != -RT_ENOSYS) + { + LOG_E("Add RK8XX - %s error = %s", name, rt_strerror(err)); + } + + return err; +} + +static rt_err_t rk8xx_i2c_probe(struct rt_i2c_client *client) +{ + int irq; + rt_err_t err; + struct rt_device *dev; + struct rt_ofw_node *np, *client_np; + const struct rk8xx_i2c_soc_data *soc_data; + rt_bus_t platform_bus = rt_bus_find_by_name("platform"); + + if (!platform_bus) + { + return -RT_EIO; + } + + irq = rt_dm_dev_get_irq(&client->parent, 0); + + if (irq < 0) + { + return irq; + } + + dev = &client->parent; + client_np = dev->ofw_node; + soc_data = client->ofw_id->data; + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + create_rk8xx_i2c_platform_device(platform_bus, client, soc_data, + "rk8xx-rtc", irq, RT_NULL); + + if ((np = rt_ofw_get_child_by_tag(client_np, "regulators"))) + { + rt_ofw_node_put(np); + + err = create_rk8xx_i2c_platform_device(platform_bus, client, soc_data, + "rk8xx-regulator", irq, np); + + if (err == -RT_ENOMEM) + { + return err; + } + } + + return RT_EOK; +} + +static const struct rk8xx_i2c_soc_data rk805_data = +{ + .variant = RK805_ID, +}; + +static const struct rk8xx_i2c_soc_data rk808_data = +{ + .variant = RK808_ID, +}; + +static const struct rk8xx_i2c_soc_data rk809_data = +{ + .variant = RK809_ID, +}; + +static const struct rk8xx_i2c_soc_data rk817_data = +{ + .variant = RK817_ID, +}; + +static const struct rk8xx_i2c_soc_data rk818_data = +{ + .variant = RK818_ID, +}; + +static const struct rt_ofw_node_id rk8xx_i2c_ofw_ids[] = +{ + { .compatible = "rockchip,rk805", .data = &rk805_data }, + { .compatible = "rockchip,rk808", .data = &rk808_data }, + { .compatible = "rockchip,rk809", .data = &rk809_data }, + { .compatible = "rockchip,rk817", .data = &rk817_data }, + { .compatible = "rockchip,rk818", .data = &rk818_data }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver rk8xx_i2c_driver = +{ + .ofw_ids = rk8xx_i2c_ofw_ids, + + .probe = rk8xx_i2c_probe, +}; +RT_I2C_DRIVER_EXPORT(rk8xx_i2c_driver); diff --git a/components/drivers/mfd/rk8xx-spi.c b/components/drivers/mfd/rk8xx-spi.c new file mode 100644 index 000000000000..b06e54a5ce46 --- /dev/null +++ b/components/drivers/mfd/rk8xx-spi.c @@ -0,0 +1,187 @@ +/* + * 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 "mfd.rk8xx-spi" +#define DBG_LVL DBG_INFO +#include + +#include "rk8xx.h" + +#define RK806_ADDR_SIZE 2 +#define RK806_CMD_WITH_SIZE(CMD, VALUE_BYTES) \ + (RK806_CMD_##CMD | RK806_CMD_CRC_DIS | (VALUE_BYTES - 1)) + +static rt_uint32_t rk8xx_spi_read(struct rk8xx *rk8xx, rt_uint16_t reg) +{ + rt_err_t err; + rt_uint32_t data = 0; + rt_uint8_t txbuf[3] = { 0 }; + struct rt_spi_device *spi_dev = rk8xx_to_spi_device(rk8xx); + + /* TX buffer contains command byte followed by two address bytes */ + txbuf[0] = RK806_CMD_WITH_SIZE(READ, sizeof(data)); + rt_memcpy(&txbuf[0], ®, sizeof(reg)); + + err = rt_spi_send_then_recv(spi_dev, txbuf, sizeof(txbuf), &data, sizeof(data)); + + if (!err) + { + return data; + } + else + { + return (rt_uint32_t)err; + } +} + +static rt_err_t rk8xx_spi_write(struct rk8xx *rk8xx, rt_uint16_t reg, + rt_uint8_t data) +{ + rt_uint8_t cmd; + struct rt_spi_message xfer[2] = { }; + struct rt_spi_device *spi_dev = rk8xx_to_spi_device(rk8xx); + + cmd = RK806_CMD_WITH_SIZE(WRITE, sizeof(data)); + + xfer[0].send_buf = &cmd; + xfer[0].length = sizeof(cmd); + xfer[1].send_buf = &data; + xfer[1].length = sizeof(data); + xfer[1].next = &xfer[0]; + + return rt_spi_transfer_message(spi_dev, xfer) ? RT_EOK : -RT_EIO; +} + +static rt_err_t rk8xx_spi_update_bits(struct rk8xx *rk8xx, rt_uint16_t reg, + rt_uint8_t mask, rt_uint8_t data) +{ + rt_uint32_t old, tmp; + + old = rk8xx_spi_read(rk8xx, reg); + + if (old < 0) + { + return old; + } + + tmp = old & ~mask; + tmp |= (data & mask); + + return rk8xx_spi_write(rk8xx, reg, tmp); +} + +static rt_err_t create_rk8xx_spi_platform_device(rt_bus_t platform_bus, + struct rt_spi_device *spi_dev, + const char *name, + int irq, + void *priv) +{ + rt_err_t err; + struct rk8xx *rk8xx; + struct rt_platform_device *pdev = rt_platform_device_alloc(name); + + if (!pdev) + { + return -RT_ENOMEM; + } + + rk8xx = rt_malloc(sizeof(*rk8xx)); + + if (!rk8xx) + { + rt_free(pdev); + + return -RT_ENOMEM; + } + + rk8xx->variant = RK806_ID; + rk8xx->irq = irq; + rk8xx->dev = &spi_dev->parent; + rk8xx->read = rk8xx_spi_read; + rk8xx->write = rk8xx_spi_write; + rk8xx->update_bits = rk8xx_spi_update_bits; + rk8xx->priv = priv; + + pdev->priv = rk8xx; + + err = rt_bus_add_device(platform_bus, &pdev->parent); + + if (err && err != -RT_ENOSYS) + { + LOG_E("Add RK8XX - %s error = %s", name, rt_strerror(err)); + } + + return err; +} + +static rt_err_t rk8xx_spi_probe(struct rt_spi_device *spi_dev) +{ + int irq; + rt_err_t err; + struct rt_device *dev; + struct rt_ofw_node *np, *spi_dev_np; + rt_bus_t platform_bus = rt_bus_find_by_name("platform"); + + if (!platform_bus) + { + return -RT_EIO; + } + + irq = rt_dm_dev_get_irq(&spi_dev->parent, 0); + + if (irq < 0) + { + return irq; + } + + dev = &spi_dev->parent; + spi_dev_np = dev->ofw_node; + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + if ((np = rt_ofw_get_child_by_tag(spi_dev_np, "regulators"))) + { + rt_ofw_node_put(np); + + err = create_rk8xx_spi_platform_device(platform_bus, spi_dev, + "rk8xx-regulator", irq, np); + + if (err == -RT_ENOMEM) + { + return err; + } + } + + return RT_EOK; +} + +static const struct rt_spi_device_id rk8xx_spi_ids[] = +{ + { .name = "rk806" }, + { /* sentinel */ }, +}; + +static const struct rt_ofw_node_id rk8xx_spi_ofw_ids[] = +{ + { .compatible = "rockchip,rk806" }, + { /* sentinel */ }, +}; + +static struct rt_spi_driver rk8xx_spi_driver = +{ + .ids = rk8xx_spi_ids, + .ofw_ids = rk8xx_spi_ofw_ids, + + .probe = rk8xx_spi_probe, +}; +RT_SPI_DRIVER_EXPORT(rk8xx_spi_driver); diff --git a/components/drivers/mfd/rk8xx.h b/components/drivers/mfd/rk8xx.h new file mode 100644 index 000000000000..5c0e8d288b24 --- /dev/null +++ b/components/drivers/mfd/rk8xx.h @@ -0,0 +1,557 @@ +/* + * 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 __RK8XX_H__ +#define __RK8XX_H__ + +#include +#include + +/* CONFIG REGISTER */ +#define RK805_VB_MON_REG 0x21 +#define RK805_THERMAL_REG 0x22 + +/* POWER CHANNELS ENABLE REGISTER */ +#define RK805_DCDC_EN_REG 0x23 +#define RK805_SLP_DCDC_EN_REG 0x25 +#define RK805_SLP_LDO_EN_REG 0x26 +#define RK805_LDO_EN_REG 0x27 + +/* BUCK AND LDO CONFIG REGISTER */ +#define RK805_BUCK_LDO_SLP_LP_EN_REG 0x2a +#define RK805_BUCK1_CONFIG_REG 0x2e +#define RK805_BUCK1_ON_VSEL_REG 0x2f +#define RK805_BUCK1_SLP_VSEL_REG 0x30 +#define RK805_BUCK2_CONFIG_REG 0x32 +#define RK805_BUCK2_ON_VSEL_REG 0x33 +#define RK805_BUCK2_SLP_VSEL_REG 0x34 +#define RK805_BUCK3_CONFIG_REG 0x36 +#define RK805_BUCK4_CONFIG_REG 0x37 +#define RK805_BUCK4_ON_VSEL_REG 0x38 +#define RK805_BUCK4_SLP_VSEL_REG 0x39 +#define RK805_LDO1_ON_VSEL_REG 0x3b +#define RK805_LDO1_SLP_VSEL_REG 0x3c +#define RK805_LDO2_ON_VSEL_REG 0x3d +#define RK805_LDO2_SLP_VSEL_REG 0x3e +#define RK805_LDO3_ON_VSEL_REG 0x3f +#define RK805_LDO3_SLP_VSEL_REG 0x40 + +#define RK806_POWER_EN0 0x0 +#define RK806_POWER_EN1 0x1 +#define RK806_POWER_EN2 0x2 +#define RK806_POWER_EN3 0x3 +#define RK806_POWER_EN4 0x4 +#define RK806_POWER_EN5 0x5 +#define RK806_POWER_SLP_EN0 0x6 +#define RK806_POWER_SLP_EN1 0x7 +#define RK806_POWER_SLP_EN2 0x8 +#define RK806_POWER_DISCHRG_EN0 0x9 +#define RK806_POWER_DISCHRG_EN1 0xa +#define RK806_POWER_DISCHRG_EN2 0xb +#define RK806_BUCK_FB_CONFIG 0xc +#define RK806_SLP_LP_CONFIG 0xd +#define RK806_POWER_FPWM_EN0 0xe +#define RK806_POWER_FPWM_EN1 0xf +#define RK806_BUCK1_CONFIG 0x10 +#define RK806_BUCK2_CONFIG 0x11 +#define RK806_BUCK3_CONFIG 0x12 +#define RK806_BUCK4_CONFIG 0x13 +#define RK806_BUCK5_CONFIG 0x14 +#define RK806_BUCK6_CONFIG 0x15 +#define RK806_BUCK7_CONFIG 0x16 +#define RK806_BUCK8_CONFIG 0x17 +#define RK806_BUCK9_CONFIG 0x18 +#define RK806_BUCK10_CONFIG 0x19 +#define RK806_BUCK1_ON_VSEL 0x1a +#define RK806_BUCK2_ON_VSEL 0x1b +#define RK806_BUCK3_ON_VSEL 0x1c +#define RK806_BUCK4_ON_VSEL 0x1d +#define RK806_BUCK5_ON_VSEL 0x1e +#define RK806_BUCK6_ON_VSEL 0x1f +#define RK806_BUCK7_ON_VSEL 0x20 +#define RK806_BUCK8_ON_VSEL 0x21 +#define RK806_BUCK9_ON_VSEL 0x22 +#define RK806_BUCK10_ON_VSEL 0x23 +#define RK806_BUCK1_SLP_VSEL 0x24 +#define RK806_BUCK2_SLP_VSEL 0x25 +#define RK806_BUCK3_SLP_VSEL 0x26 +#define RK806_BUCK4_SLP_VSEL 0x27 +#define RK806_BUCK5_SLP_VSEL 0x28 +#define RK806_BUCK6_SLP_VSEL 0x29 +#define RK806_BUCK7_SLP_VSEL 0x2a +#define RK806_BUCK8_SLP_VSEL 0x2b +#define RK806_BUCK9_SLP_VSEL 0x2d +#define RK806_BUCK10_SLP_VSEL 0x2e +#define RK806_BUCK_DEBUG1 0x30 +#define RK806_BUCK_DEBUG2 0x31 +#define RK806_BUCK_DEBUG3 0x32 +#define RK806_BUCK_DEBUG4 0x33 +#define RK806_BUCK_DEBUG5 0x34 +#define RK806_BUCK_DEBUG6 0x35 +#define RK806_BUCK_DEBUG7 0x36 +#define RK806_BUCK_DEBUG8 0x37 +#define RK806_BUCK_DEBUG9 0x38 +#define RK806_BUCK_DEBUG10 0x39 +#define RK806_BUCK_DEBUG11 0x3a +#define RK806_BUCK_DEBUG12 0x3b +#define RK806_BUCK_DEBUG13 0x3c +#define RK806_BUCK_DEBUG14 0x3d +#define RK806_BUCK_DEBUG15 0x3e +#define RK806_BUCK_DEBUG16 0x3f +#define RK806_BUCK_DEBUG17 0x40 +#define RK806_BUCK_DEBUG18 0x41 +#define RK806_NLDO_IMAX 0x42 +#define RK806_NLDO1_ON_VSEL 0x43 +#define RK806_NLDO2_ON_VSEL 0x44 +#define RK806_NLDO3_ON_VSEL 0x45 +#define RK806_NLDO4_ON_VSEL 0x46 +#define RK806_NLDO5_ON_VSEL 0x47 +#define RK806_NLDO1_SLP_VSEL 0x48 +#define RK806_NLDO2_SLP_VSEL 0x49 +#define RK806_NLDO3_SLP_VSEL 0x4a +#define RK806_NLDO4_SLP_VSEL 0x4b +#define RK806_NLDO5_SLP_VSEL 0x4c +#define RK806_PLDO_IMAX 0x4d +#define RK806_PLDO1_ON_VSEL 0x4e +#define RK806_PLDO2_ON_VSEL 0x4f +#define RK806_PLDO3_ON_VSEL 0x50 +#define RK806_PLDO4_ON_VSEL 0x51 +#define RK806_PLDO5_ON_VSEL 0x52 +#define RK806_PLDO6_ON_VSEL 0x53 +#define RK806_PLDO1_SLP_VSEL 0x54 +#define RK806_PLDO2_SLP_VSEL 0x55 +#define RK806_PLDO3_SLP_VSEL 0x56 +#define RK806_PLDO4_SLP_VSEL 0x57 +#define RK806_PLDO5_SLP_VSEL 0x58 +#define RK806_PLDO6_SLP_VSEL 0x59 +#define RK806_CHIP_NAME 0x5a +#define RK806_CHIP_VER 0x5b +#define RK806_OTP_VER 0x5c +#define RK806_SYS_STS 0x5d +#define RK806_SYS_CFG0 0x5e +#define RK806_SYS_CFG1 0x5f +#define RK806_SYS_OPTION 0x61 +#define RK806_SLEEP_CONFIG0 0x62 +#define RK806_SLEEP_CONFIG1 0x63 +#define RK806_SLEEP_CTR_SEL0 0x64 +#define RK806_SLEEP_CTR_SEL1 0x65 +#define RK806_SLEEP_CTR_SEL2 0x66 +#define RK806_SLEEP_CTR_SEL3 0x67 +#define RK806_SLEEP_CTR_SEL4 0x68 +#define RK806_SLEEP_CTR_SEL5 0x69 +#define RK806_DVS_CTRL_SEL0 0x6a +#define RK806_DVS_CTRL_SEL1 0x6b +#define RK806_DVS_CTRL_SEL2 0x6c +#define RK806_DVS_CTRL_SEL3 0x6d +#define RK806_DVS_CTRL_SEL4 0x6e +#define RK806_DVS_CTRL_SEL5 0x6f +#define RK806_DVS_START_CTRL 0x70 +#define RK806_SLEEP_GPIO 0x71 +#define RK806_SYS_CFG3 0x72 +#define RK806_ON_SOURCE 0x74 +#define RK806_OFF_SOURCE 0x75 +#define RK806_PWRON_KEY 0x76 +#define RK806_INT_STS0 0x77 +#define RK806_INT_MSK0 0x78 +#define RK806_INT_STS1 0x79 +#define RK806_INT_MSK1 0x7a +#define RK806_GPIO_INT_CONFIG 0x7b +#define RK806_DATA_REG0 0x7c +#define RK806_DATA_REG1 0x7d +#define RK806_DATA_REG2 0x7e +#define RK806_DATA_REG3 0x7f +#define RK806_DATA_REG4 0x80 +#define RK806_DATA_REG5 0x81 +#define RK806_DATA_REG6 0x82 +#define RK806_DATA_REG7 0x83 +#define RK806_DATA_REG8 0x84 +#define RK806_DATA_REG9 0x85 +#define RK806_DATA_REG10 0x86 +#define RK806_DATA_REG11 0x87 +#define RK806_DATA_REG12 0x88 +#define RK806_DATA_REG13 0x89 +#define RK806_DATA_REG14 0x8a +#define RK806_DATA_REG15 0x8b +#define RK806_TM_REG 0x8c +#define RK806_OTP_EN_REG 0x8d +#define RK806_FUNC_OTP_EN_REG 0x8e +#define RK806_TEST_REG1 0x8f +#define RK806_TEST_REG2 0x90 +#define RK806_TEST_REG3 0x91 +#define RK806_TEST_REG4 0x92 +#define RK806_TEST_REG5 0x93 +#define RK806_BUCK_VSEL_OTP_REG0 0x94 +#define RK806_BUCK_VSEL_OTP_REG1 0x95 +#define RK806_BUCK_VSEL_OTP_REG2 0x96 +#define RK806_BUCK_VSEL_OTP_REG3 0x97 +#define RK806_BUCK_VSEL_OTP_REG4 0x98 +#define RK806_BUCK_VSEL_OTP_REG5 0x99 +#define RK806_BUCK_VSEL_OTP_REG6 0x9a +#define RK806_BUCK_VSEL_OTP_REG7 0x9b +#define RK806_BUCK_VSEL_OTP_REG8 0x9c +#define RK806_BUCK_VSEL_OTP_REG9 0x9d +#define RK806_NLDO1_VSEL_OTP_REG0 0x9e +#define RK806_NLDO1_VSEL_OTP_REG1 0x9f +#define RK806_NLDO1_VSEL_OTP_REG2 0xa0 +#define RK806_NLDO1_VSEL_OTP_REG3 0xa1 +#define RK806_NLDO1_VSEL_OTP_REG4 0xa2 +#define RK806_PLDO_VSEL_OTP_REG0 0xa3 +#define RK806_PLDO_VSEL_OTP_REG1 0xa4 +#define RK806_PLDO_VSEL_OTP_REG2 0xa5 +#define RK806_PLDO_VSEL_OTP_REG3 0xa6 +#define RK806_PLDO_VSEL_OTP_REG4 0xa7 +#define RK806_PLDO_VSEL_OTP_REG5 0xa8 +#define RK806_BUCK_EN_OTP_REG1 0xa9 +#define RK806_NLDO_EN_OTP_REG1 0xaa +#define RK806_PLDO_EN_OTP_REG1 0xab +#define RK806_BUCK_FB_RES_OTP_REG1 0xac +#define RK806_OTP_RESEV_REG0 0xad +#define RK806_OTP_RESEV_REG1 0xae +#define RK806_OTP_RESEV_REG2 0xaf +#define RK806_OTP_RESEV_REG3 0xb0 +#define RK806_OTP_RESEV_REG4 0xb1 +#define RK806_BUCK_SEQ_REG0 0xb2 +#define RK806_BUCK_SEQ_REG1 0xb3 +#define RK806_BUCK_SEQ_REG2 0xb4 +#define RK806_BUCK_SEQ_REG3 0xb5 +#define RK806_BUCK_SEQ_REG4 0xb6 +#define RK806_BUCK_SEQ_REG5 0xb7 +#define RK806_BUCK_SEQ_REG6 0xb8 +#define RK806_BUCK_SEQ_REG7 0xb9 +#define RK806_BUCK_SEQ_REG8 0xba +#define RK806_BUCK_SEQ_REG9 0xbb +#define RK806_BUCK_SEQ_REG10 0xbc +#define RK806_BUCK_SEQ_REG11 0xbd +#define RK806_BUCK_SEQ_REG12 0xbe +#define RK806_BUCK_SEQ_REG13 0xbf +#define RK806_BUCK_SEQ_REG14 0xc0 +#define RK806_BUCK_SEQ_REG15 0xc1 +#define RK806_BUCK_SEQ_REG16 0xc2 +#define RK806_BUCK_SEQ_REG17 0xc3 +#define RK806_HK_TRIM_REG1 0xc4 +#define RK806_HK_TRIM_REG2 0xc5 +#define RK806_BUCK_REF_TRIM_REG1 0xc6 +#define RK806_BUCK_REF_TRIM_REG2 0xc7 +#define RK806_BUCK_REF_TRIM_REG3 0xc8 +#define RK806_BUCK_REF_TRIM_REG4 0xc9 +#define RK806_BUCK_REF_TRIM_REG5 0xca +#define RK806_BUCK_OSC_TRIM_REG1 0xcb +#define RK806_BUCK_OSC_TRIM_REG2 0xcc +#define RK806_BUCK_OSC_TRIM_REG3 0xcd +#define RK806_BUCK_OSC_TRIM_REG4 0xce +#define RK806_BUCK_OSC_TRIM_REG5 0xcf +#define RK806_BUCK_TRIM_ZCDIOS_REG1 0xd0 +#define RK806_BUCK_TRIM_ZCDIOS_REG2 0xd1 +#define RK806_NLDO_TRIM_REG1 0xd2 +#define RK806_NLDO_TRIM_REG2 0xd3 +#define RK806_NLDO_TRIM_REG3 0xd4 +#define RK806_PLDO_TRIM_REG1 0xd5 +#define RK806_PLDO_TRIM_REG2 0xd6 +#define RK806_PLDO_TRIM_REG3 0xd7 +#define RK806_TRIM_ICOMP_REG1 0xd8 +#define RK806_TRIM_ICOMP_REG2 0xd9 +#define RK806_EFUSE_CONTROL_REGH 0xda +#define RK806_FUSE_PROG_REG 0xdb +#define RK806_MAIN_FSM_STS_REG 0xdd +#define RK806_FSM_REG 0xde +#define RK806_TOP_RESEV_OFFR 0xec +#define RK806_TOP_RESEV_POR 0xed +#define RK806_BUCK_VRSN_REG1 0xee +#define RK806_BUCK_VRSN_REG2 0xef +#define RK806_NLDO_RLOAD_SEL_REG1 0xf0 +#define RK806_PLDO_RLOAD_SEL_REG1 0xf1 +#define RK806_PLDO_RLOAD_SEL_REG2 0xf2 +#define RK806_BUCK_CMIN_MX_REG1 0xf3 +#define RK806_BUCK_CMIN_MX_REG2 0xf4 +#define RK806_BUCK_FREQ_SET_REG1 0xf5 +#define RK806_BUCK_FREQ_SET_REG2 0xf6 +#define RK806_BUCK_RS_MEABS_REG1 0xf7 +#define RK806_BUCK_RS_MEABS_REG2 0xf8 +#define RK806_BUCK_RS_ZDLEB_REG1 0xf9 +#define RK806_BUCK_RS_ZDLEB_REG2 0xfa +#define RK806_BUCK_RSERVE_REG1 0xfb +#define RK806_BUCK_RSERVE_REG2 0xfc +#define RK806_BUCK_RSERVE_REG3 0xfd +#define RK806_BUCK_RSERVE_REG4 0xfe +#define RK806_BUCK_RSERVE_REG5 0xff + +#define RK806_CMD_READ 0 +#define RK806_CMD_WRITE RT_BIT(7) +#define RK806_CMD_CRC_EN RT_BIT(6) +#define RK806_CMD_CRC_DIS 0 +#define RK806_CMD_LEN_MSK 0x0f +#define RK806_REG_H 0x00 + +#define RK808_SECONDS_REG 0x00 +#define RK808_MINUTES_REG 0x01 +#define RK808_HOURS_REG 0x02 +#define RK808_DAYS_REG 0x03 +#define RK808_MONTHS_REG 0x04 +#define RK808_YEARS_REG 0x05 +#define RK808_WEEKS_REG 0x06 +#define RK808_ALARM_SECONDS_REG 0x08 +#define RK808_ALARM_MINUTES_REG 0x09 +#define RK808_ALARM_HOURS_REG 0x0a +#define RK808_ALARM_DAYS_REG 0x0b +#define RK808_ALARM_MONTHS_REG 0x0c +#define RK808_ALARM_YEARS_REG 0x0d +#define RK808_RTC_CTRL_REG 0x10 +#define RK808_RTC_STATUS_REG 0x11 +#define RK808_RTC_INT_REG 0x12 +#define RK808_RTC_COMP_LSB_REG 0x13 +#define RK808_RTC_COMP_MSB_REG 0x14 +#define RK808_ID_MSB 0x17 +#define RK808_ID_LSB 0x18 +#define RK808_CLK32OUT_REG 0x20 +#define RK808_VB_MON_REG 0x21 +#define RK808_THERMAL_REG 0x22 +#define RK808_DCDC_EN_REG 0x23 +#define RK808_LDO_EN_REG 0x24 +#define RK808_SLEEP_SET_OFF_REG1 0x25 +#define RK808_SLEEP_SET_OFF_REG2 0x26 +#define RK808_DCDC_UV_STS_REG 0x27 +#define RK808_DCDC_UV_ACT_REG 0x28 +#define RK808_LDO_UV_STS_REG 0x29 +#define RK808_LDO_UV_ACT_REG 0x2a +#define RK808_DCDC_PG_REG 0x2b +#define RK808_LDO_PG_REG 0x2c +#define RK808_VOUT_MON_TDB_REG 0x2d +#define RK808_BUCK1_CONFIG_REG 0x2e +#define RK808_BUCK1_ON_VSEL_REG 0x2f +#define RK808_BUCK1_SLP_VSEL_REG 0x30 +#define RK808_BUCK1_DVS_VSEL_REG 0x31 +#define RK808_BUCK2_CONFIG_REG 0x32 +#define RK808_BUCK2_ON_VSEL_REG 0x33 +#define RK808_BUCK2_SLP_VSEL_REG 0x34 +#define RK808_BUCK2_DVS_VSEL_REG 0x35 +#define RK808_BUCK3_CONFIG_REG 0x36 +#define RK808_BUCK4_CONFIG_REG 0x37 +#define RK808_BUCK4_ON_VSEL_REG 0x38 +#define RK808_BUCK4_SLP_VSEL_REG 0x39 +#define RK808_BOOST_CONFIG_REG 0x3a +#define RK808_LDO1_ON_VSEL_REG 0x3b +#define RK808_LDO1_SLP_VSEL_REG 0x3c +#define RK808_LDO2_ON_VSEL_REG 0x3d +#define RK808_LDO2_SLP_VSEL_REG 0x3e +#define RK808_LDO3_ON_VSEL_REG 0x3f +#define RK808_LDO3_SLP_VSEL_REG 0x40 +#define RK808_LDO4_ON_VSEL_REG 0x41 +#define RK808_LDO4_SLP_VSEL_REG 0x42 +#define RK808_LDO5_ON_VSEL_REG 0x43 +#define RK808_LDO5_SLP_VSEL_REG 0x44 +#define RK808_LDO6_ON_VSEL_REG 0x45 +#define RK808_LDO6_SLP_VSEL_REG 0x46 +#define RK808_LDO7_ON_VSEL_REG 0x47 +#define RK808_LDO7_SLP_VSEL_REG 0x48 +#define RK808_LDO8_ON_VSEL_REG 0x49 +#define RK808_LDO8_SLP_VSEL_REG 0x4a +#define RK808_DEVCTRL_REG 0x4b +#define RK808_INT_STS_REG1 0x4c +#define RK808_INT_STS_MSK_REG1 0x4d +#define RK808_INT_STS_REG2 0x4e +#define RK808_INT_STS_MSK_REG2 0x4f +#define RK808_IO_POL_REG 0x50 + +#define RK809_BUCK5_CONFIG(i) (RK817_BOOST_OTG_CFG + (i) * 1) + +#define RK817_SECONDS_REG 0x00 +#define RK817_MINUTES_REG 0x01 +#define RK817_HOURS_REG 0x02 +#define RK817_DAYS_REG 0x03 +#define RK817_MONTHS_REG 0x04 +#define RK817_YEARS_REG 0x05 +#define RK817_WEEKS_REG 0x06 +#define RK817_ALARM_SECONDS_REG 0x07 +#define RK817_ALARM_MINUTES_REG 0x08 +#define RK817_ALARM_HOURS_REG 0x09 +#define RK817_ALARM_DAYS_REG 0x0a +#define RK817_ALARM_MONTHS_REG 0x0b +#define RK817_ALARM_YEARS_REG 0x0c +#define RK817_RTC_CTRL_REG 0xd +#define RK817_RTC_STATUS_REG 0xe +#define RK817_RTC_INT_REG 0xf +#define RK817_RTC_COMP_LSB_REG 0x10 +#define RK817_RTC_COMP_MSB_REG 0x11 + +#define RK817_POWER_EN_REG(i) (0xb1 + (i)) +#define RK817_POWER_SLP_EN_REG(i) (0xb5 + (i)) + +#define RK817_POWER_CONFIG (0xb9) + +#define RK817_BUCK_CONFIG_REG(i) (0xba + (i) * 3) + +#define RK817_BUCK1_ON_VSEL_REG 0xbb +#define RK817_BUCK1_SLP_VSEL_REG 0xbc + +#define RK817_BUCK2_CONFIG_REG 0xbd +#define RK817_BUCK2_ON_VSEL_REG 0xbe +#define RK817_BUCK2_SLP_VSEL_REG 0xbf + +#define RK817_BUCK3_CONFIG_REG 0xc0 +#define RK817_BUCK3_ON_VSEL_REG 0xc1 +#define RK817_BUCK3_SLP_VSEL_REG 0xc2 + +#define RK817_BUCK4_CONFIG_REG 0xc3 +#define RK817_BUCK4_ON_VSEL_REG 0xc4 +#define RK817_BUCK4_SLP_VSEL_REG 0xc5 + +#define RK817_LDO_ON_VSEL_REG(idx) (0xcc + (idx) * 2) +#define RK817_BOOST_OTG_CFG (0xde) + +enum rk817_reg_id +{ + RK817_ID_DCDC1 = 0, + RK817_ID_DCDC2, + RK817_ID_DCDC3, + RK817_ID_DCDC4, + RK817_ID_LDO1, + RK817_ID_LDO2, + RK817_ID_LDO3, + RK817_ID_LDO4, + RK817_ID_LDO5, + RK817_ID_LDO6, + RK817_ID_LDO7, + RK817_ID_LDO8, + RK817_ID_LDO9, + RK817_ID_BOOST, + RK817_ID_BOOST_OTG_SW, + RK817_NUM_REGULATORS +}; + +#define RK818_DCDC1 0 +#define RK818_LDO1 4 +#define RK818_NUM_REGULATORS 17 + +enum rk818_reg +{ + RK818_ID_DCDC1, + RK818_ID_DCDC2, + RK818_ID_DCDC3, + RK818_ID_DCDC4, + RK818_ID_BOOST, + RK818_ID_LDO1, + RK818_ID_LDO2, + RK818_ID_LDO3, + RK818_ID_LDO4, + RK818_ID_LDO5, + RK818_ID_LDO6, + RK818_ID_LDO7, + RK818_ID_LDO8, + RK818_ID_LDO9, + RK818_ID_SWITCH, + RK818_ID_HDMI_SWITCH, + RK818_ID_OTG_SWITCH, +}; + +#define RK818_DCDC_EN_REG 0x23 +#define RK818_LDO_EN_REG 0x24 +#define RK818_SLEEP_SET_OFF_REG1 0x25 +#define RK818_SLEEP_SET_OFF_REG2 0x26 +#define RK818_DCDC_UV_STS_REG 0x27 +#define RK818_DCDC_UV_ACT_REG 0x28 +#define RK818_LDO_UV_STS_REG 0x29 +#define RK818_LDO_UV_ACT_REG 0x2a +#define RK818_DCDC_PG_REG 0x2b +#define RK818_LDO_PG_REG 0x2c +#define RK818_VOUT_MON_TDB_REG 0x2d +#define RK818_BUCK1_CONFIG_REG 0x2e +#define RK818_BUCK1_ON_VSEL_REG 0x2f +#define RK818_BUCK1_SLP_VSEL_REG 0x30 +#define RK818_BUCK2_CONFIG_REG 0x32 +#define RK818_BUCK2_ON_VSEL_REG 0x33 +#define RK818_BUCK2_SLP_VSEL_REG 0x34 +#define RK818_BUCK3_CONFIG_REG 0x36 +#define RK818_BUCK4_CONFIG_REG 0x37 +#define RK818_BUCK4_ON_VSEL_REG 0x38 +#define RK818_BUCK4_SLP_VSEL_REG 0x39 +#define RK818_BOOST_CONFIG_REG 0x3a +#define RK818_LDO1_ON_VSEL_REG 0x3b +#define RK818_LDO1_SLP_VSEL_REG 0x3c +#define RK818_LDO2_ON_VSEL_REG 0x3d +#define RK818_LDO2_SLP_VSEL_REG 0x3e +#define RK818_LDO3_ON_VSEL_REG 0x3f +#define RK818_LDO3_SLP_VSEL_REG 0x40 +#define RK818_LDO4_ON_VSEL_REG 0x41 +#define RK818_LDO4_SLP_VSEL_REG 0x42 +#define RK818_LDO5_ON_VSEL_REG 0x43 +#define RK818_LDO5_SLP_VSEL_REG 0x44 +#define RK818_LDO6_ON_VSEL_REG 0x45 +#define RK818_LDO6_SLP_VSEL_REG 0x46 +#define RK818_LDO7_ON_VSEL_REG 0x47 +#define RK818_LDO7_SLP_VSEL_REG 0x48 +#define RK818_LDO8_ON_VSEL_REG 0x49 +#define RK818_LDO8_SLP_VSEL_REG 0x4a +#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54 +#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55 +#define RK818_DEVCTRL_REG 0x4b +#define RK818_INT_STS_REG1 0X4c +#define RK818_INT_STS_MSK_REG1 0x4d +#define RK818_INT_STS_REG2 0x4e +#define RK818_INT_STS_MSK_REG2 0x4f +#define RK818_IO_POL_REG 0x50 +#define RK818_H5V_EN_REG 0x52 +#define RK818_SLEEP_SET_OFF_REG3 0x53 +#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54 +#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55 +#define RK818_BOOST_CTRL_REG 0x56 +#define RK818_DCDC_ILMAX 0x90 +#define RK818_USB_CTRL_REG 0xa1 + +#define RK818_H5V_EN RT_BIT(0) +#define RK818_REF_RDY_CTRL RT_BIT(1) +#define RK818_USB_ILIM_SEL_MASK 0xf +#define RK818_USB_ILMIN_2000MA 0x7 +#define RK818_USB_CHG_SD_VSEL_MASK 0x70 + +enum +{ + RK805_ID = 0x8050, + RK806_ID = 0x8060, + RK808_ID = 0x0000, + RK809_ID = 0x8090, + RK817_ID = 0x8170, + RK818_ID = 0x8180, +}; + +struct rk8xx +{ + int variant; + + int irq; + struct rt_device *dev; + + rt_uint32_t (*read)(struct rk8xx *, rt_uint16_t reg); + rt_err_t (*write)(struct rk8xx *, rt_uint16_t reg, rt_uint8_t data); + rt_err_t (*update_bits)(struct rk8xx *, rt_uint16_t reg, rt_uint8_t mask, + rt_uint8_t data); + + void *priv; +}; + +#define rk8xx_to_i2c_client(rk8xx) rt_container_of((rk8xx)->dev, struct rt_i2c_client, parent) +#define rk8xx_to_spi_device(rk8xx) rt_container_of((rk8xx)->dev, struct rt_spi_device, parent) + +rt_inline rt_uint32_t rk8xx_read(struct rk8xx *rk8xx, rt_uint16_t reg) +{ + return rk8xx->read(rk8xx, reg); +} + +rt_inline rt_err_t rk8xx_write(struct rk8xx *rk8xx, rt_uint16_t reg, rt_uint8_t data) +{ + return rk8xx->write(rk8xx, reg, data); +} + +rt_inline rt_err_t rk8xx_update_bits(struct rk8xx *rk8xx, rt_uint16_t reg, + rt_uint8_t mask, rt_uint8_t data) +{ + return rk8xx->update_bits(rk8xx, reg, mask, data); +} + +#endif /* __RK8XX_H__ */ diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript index 18db8bad4831..049b6aaedc8a 100644 --- a/components/drivers/misc/SConscript +++ b/components/drivers/misc/SConscript @@ -5,15 +5,9 @@ src = [] CPPPATH = [cwd + '/../include'] group = [] -if GetDepend(['RT_USING_ADC']): - src = src + ['adc.c'] - if GetDepend(['RT_USING_DAC']): src = src + ['dac.c'] -if GetDepend(['RT_USING_PWM']): - src = src + ['rt_drv_pwm.c'] - if GetDepend(['RT_USING_PULSE_ENCODER']): src = src + ['pulse_encoder.c'] diff --git a/components/drivers/mtd/mtd-cfi.c b/components/drivers/mtd/mtd-cfi.c index 3940cbaf39f2..7378737cd89e 100755 --- a/components/drivers/mtd/mtd-cfi.c +++ b/components/drivers/mtd/mtd-cfi.c @@ -819,13 +819,14 @@ static rt_ssize_t cfi_flash_write(struct rt_mtd_nor_device *dev, rt_off_t offset static rt_err_t cfi_flash_erase_block(struct rt_mtd_nor_device *dev, rt_off_t offset, rt_size_t length) { union cfiptr cptr; - union cfiword cword; + union cfiword cword = { .c = 0xff }; rt_int32_t sect; rt_int32_t prot = 0; + rt_err_t err = RT_EOK; struct cfi_flash_map *maps = raw_to_cfi_flash_map(dev); rt_off_t sect_start = offset / maps->block_size, sect_end = (offset + length) / maps->block_size; - cword.c = 0xff; + rt_mutex_take(&maps->rw_lock, RT_WAITING_FOREVER); for (sect = sect_start; sect <= sect_end; ++sect) { @@ -839,7 +840,8 @@ static rt_err_t cfi_flash_erase_block(struct rt_mtd_nor_device *dev, rt_off_t of { LOG_W("%d protected sectors will not be erased", prot); - return -RT_EIO; + err = -RT_EIO; + goto _out_lock; } if (sect_start == 0 && sect_end == (maps->sect_count - 1) @@ -857,7 +859,8 @@ static rt_err_t cfi_flash_erase_block(struct rt_mtd_nor_device *dev, rt_off_t of if (cfi_flash_full_status_check(maps, cptr, &cword, maps->erase_chip_tout, "chip erase")) { - return -RT_ERROR; + err = -RT_ERROR; + goto _out_lock; } } else @@ -893,13 +896,17 @@ static rt_err_t cfi_flash_erase_block(struct rt_mtd_nor_device *dev, rt_off_t of if (cfi_flash_full_status_check(maps, cptr, &cword, maps->erase_blk_tout, "sector erase")) { - return -RT_ERROR; + err = -RT_ERROR; + goto _out_lock; } } } } - return RT_EOK; +_out_lock: + rt_mutex_release(&maps->rw_lock); + + return err; } const static struct rt_mtd_nor_driver_ops cfi_flash_ops = @@ -910,52 +917,36 @@ const static struct rt_mtd_nor_driver_ops cfi_flash_ops = .erase_block = cfi_flash_erase_block, }; -static rt_err_t cfi_flash_ofw_init(struct rt_platform_device *pdev, struct cfi_flash *cfi) +static rt_err_t cfi_flash_probe(struct rt_platform_device *pdev) { - rt_err_t err; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - cfi->maps_nr = rt_ofw_get_address_count(np); + const char *name; + rt_err_t err = RT_EOK; + struct rt_device *dev = &pdev->parent; + struct cfi_flash *cfi = rt_calloc(1, sizeof(*cfi)); - if (cfi->maps_nr <= 0) + if (!cfi) { - return -RT_EEMPTY; + return -RT_ENOMEM; } - if ((err = rt_ofw_prop_read_u32(np, "bank-width", &cfi->bank_width))) - { - return err; - } + cfi->maps_nr = rt_dm_dev_get_address_count(dev); - if (!(cfi->maps = rt_calloc(1, sizeof(*cfi->maps) * cfi->maps_nr))) + if (cfi->maps_nr <= 0) { - return -RT_ENOMEM; - } + err = -RT_EEMPTY; - for (int i = 0; i < cfi->maps_nr; ++i) - { - if ((err = rt_ofw_get_address(np, i, &cfi->maps[i].address, &cfi->maps[i].size))) - { - break; - } + goto _fail; } - return err; -} - -static rt_err_t cfi_flash_probe(struct rt_platform_device *pdev) -{ - const char *name; - rt_err_t err = RT_EOK; - struct cfi_flash *cfi = rt_calloc(1, sizeof(*cfi)); - - if (!cfi) + if ((err = rt_dm_dev_prop_read_u32(dev, "bank-width", &cfi->bank_width))) { - return -RT_ENOMEM; + goto _fail; } - if ((err = cfi_flash_ofw_init(pdev, cfi))) + if (!(cfi->maps = rt_calloc(1, sizeof(*cfi->maps) * cfi->maps_nr))) { + err = -RT_ENOMEM; + goto _fail; } @@ -963,11 +954,23 @@ static rt_err_t cfi_flash_probe(struct rt_platform_device *pdev) { struct cfi_flash_map *maps = &cfi->maps[i]; rt_int32_t size_ratio, offset_etout, offset_wbtout, wtout; - rt_uint64_t address = maps->address, size = maps->size; + rt_uint64_t address, size; rt_size_t sect_count = 0; rt_ubase_t sector; /* map a page early first */ - void *early_base = rt_ioremap((void *)address, RT_MM_PAGE_SIZE); + void *early_base; + + if (rt_dm_dev_get_address(dev, i, &address, &size) < 0) + { + err = -RT_EIO; + + goto _fail; + } + + maps->address = address; + maps->size = size; + + early_base = rt_ioremap((void *)address, RT_MM_PAGE_SIZE); if (!early_base) { @@ -1109,12 +1112,12 @@ static rt_err_t cfi_flash_probe(struct rt_platform_device *pdev) maps->parent.block_end = maps->sect_count; maps->parent.block_size = maps->block_size; - if ((err = rt_dm_set_dev_name_auto(&maps->parent.parent, "nor")) < 0) + if ((err = rt_dm_dev_set_name_auto(&maps->parent.parent, "nor")) < 0) { goto _fail; } - name = rt_dm_get_dev_name(&maps->parent.parent); + name = rt_dm_dev_get_name(&maps->parent.parent); if ((err = rt_mutex_init(&maps->rw_lock, name, RT_IPC_FLAG_PRIO))) { diff --git a/components/drivers/ofw/Kconfig b/components/drivers/ofw/Kconfig index bebb5b43843e..5beb7df85c26 100755 --- a/components/drivers/ofw/Kconfig +++ b/components/drivers/ofw/Kconfig @@ -20,3 +20,10 @@ config RT_FDT_EARLYCON_MSG_SIZE int "Earlycon message buffer size (KB)" depends on RT_USING_OFW default 128 + +config RT_USING_OFW_DIRECTFS + bool "Export fdt in direct access" + depends on RT_USING_OFW + select RT_USING_DFS + select RT_USING_DFS_DIRECTFS + default n diff --git a/components/drivers/ofw/base.c b/components/drivers/ofw/base.c index 562ce6093e04..011060b71e9c 100644 --- a/components/drivers/ofw/base.c +++ b/components/drivers/ofw/base.c @@ -609,7 +609,7 @@ struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path) break; } - path += len; + path += len + !!*next; } np = tmp; @@ -1030,9 +1030,9 @@ rt_err_t ofw_alias_scan(void) continue; } - end = name + rt_strlen(name); + end = name + rt_strlen(name) - 1; - while (*end && !(*end >= '0' && *end <= '9')) + while (*end && !(*end >= '0' && *end <= '9') && end > name) { --end; } @@ -1042,7 +1042,7 @@ rt_err_t ofw_alias_scan(void) id += (*end - '0') * rate; rate *= 10; - --end; + ++end; } info = rt_malloc(sizeof(*info)); @@ -1057,7 +1057,7 @@ rt_err_t ofw_alias_scan(void) info->id = id; info->tag = name; - info->tag_len = end - name; + info->tag_len = end - name - 1; info->np = tmp; rt_list_insert_after(&_aliases_nodes, &info->list); diff --git a/components/drivers/ofw/fdt.c b/components/drivers/ofw/fdt.c index 477511b96b4c..762b88f950f3 100755 --- a/components/drivers/ofw/fdt.c +++ b/components/drivers/ofw/fdt.c @@ -14,12 +14,17 @@ #include #include #include +#ifdef RT_USING_OFW_DIRECTFS +#include +#include +#endif #define DBG_TAG "rtdm.ofw" #define DBG_LVL DBG_INFO #include #include "ofw_internal.h" +#include "../serial/serial_dm.h" struct rt_fdt_earlycon fdt_earlycon rt_section(".bss.noclean.earlycon"); @@ -79,14 +84,13 @@ rt_uint64_t rt_fdt_translate_address(void *fdt, int nodeoffset, rt_uint64_t addr int addr_cells; int size_cells; } local, cpu; - int parent, length, group_len; + int parent, length = 0, group_len; const fdt32_t *ranges = RT_NULL; parent = fdt_parent_offset(fdt, nodeoffset); if (parent >= 0) { - length = 0; ranges = fdt_getprop(fdt, nodeoffset, "ranges", &length); } @@ -322,7 +326,7 @@ static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname) } else { - while (len >= t_len) + for (; len >= t_len; len -= t_len) { base = rt_fdt_next_cell(&prop, _root_addr_cells); size = rt_fdt_next_cell(&prop, _root_size_cells); @@ -334,8 +338,6 @@ static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname) base = rt_fdt_translate_address(_fdt, nodeoffset, base); reserve_memregion(fdt_get_name(_fdt, nodeoffset, RT_NULL), base, size); - - len -= t_len; } } } @@ -665,12 +667,17 @@ void rt_fdt_earlycon_kick(int why) fdt_earlycon.console_kick(&fdt_earlycon, why); } - if (why == FDT_EARLYCON_KICK_COMPLETED && fdt_earlycon.msg_idx) + if (why == FDT_EARLYCON_KICK_COMPLETED) { - fdt_earlycon.msg_idx = 0; + fdt_earlycon.console_putc = RT_NULL; - /* Dump old messages */ - rt_kputs(fdt_earlycon.msg); + if (fdt_earlycon.msg_idx) + { + fdt_earlycon.msg_idx = 0; + + /* Dump old messages */ + rt_kputs(fdt_earlycon.msg); + } } } @@ -788,6 +795,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void) if (options && *options && *options != ' ') { options_len = rt_strchrnul(options, ' ') - options; + + rt_strncpy(fdt_earlycon.options, options, options_len); } /* console > stdout-path */ @@ -825,7 +834,7 @@ rt_err_t rt_fdt_scan_chosen_stdout(void) if (best_earlycon_id && best_earlycon_id->setup) { - rt_bool_t used_options = RT_FALSE; + int split = 0; if (!con_type) { @@ -834,25 +843,26 @@ rt_err_t rt_fdt_scan_chosen_stdout(void) fdt_earlycon.fdt = _fdt; fdt_earlycon.nodeoffset = offset; - err = best_earlycon_id->setup(&fdt_earlycon, options); + err = best_earlycon_id->setup(&fdt_earlycon, fdt_earlycon.options); - for (int i = 0; i < options_len; ++i) + for (int i = 0; i <= options_len; ++i) { - if (options[i] == RT_FDT_EARLYCON_OPTION_SIGNATURE) + if (fdt_earlycon.options[i] == '\0') { - /* Restore ',' */ - ((char *)options)[i++] = ','; - options = &options[i]; - options_len -= i; - used_options = RT_TRUE; - break; + if (i == options_len) + { + options_len -= split++; + + rt_memmove(fdt_earlycon.options, + &fdt_earlycon.options[split], options_len); + fdt_earlycon.options[options_len] = '\0'; + + break; + } + + split = i; } } - if (!used_options) - { - options = RT_NULL; - options_len = 0; - } } } } @@ -878,8 +888,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void) if (fdt_earlycon.mmio) { - LOG_I("Earlycon: %s at MMIO/PIO %p (options '%.*s')", - con_type, fdt_earlycon.mmio, options_len, options ? options : ""); + LOG_I("Earlycon: %s at MMIO/PIO %p (options '%s')", + con_type, fdt_earlycon.mmio, fdt_earlycon.options); } return err; @@ -936,6 +946,45 @@ rt_err_t rt_fdt_unflatten(void) return err; } +#ifdef RT_USING_OFW_DIRECTFS +static rt_ssize_t dts_directfs_read_raw(rt_object_t obj, struct directfs_bin_attribute *attr, + char *buffer, rt_off_t pos, rt_size_t count) +{ + rt_ssize_t res; + rt_size_t size; + struct rt_ofw_prop *prop = rt_container_of(obj, struct rt_ofw_prop, obj); + + size = prop->length; + + if (pos <= size) + { + if (count > size - pos) + { + count = size - pos; + } + + rt_memcpy(buffer, prop->value + pos, count); + + res = count; + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +static struct directfs_bin_attribute dts_directfs_attr_raw = +{ + .attr = + { + .name = "raw", + }, + .read = dts_directfs_read_raw, +}; +#endif /* RT_USING_OFW_DIRECTFS */ + static rt_err_t fdt_unflatten_props(struct rt_ofw_node *np, int node_off) { rt_err_t err = RT_EOK; @@ -964,6 +1013,11 @@ static rt_err_t fdt_unflatten_props(struct rt_ofw_node *np, int node_off) np->name = prop->value; } + #ifdef RT_USING_OFW_DIRECTFS + dfs_directfs_create_link(&np->obj, &prop->obj, prop->name); + dfs_directfs_create_bin_file(&prop->obj, &dts_directfs_attr_raw); + #endif + prop_off = fdt_next_property_offset(_fdt, prop_off); if (prop_off < 0) @@ -1009,6 +1063,13 @@ static rt_err_t fdt_unflatten_single(struct rt_ofw_node *np, int node_off) } } + #ifdef RT_USING_OFW_DIRECTFS + if (parent) + { + dfs_directfs_create_link(&parent->obj, &np->obj, np->full_name); + } + #endif + if ((err = fdt_unflatten_props(np, node_off))) { break; @@ -1070,11 +1131,52 @@ static rt_err_t fdt_unflatten_single(struct rt_ofw_node *np, int node_off) return err; } +#ifdef RT_USING_OFW_DIRECTFS +static rt_ssize_t fdt_directfs_read_raw(rt_object_t obj, struct directfs_bin_attribute *attr, + char *buffer, rt_off_t pos, rt_size_t count) +{ + rt_ssize_t res; + void *fdt = ((struct fdt_info *)ofw_node_root->name)->fdt; + rt_size_t fdt_size = fdt_totalsize(fdt); + + if (pos <= fdt_size) + { + if (count > fdt_size - pos) + { + count = fdt_size - pos; + } + + rt_memcpy(buffer, fdt + pos, count); + + res = count; + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +static struct directfs_bin_attribute fdt_directfs_attr_raw = +{ + .attr = + { + .name = "raw", + }, + .read = fdt_directfs_read_raw, +}; +#endif /* RT_USING_OFW_DIRECTFS */ + struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt) { int root_off; struct fdt_info *header; struct rt_ofw_node *root = RT_NULL; +#ifdef RT_USING_OFW_DIRECTFS + rt_object_t fdt_fsobj; + rt_object_t firmware = dfs_directfs_find_object(RT_NULL, "firmware"); +#endif if (fdt && (root_off = fdt_path_offset(fdt, "/")) >= 0) { @@ -1092,9 +1194,23 @@ struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt) header->rsvmap = (struct fdt_reserve_entry *)((void *)fdt + fdt_off_mem_rsvmap(fdt)); header->rsvmap_nr = fdt_num_mem_rsv(fdt); + #ifdef RT_USING_OFW_DIRECTFS + dfs_directfs_create_link(firmware, &root->obj, "devicetree"); + #endif + if (!fdt_unflatten_single(root, root_off)) { root->name = (const char *)header; + + #ifdef RT_USING_OFW_DIRECTFS + fdt_fsobj = rt_malloc(sizeof(*fdt_fsobj)); + + if (fdt_fsobj) + { + dfs_directfs_create_link(firmware, fdt_fsobj, "fdt"); + dfs_directfs_create_bin_file(fdt_fsobj, &fdt_directfs_attr_raw); + } + #endif } else { diff --git a/components/drivers/ofw/io.c b/components/drivers/ofw/io.c index b5d6b584251f..5f4892c1485c 100755 --- a/components/drivers/ofw/io.c +++ b/components/drivers/ofw/io.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -155,7 +154,7 @@ static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name { int index = 0; - rt_err_t err = RT_EOK; + rt_err_t err = -RT_EEMPTY; const char *reg_name; struct rt_ofw_prop *prop; @@ -386,6 +385,22 @@ rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_t return cpu_addr; } +#ifdef ARCH_CPU_64BIT +#define ofw_address_cpu_cast(np, address) (void *)(address) +#else +#define ofw_address_cpu_cast(np, address) \ +({ \ + if (((address) >> 32)) \ + { \ + LOG_W("%s find 64 bits address = %x%x", \ + rt_ofw_node_full_name(np), \ + ofw_static_cast(rt_ubase_t, (address) >> 32), \ + ofw_static_cast(rt_ubase_t, (address))); \ + } \ + (void *)ofw_static_cast(rt_ubase_t, (address)); \ +}) +#endif + void *rt_ofw_iomap(struct rt_ofw_node *np, int index) { void *iomem = RT_NULL; @@ -396,7 +411,7 @@ void *rt_ofw_iomap(struct rt_ofw_node *np, int index) if (!ofw_get_address(np, index, ®s[0], ®s[1])) { - iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]); + iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]); } } @@ -413,7 +428,7 @@ void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name) if (!ofw_get_address_by_name(np, name, ®s[0], ®s[1])) { - iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]); + iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]); } } diff --git a/components/drivers/ofw/irq.c b/components/drivers/ofw/irq.c index f5457453b4ab..0c7db4109ad2 100755 --- a/components/drivers/ofw/irq.c +++ b/components/drivers/ofw/irq.c @@ -196,6 +196,9 @@ static rt_err_t ofw_parse_irq_map(struct rt_ofw_node *np, struct rt_ofw_cell_arg break; } + map_len /= sizeof(fdt32_t); + map_mask_len /= sizeof(fdt32_t); + err = -RT_EINVAL; addr = irq_args->data; @@ -491,7 +494,7 @@ rt_err_t rt_ofw_parse_irq_cells(struct rt_ofw_node *np, int index, struct rt_ofw struct rt_ofw_node *rt_ofw_find_irq_parent(struct rt_ofw_node *np, int *out_interrupt_cells) { - rt_ofw_foreach_parent_node(np) + for (np = rt_ofw_node_get(np); np; np = rt_ofw_get_next_parent(np)) { rt_phandle ic_phandle; @@ -523,7 +526,7 @@ static int ofw_map_irq(struct rt_ofw_cell_args *irq_args) { int irq; struct rt_ofw_node *ic_np = irq_args->data; - struct rt_pic *pic = rt_ofw_data(ic_np); + struct rt_pic *pic = rt_pic_dynamic_cast(rt_ofw_data(ic_np)); /* args.data is "interrupt-controller" */ if (pic) @@ -611,7 +614,26 @@ int rt_ofw_get_irq(struct rt_ofw_node *np, int index) if (irq >= 0) { + rt_phandle cpu_phandle; + irq = ofw_map_irq(&irq_args); + + if (irq >= 0 && !rt_ofw_prop_read_u32_index(np, "interrupt-affinity", index, &cpu_phandle)) + { + rt_uint64_t cpuid = rt_ofw_get_cpu_id(rt_ofw_find_node_by_phandle(cpu_phandle)); + + if ((rt_int64_t)cpuid >= 0) + { + DECLARE_BITMAP(affinity, RT_CPUS_NR) = { 0 }; + + bitmap_set_bit(affinity, cpuid); + + if (rt_pic_irq_set_affinity(irq, affinity) == -RT_ENOSYS) + { + LOG_W("%s irq affinity init fail", np->full_name); + } + } + } } } else diff --git a/components/drivers/ofw/ofw.c b/components/drivers/ofw/ofw.c index 88a5fe963d04..3fa039e6a93b 100755 --- a/components/drivers/ofw/ofw.c +++ b/components/drivers/ofw/ofw.c @@ -16,6 +16,7 @@ #include #include "ofw_internal.h" +#include "../serial/serial_dm.h" struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np, const struct rt_ofw_stub *stub_start, const struct rt_ofw_stub *stub_end) @@ -96,7 +97,6 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con) if (platform_bus) { rt_device_t dev; - rt_ubase_t level; const char *console = con; int tty_idx = 0, tty_id = 0, tty_name_len; @@ -117,7 +117,7 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con) ++con; } - level = rt_spin_lock_irqsave(&platform_bus->spinlock); + rt_bus_lock(platform_bus); rt_list_for_each_entry(dev, &platform_bus->dev_list, node) { @@ -137,7 +137,7 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con) } } - rt_spin_unlock_irqrestore(&platform_bus->spinlock, level); + rt_bus_unlock(platform_bus); } return ofw_name; @@ -146,7 +146,7 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con) rt_err_t rt_ofw_console_setup(void) { rt_err_t err = -RT_ENOSYS; - char con_name[RT_NAME_MAX]; + char con_name[RT_NAME_MAX], *options = RT_NULL; const char *ofw_name = RT_NULL, *stdout_path, *con; /* chosen.console > chosen.stdout-path > RT_CONSOLE_DEVICE_NAME */ @@ -168,6 +168,19 @@ rt_err_t rt_ofw_console_setup(void) if (ofw_name) { + const char *ch = con; + + /* Find 'ttyX,BBBBPNF' */ + while (*ch && *ch != ' ') + { + if (*ch++ == ',') + { + options = (char *)ch; + + break; + } + } + err = RT_EOK; break; } @@ -208,6 +221,19 @@ rt_err_t rt_ofw_console_setup(void) rt_console_set_device(con); + /* Reconfigure serial by options */ + if (options) + { + rt_device_t con_dev = rt_console_get_device(); + + if (con_dev) + { + struct serial_configure con_conf = serial_cfg_from_args(options); + + rt_device_control(con_dev, RT_DEVICE_CTRL_CONFIG, &con_conf); + } + } + rt_fdt_earlycon_kick(FDT_EARLYCON_KICK_COMPLETED); LOG_I("Console: %s (%s)", con, ofw_name ? ofw_name : ""); @@ -252,6 +278,11 @@ const char *rt_ofw_bootargs_select(const char *key, int index) { *(char *)ch++ = '\0'; } + if (*ch == '\0') + { + /* space in the end */ + --bootargs_nr; + } --ch; } diff --git a/components/drivers/pci/Kconfig b/components/drivers/pci/Kconfig index 20e725e77aac..1ceb757728d0 100644 --- a/components/drivers/pci/Kconfig +++ b/components/drivers/pci/Kconfig @@ -1,6 +1,7 @@ menuconfig RT_USING_PCI bool "Using Peripheral Component Interconnect Express (PCIe/PCI)" depends on RT_USING_DM + depends on RT_USING_PIC default n config RT_PCI_MSI @@ -8,9 +9,28 @@ config RT_PCI_MSI depends on RT_USING_PCI default y +config RT_PCI_SYS_64BIT + bool "System 64bit" + depends on RT_USING_PCI + depends on ARCH_CPU_64BIT + default y + +config RT_PCI_CACHE_LINE_SIZE + int "Cache line size" + depends on RT_USING_PCI + default 8 if ARCH_CPU_64BIT + default 4 + +config RT_PCI_LOCKLESS + bool "Lock less in PCI options" + depends on RT_USING_PCI + default n + config RT_PCI_ECAM bool "PCIe ECAM" depends on RT_USING_PCI default y help PCIe Express Enhanced Configuration Access Mechanism + +source "$RTT_DIR/components/drivers/pci/host/Kconfig" diff --git a/components/drivers/pci/SConscript b/components/drivers/pci/SConscript new file mode 100644 index 000000000000..40a6cabb8fde --- /dev/null +++ b/components/drivers/pci/SConscript @@ -0,0 +1,28 @@ +from building import * + +objs = [] + +if not GetDepend(['RT_USING_PCI']): + Return('objs') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = ['access.c', 'host-bridge.c', 'irq.c', 'pci.c', 'probe.c'] + +if GetDepend(['RT_USING_OFW']): + src += ['ofw.c'] + +if GetDepend(['RT_PCI_ECAM']): + src += ['ecam.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/components/drivers/pci/access.c b/components/drivers/pci/access.c new file mode 100755 index 000000000000..9a389485a45d --- /dev/null +++ b/components/drivers/pci/access.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#include + +struct rt_spinlock rt_pci_lock = { 0 }; + +#ifdef RT_PCI_LOCKLESS +#define pci_lock_config(l) do { (void)(l); } while (0) +#define pci_unlock_config(l) do { (void)(l); } while (0) +#else +#define pci_lock_config(l) l = rt_spin_lock_irqsave(&rt_pci_lock) +#define pci_unlock_config(l) rt_spin_unlock_irqrestore(&rt_pci_lock, l) +#endif + +#define PCI_OPS_READ(name, type) \ +rt_err_t rt_pci_bus_read_config_##name(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, type *value) \ +{ \ + rt_err_t err; \ + rt_ubase_t level; \ + rt_uint32_t data = 0; \ + pci_lock_config(level); \ + err = bus->ops->read(bus, devfn, reg, sizeof(type), &data); \ + *value = err ? (type)(~0) : (type)data; \ + pci_unlock_config(level); \ + return err; \ +} + +#define PCI_OPS_WRITE(name, type) \ +rt_err_t rt_pci_bus_write_config_##name(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, type value) \ +{ \ + rt_err_t err; \ + rt_ubase_t level; \ + pci_lock_config(level); \ + err = bus->ops->write(bus, devfn, reg, sizeof(type), value); \ + pci_unlock_config(level); \ + return err; \ +} + +#define PCI_OPS(name, type) \ + PCI_OPS_READ(name, type) \ + PCI_OPS_WRITE(name, type) + +PCI_OPS(u8, rt_uint8_t) +PCI_OPS(u16, rt_uint16_t) +PCI_OPS(u32, rt_uint32_t) + +#undef PCI_OP_WRITE +#undef PCI_OP_READ +#undef PCI_OPS + +rt_err_t rt_pci_bus_read_config_uxx(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t *val) +{ + void *base; + + if ((base = bus->ops->map(bus, devfn, reg))) + { + if (width == 1) + { + *val = HWREG8(base); + } + else if (width == 2) + { + *val = HWREG16(base); + } + else + { + *val = HWREG32(base); + } + + return RT_EOK; + } + + return -RT_ERROR; +} + +rt_err_t rt_pci_bus_write_config_uxx(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, int width, rt_uint32_t val) +{ + void *base; + + if ((base = bus->ops->map(bus, devfn, reg))) + { + if (width == 1) + { + HWREG8(base) = val; + } + else if (width == 2) + { + HWREG16(base) = val; + } + else + { + HWREG32(base) = val; + } + + return RT_EOK; + } + + return -RT_ERROR; +} diff --git a/components/drivers/pci/ecam.c b/components/drivers/pci/ecam.c new file mode 100644 index 000000000000..559e0d8d5041 --- /dev/null +++ b/components/drivers/pci/ecam.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pci.ecam" +#define DBG_LVL DBG_INFO +#include + +#include "ecam.h" + +struct pci_ecam_config_window *pci_ecam_create(struct rt_pci_host_bridge *host_bridge, + const struct pci_ecam_ops *ops) +{ + struct pci_ecam_config_window *conf_win = rt_calloc(1, sizeof(*conf_win)); + + if (!conf_win) + { + return RT_NULL; + } + + conf_win->bus_range = host_bridge->bus_range; + conf_win->bus_shift = ops->bus_shift; + conf_win->ops = ops; + + host_bridge->ops = (struct rt_pci_ops *)&ops->pci_ops; + + return conf_win; +} + +void *pci_ecam_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int where) +{ + struct pci_ecam_config_window *conf_win = bus->sysdata; + const struct pci_ecam_ops *eops = conf_win->ops; + void *win = conf_win->win, *map; + rt_uint32_t busn = bus->number, bus_shift = eops->bus_shift, devfn_shift = eops->bus_shift - 8; + + if (eops->bus_shift) + { + rt_uint32_t bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift; + rt_uint32_t devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift; + + where &= PCIE_ECAM_REG_MASK; + map = win + (bus_offset | devfn_offset | where); + } + else + { + map = win + PCIE_ECAM_OFFSET(busn, devfn, where); + } + + return map; +} + +const struct pci_ecam_ops pci_generic_ecam_ops = +{ + .pci_ops = + { + .map = pci_ecam_map, + .read = rt_pci_bus_read_config_uxx, + .write = rt_pci_bus_write_config_uxx, + } +}; diff --git a/components/drivers/pci/ecam.h b/components/drivers/pci/ecam.h new file mode 100644 index 000000000000..dff28ce9c9d1 --- /dev/null +++ b/components/drivers/pci/ecam.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#ifndef __RT_PCI_ECAM_H__ +#define __RT_PCI_ECAM_H__ + +#include +#include +#include +#include + +/* + * Memory address shift values for the byte-level address that + * can be used when accessing the PCI Express Configuration Space. + */ + +/* + * Enhanced Configuration Access Mechanism (ECAM) + * + * See PCI Express Base Specification, Revision 5.0, Version 1.0, + * Section 7.2.2, Table 7-1, p. 677. + */ +#define PCIE_ECAM_BUS_SHIFT 20 /* Bus number */ +#define PCIE_ECAM_DEVFN_SHIFT 12 /* Device and Function number */ + +#define PCIE_ECAM_BUS_MASK 0xff +#define PCIE_ECAM_DEVFN_MASK 0xff +#define PCIE_ECAM_REG_MASK 0xfff /* Limit offset to a maximum of 4K */ + +#define PCIE_ECAM_BUS(x) (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT) +#define PCIE_ECAM_DEVFN(x) (((x) & PCIE_ECAM_DEVFN_MASK) << PCIE_ECAM_DEVFN_SHIFT) +#define PCIE_ECAM_REG(x) ((x) & PCIE_ECAM_REG_MASK) + +#define PCIE_ECAM_OFFSET(bus, devfn, where) \ + (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEVFN(devfn) | PCIE_ECAM_REG(where)) + +struct pci_ecam_ops +{ + rt_uint32_t bus_shift; + struct rt_pci_ops pci_ops; +}; + +struct pci_ecam_config_window +{ + rt_uint32_t *bus_range; + rt_uint32_t bus_shift; + + void *win; + void *priv; + const struct pci_ecam_ops *ops; +}; + +/* Default ECAM ops */ +extern const struct pci_ecam_ops pci_generic_ecam_ops; + +void *pci_ecam_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int where); +struct pci_ecam_config_window *pci_ecam_create(struct rt_pci_host_bridge *host_bridge, + const struct pci_ecam_ops *ops); +rt_err_t pci_host_common_probe(struct rt_platform_device *pdev); + +#endif /* __RT_PCI_ECAM_H__ */ diff --git a/components/drivers/pci/host-bridge.c b/components/drivers/pci/host-bridge.c new file mode 100644 index 000000000000..11067323f0cc --- /dev/null +++ b/components/drivers/pci/host-bridge.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include + +#include + +static rt_err_t host_bridge_probe(struct rt_pci_device *pdev) +{ + rt_err_t err = -RT_EINVAL; + + if (pdev->class >> 8 == PCIS_BRIDGE_HOST) + { + err = RT_EOK; + } + + return err; +} + +static struct rt_pci_device_id host_bridge_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0008) }, + { /* sentinel */ } +}; + +static struct rt_pci_driver host_bridge_driver = +{ + .name = "host-bridge", + + .ids = host_bridge_pci_ids, + .probe = host_bridge_probe, +}; +RT_PCI_DRIVER_EXPORT(host_bridge_driver); diff --git a/components/drivers/pci/host/Kconfig b/components/drivers/pci/host/Kconfig new file mode 100644 index 000000000000..446d6f2ef8df --- /dev/null +++ b/components/drivers/pci/host/Kconfig @@ -0,0 +1,12 @@ +config RT_PCI_HOST_COMMON + bool "Common PCI host controller" + depends on RT_PCI_ECAM + default y + +config RT_PCI_HOST_GENERIC + bool "Generic PCI host controller" + depends on RT_PCI_ECAM + select RT_PCI_HOST_COMMON + default y + +source "$RTT_DIR/components/drivers/pci/host/dw/Kconfig" diff --git a/components/drivers/pci/host/SConscript b/components/drivers/pci/host/SConscript new file mode 100644 index 000000000000..91555f88d4e1 --- /dev/null +++ b/components/drivers/pci/host/SConscript @@ -0,0 +1,25 @@ +from building import * + +objs = [] + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_PCI_HOST_COMMON']): + src += ['pci-host-common.c'] + +if GetDepend(['RT_PCI_HOST_GENERIC']): + src += ['pci-host-generic.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/components/drivers/pci/host/dw/Kconfig b/components/drivers/pci/host/dw/Kconfig new file mode 100644 index 000000000000..8928820faf7f --- /dev/null +++ b/components/drivers/pci/host/dw/Kconfig @@ -0,0 +1,13 @@ +config RT_PCI_DW_HOST + bool "DesignWare-based PCIe host" + depends on RT_USING_PCI + default n + +config RT_PCI_DW_HOST_ROCKCHIP + bool "Rockchip DesignWare PCIe host" + depends on RT_PCI_DW_HOST + select RT_USING_PHY + select RT_USING_RESET + select RT_MFD_SYSCON + select RT_USING_REGULATOR + default n diff --git a/components/drivers/pci/host/dw/SConscript b/components/drivers/pci/host/dw/SConscript new file mode 100644 index 000000000000..19100e7df7ba --- /dev/null +++ b/components/drivers/pci/host/dw/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_PCI_DW_HOST']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../../include'] + +src = ['pcie-dw.c', 'pcie-dw_ep.c', 'pcie-dw_host.c', 'pcie-dw_platfrom.c'] + +if GetDepend(['RT_PCI_DW_HOST_ROCKCHIP']): + src += ['pcie-dw-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/pci/host/dw/pcie-dw-rockchip.c b/components/drivers/pci/host/dw/pcie-dw-rockchip.c new file mode 100644 index 000000000000..9dce3978e16b --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw-rockchip.c @@ -0,0 +1,487 @@ +/* + * 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 + */ + +#define DBG_TAG "pci.dw.rockchip" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +/* + * The upper 16 bits of PCIE_CLIENT_CONFIG are a write + * mask for the lower 16 bits. + */ +#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val)) +#define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) +#define HIWORD_DISABLE_BIT(val) HIWORD_UPDATE(val, ~val) + +#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40) +#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc) +#define PCIE_SMLH_LINKUP RT_BIT(16) +#define PCIE_RDLH_LINKUP RT_BIT(17) +#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) +#define PCIE_L0S_ENTRY 0x11 +#define PCIE_CLIENT_GENERAL_CONTROL 0x0 +#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 +#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c +#define PCIE_CLIENT_GENERAL_DEBUG 0x104 +#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_CLIENT_LTSSM_STATUS 0x300 +#define PCIE_LTSSM_ENABLE_ENHANCE RT_BIT(4) +#define PCIE_LTSSM_STATUS_MASK RT_GENMASK(5, 0) + +struct rockchip_pcie +{ + struct dw_pcie pci; + void *apb_base; + + rt_base_t rst_pin; + struct rt_phy_device *phy; + struct rt_clk_array *clk_arr; + struct rt_reset_control *rstc; + struct rt_regulator *vpcie3v3; + + int intx_irq; + struct rt_pic intx_pic; +}; + +#define to_rockchip_pcie(dw_pcie) rt_container_of(dw_pcie, struct rockchip_pcie, pci) + +rt_inline rt_uint32_t rockchip_pcie_readl_apb(struct rockchip_pcie *rk_pcie, + int offset) +{ + return HWREG32(rk_pcie->apb_base + offset); +} + +rt_inline void rockchip_pcie_writel_apb(struct rockchip_pcie *rk_pcie, + rt_uint32_t val, int offset) +{ + HWREG32(rk_pcie->apb_base + offset) = val; +} + +static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rk_pcie) +{ + rockchip_pcie_writel_apb(rk_pcie, PCIE_CLIENT_ENABLE_LTSSM, + PCIE_CLIENT_GENERAL_CONTROL); +} + +static rt_bool_t rockchip_pcie_link_up(struct dw_pcie *pci) +{ + rt_uint32_t val; + struct rockchip_pcie *rk_pcie = to_rockchip_pcie(pci); + + val = rockchip_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS); + + if ((val & PCIE_LINKUP) == PCIE_LINKUP && + (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY) + { + return RT_TRUE; + } + + return RT_FALSE; +} + +static rt_err_t rockchip_pcie_start_link(struct dw_pcie *pci) +{ + struct rockchip_pcie *rk_pcie = to_rockchip_pcie(pci); + + /* Reset device */ + if (rk_pcie->rst_pin >= 0) + { + rt_pin_write(rk_pcie->rst_pin, PIN_LOW); + } + + rockchip_pcie_enable_ltssm(rk_pcie); + + /* + * PCIe requires the refclk to be stable for 100µs prior to releasing + * PERST. See table 2-4 in section 2.6.2 AC Specifications of the PCI + * Express Card Electromechanical Specification, 1.1. However, we don't + * know if the refclk is coming from RC's PHY or external OSC. If it's + * from RC, so enabling LTSSM is the just right place to release #PERST. + * We need more extra time as before, rather than setting just + * 100us as we don't know how long should the device need to reset. + */ + rt_thread_mdelay(100); + + if (rk_pcie->rst_pin >= 0) + { + rt_pin_write(rk_pcie->rst_pin, PIN_HIGH); + } + + return RT_EOK; +} + +static const struct dw_pcie_ops dw_pcie_ops = +{ + .link_up = rockchip_pcie_link_up, + .start_link = rockchip_pcie_start_link, +}; + +static void rockchip_pcie_intx_mask(struct rt_pic_irq *pirq) +{ + struct rockchip_pcie *rk_pcie = pirq->pic->priv_data; + + rockchip_pcie_writel_apb(rk_pcie, HIWORD_UPDATE_BIT(RT_BIT(pirq->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +} + +static void rockchip_pcie_intx_unmask(struct rt_pic_irq *pirq) +{ + struct rockchip_pcie *rk_pcie = pirq->pic->priv_data; + + rockchip_pcie_writel_apb(rk_pcie, HIWORD_DISABLE_BIT(RT_BIT(pirq->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +} + +static int rockchip_intx_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + if (pirq->irq >= 0) + { + irq = pirq->irq; + } + else + { + struct rockchip_pcie *rk_pcie = pic->priv_data; + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + rt_pic_cascade(pirq, rk_pcie->intx_irq); + rt_pic_irq_set_triger_mode(irq, mode); + } + } + else + { + irq = -1; + } + + return irq; +} + +static rt_err_t rockchip_intx_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 == 1) + { + out_pirq->hwirq = args->args[1]; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static struct rt_pic_ops rockchip_intx_ops = +{ + .name = "RK-INTx", + .irq_mask = rockchip_pcie_intx_mask, + .irq_unmask = rockchip_pcie_intx_unmask, + .irq_map = rockchip_intx_irq_map, + .irq_parse = rockchip_intx_irq_parse, +}; + +static void rk_pcie_intx_isr(int irqno, void *param) +{ + rt_uint32_t ints; + struct rt_pic_irq *pirq; + struct rockchip_pcie *rk_pcie = param; + + ints = rockchip_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_LEGACY); + + for (int pin = 0; ints && pin < RT_PCI_INTX_PIN_MAX; ++pin, ints >>= 1) + { + if ((ints & 1)) + { + pirq = rt_pic_find_irq(&rk_pcie->intx_pic, pin); + + rt_pic_handle_isr(pirq); + } + } +} + +static rt_err_t rockchip_pcie_init_irq(struct rockchip_pcie *rk_pcie) +{ + struct rt_ofw_node *np = rk_pcie->pci.dev->ofw_node, *intx_np; + struct rt_pic *intx_pic = &rk_pcie->intx_pic; + + intx_np = rt_ofw_get_child_by_tag(np, "legacy-interrupt-controller"); + + if (!intx_np) + { + LOG_E("INTx ofw node not found"); + + return -RT_EIO; + } + + rk_pcie->intx_irq = rt_ofw_get_irq(intx_np, 0); + + rt_ofw_node_put(intx_np); + + if (rk_pcie->intx_irq < 0) + { + rk_pcie->intx_irq = rt_ofw_get_irq_by_name(np, "legacy"); + } + + if (rk_pcie->intx_irq < 0) + { + LOG_E("INTx irq get fail"); + + return rk_pcie->intx_irq; + } + + intx_pic->priv_data = rk_pcie; + intx_pic->ops = &rockchip_intx_ops; + + rt_pic_linear_irq(intx_pic, RT_PCI_INTX_PIN_MAX); + + rt_pic_user_extends(intx_pic); + + rt_ofw_data(np) = intx_pic; + + rt_hw_interrupt_install(rk_pcie->intx_irq, rk_pcie_intx_isr, rk_pcie, "rk-pcie-INTx"); + rt_hw_interrupt_umask(rk_pcie->intx_irq); + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_host_init(struct dw_pcie_rp *pp) +{ + rt_err_t err; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct rockchip_pcie *rk_pcie = to_rockchip_pcie(pci); + rt_uint32_t val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); + + if ((err = rockchip_pcie_init_irq(rk_pcie))) + { + return err; + } + + /* LTSSM enable control mode */ + rockchip_pcie_writel_apb(rk_pcie, val, PCIE_CLIENT_HOT_RESET_CTRL); + rockchip_pcie_writel_apb(rk_pcie, PCIE_CLIENT_RC_MODE, PCIE_CLIENT_GENERAL_CONTROL); + + return RT_EOK; +} + +static const struct dw_pcie_host_ops rockchip_pcie_host_ops = +{ + .host_init = rockchip_pcie_host_init, +}; + +static rt_err_t rockchip_pcie_phy_init(struct rockchip_pcie *rk_pcie) +{ + rt_phy_status phy_status; + struct rt_device *dev = rk_pcie->pci.dev; + + rk_pcie->phy = rt_phy_get_by_name(dev, "pcie-phy"); + if (!rk_pcie->phy) + { + LOG_E("Missing PHY"); + return -RT_ERROR; + } + + phy_status = rt_phy_init(rk_pcie->phy, RT_NULL, 0, 0); + if (phy_status) + { + rk_pcie->phy = RT_NULL; + LOG_E("%s PHY fail", "Init"); + + return -RT_EIO; + } + + phy_status = rt_phy_power_on(rk_pcie->phy); + if (phy_status) + { + rt_phy_exit(rk_pcie->phy, RT_NULL, 0); + rk_pcie->phy = RT_NULL; + + LOG_E("%s PHY fail", "Power on"); + + return -RT_EIO; + } + + return RT_EOK; +} + +static rt_err_t rockchip_pcie_resource_init(struct rockchip_pcie *rk_pcie) +{ + struct rt_device *dev = rk_pcie->pci.dev; + + rk_pcie->apb_base = rt_dm_dev_iomap_by_name(dev, "apb"); + if (!rk_pcie->apb_base) + { + rk_pcie->apb_base = rt_dm_dev_iomap_by_name(dev, "pcie-apb"); + } + + if (!rk_pcie->apb_base) + { + return -RT_EIO; + } + + rk_pcie->rst_pin = rt_pin_get_named_pin(dev, "reset", 0, RT_NULL, RT_NULL); + if (rk_pcie->rst_pin < 0 && rk_pcie->rst_pin != -RT_EEMPTY) + { + return (rt_err_t)rk_pcie->rst_pin; + } + + if (rk_pcie->rst_pin >= 0) + { + rt_pin_mode(rk_pcie->rst_pin, PIN_MODE_OUTPUT); + rt_pin_write(rk_pcie->rst_pin, PIN_HIGH); + } + + if (rt_dm_dev_prop_read_bool(dev, "resets")) + { + rk_pcie->rstc = rt_reset_control_get_array(dev); + + if (!rk_pcie->rstc) + { + return -RT_EIO; + } + } + + return RT_EOK; +} + +static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rk_pcie) +{ + rt_phy_exit(rk_pcie->phy, RT_NULL, 0); + rt_phy_power_off(rk_pcie->phy); +} + +static rt_err_t rockchip_pcie_clk_init(struct rockchip_pcie *rk_pcie) +{ + struct rt_device *dev = rk_pcie->pci.dev; + + rk_pcie->clk_arr = rt_clk_get_array(dev); + if (!rk_pcie->clk_arr) + { + return -RT_EIO; + } + + return rt_clk_array_prepare_enable(rk_pcie->clk_arr); +} + +static void rockchip_pcie_remove(struct rockchip_pcie *rk_pcie) +{ + if (rk_pcie->apb_base) + { + rt_iounmap(rk_pcie->apb_base); + } + + if (rk_pcie->rstc) + { + rt_reset_control_put(rk_pcie->rstc); + } + + if (rk_pcie->vpcie3v3) + { + rt_regulator_disable(rk_pcie->vpcie3v3); + } + + if (rk_pcie->phy) + { + rockchip_pcie_phy_deinit(rk_pcie); + } + + if (rk_pcie->clk_arr) + { + rt_clk_array_disable_unprepare(rk_pcie->clk_arr); + rt_clk_array_put(rk_pcie->clk_arr); + } + + rt_free(rk_pcie); +} + +static rt_err_t rockchip_pcie_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct rockchip_pcie *rk_pcie = rt_calloc(1, sizeof(*rk_pcie)); + + if (!rk_pcie) + { + return -RT_EINVAL; + } + + rk_pcie->pci.dev = dev; + rk_pcie->pci.ops = &dw_pcie_ops; + rk_pcie->pci.pp.ops = &rockchip_pcie_host_ops; + + if ((err = rockchip_pcie_resource_init(rk_pcie))) + { + goto _free_res; + } + + if ((err = rt_reset_control_assert(rk_pcie->rstc))) + { + goto _free_res; + } + + rk_pcie->vpcie3v3 = rt_regulator_get_optional(dev, "vpcie3v3"); + + if (rk_pcie->vpcie3v3) + { + if ((err = rt_regulator_enable(rk_pcie->vpcie3v3))) + { + goto _free_res; + } + } + + if ((err = rockchip_pcie_phy_init(rk_pcie))) + { + goto _free_res; + } + + if ((err = rt_reset_control_deassert(rk_pcie->rstc))) + { + goto _free_res; + } + + if ((err = rockchip_pcie_clk_init(rk_pcie))) + { + goto _free_res; + } + + if ((err = dw_pcie_host_init(&rk_pcie->pci.pp))) + { + goto _free_res; + } + + return RT_EOK; + +_free_res: + rockchip_pcie_remove(rk_pcie); + + return err; +} + +static const struct rt_ofw_node_id rockchip_pcie_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-pcie" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pcie_driver = +{ + .name = "rockchip-dw-pcie", + .ids = rockchip_pcie_ofw_ids, + + .probe = rockchip_pcie_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_pcie_driver); diff --git a/components/drivers/pci/host/dw/pcie-dw.c b/components/drivers/pci/host/dw/pcie-dw.c new file mode 100644 index 000000000000..36dbe4ba208d --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw.c @@ -0,0 +1,16 @@ +/* + * 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 "pcie-dw.h" + +rt_err_t dw_pcie_host_init(struct dw_pcie_rp *pp) +{ + return RT_EOK; +} diff --git a/components/drivers/pci/host/dw/pcie-dw.h b/components/drivers/pci/host/dw/pcie-dw.h new file mode 100644 index 000000000000..26f572f52451 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw.h @@ -0,0 +1,96 @@ +/* + * 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 + */ + +#ifndef __PCIE_DESIGNWARE_H__ +#define __PCIE_DESIGNWARE_H__ + +#include +#include + +struct dw_pcie_ops; +struct dw_pcie_host_ops; + +struct dw_pcie_rp +{ + rt_bool_t has_msi_ctrl:1; + rt_bool_t cfg0_io_shared:1; + + rt_uint64_t cfg0_base; + void *va_cfg0_base; + rt_uint32_t cfg0_size; + + rt_size_t io_base; + rt_ubase_t io_bus_addr; + rt_uint32_t io_size; + + int irq; + const struct dw_pcie_host_ops *ops; +}; + +struct dw_pcie_host_ops +{ + rt_err_t (*host_init)(struct dw_pcie_rp *pp); + void (*host_deinit)(struct dw_pcie_rp *pp); + rt_err_t (*msi_host_init)(struct dw_pcie_rp *pp); +}; + +struct dw_pcie_ep +{ + const struct dw_pcie_ep_ops *ops; + + rt_ubase_t phys_base; + rt_size_t addr_size; + rt_size_t page_size; + rt_uint8_t bar_to_atu[PCI_STD_NUM_BARS]; + rt_ubase_t *outbound_addr; + rt_ubase_t *ib_window_map; + rt_ubase_t *ob_window_map; + void *msi_mem; + rt_ubase_t msi_mem_phys; +}; + +struct dw_pcie +{ + struct rt_device *dev; + + void *dbi_base; + void *dbi_base2; + void *atu_base; + + rt_size_t atu_size; + rt_uint32_t num_ib_windows; + rt_uint32_t num_ob_windows; + rt_uint32_t region_align; + rt_uint64_t region_limit; + + struct dw_pcie_rp pp; + struct dw_pcie_ep ep; + const struct dw_pcie_ops *ops; + + void *priv; +}; + +struct dw_pcie_ops +{ + rt_uint64_t (*cpu_addr_fixup)(struct dw_pcie *pcie, rt_uint64_t cpu_addr); + rt_uint32_t (*read_dbi)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size); + void (*write_dbi)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); + void (*write_dbi2)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); + rt_bool_t (*link_up)(struct dw_pcie *pcie); + rt_err_t (*start_link)(struct dw_pcie *pcie); + void (*stop_link)(struct dw_pcie *pcie); +}; + +#define to_dw_pcie_from_pp(port) rt_container_of((port), struct dw_pcie, pp) +#define to_dw_pcie_from_ep(endpoint) rt_container_of((endpoint), struct dw_pcie, ep) + +rt_err_t dw_pcie_host_init(struct dw_pcie_rp *pp); + +#endif /* __PCIE_DESIGNWARE_H__ */ diff --git a/components/drivers/pci/host/dw/pcie-dw_ep.c b/components/drivers/pci/host/dw/pcie-dw_ep.c new file mode 100644 index 000000000000..ba89ddaf28e6 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_ep.c @@ -0,0 +1,9 @@ +/* + * 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 + */ \ No newline at end of file diff --git a/components/drivers/pci/host/dw/pcie-dw_host.c b/components/drivers/pci/host/dw/pcie-dw_host.c new file mode 100644 index 000000000000..ba89ddaf28e6 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_host.c @@ -0,0 +1,9 @@ +/* + * 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 + */ \ No newline at end of file diff --git a/components/drivers/pci/host/dw/pcie-dw_platfrom.c b/components/drivers/pci/host/dw/pcie-dw_platfrom.c new file mode 100644 index 000000000000..ba89ddaf28e6 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_platfrom.c @@ -0,0 +1,9 @@ +/* + * 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 + */ \ No newline at end of file diff --git a/components/drivers/pci/host/pci-host-common.c b/components/drivers/pci/host/pci-host-common.c new file mode 100644 index 000000000000..bfc409e76aa1 --- /dev/null +++ b/components/drivers/pci/host/pci-host-common.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include + +#include "../ecam.h" + +rt_err_t pci_host_common_probe(struct rt_platform_device *pdev) +{ + void *base; + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct pci_ecam_config_window *conf_win; + struct rt_pci_host_bridge *host_bridge = rt_pci_host_bridge_alloc(0); + + if (!host_bridge) + { + return -RT_ENOMEM; + } + + if (!(base = rt_dm_dev_iomap(dev, 0))) + { + err = -RT_EIO; + goto _fail; + } + + host_bridge->parent.ofw_node = dev->ofw_node; + host_bridge->sysdata = conf_win = pci_ecam_create(host_bridge, + (const struct pci_ecam_ops *)pdev->id->data); + + if (!conf_win) + { + err = -RT_ENOMEM; + goto _fail; + } + + conf_win->win = base; + conf_win->priv = host_bridge; + + if ((err = rt_pci_host_bridge_init(host_bridge))) + { + goto _fail; + } + + if ((err = rt_pci_host_bridge_probe(host_bridge))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (base) + { + rt_iounmap(base); + } + rt_free(host_bridge); + + return err; +} + diff --git a/components/drivers/pci/host/pci-host-generic.c b/components/drivers/pci/host/pci-host-generic.c new file mode 100644 index 000000000000..5d497c48f4d1 --- /dev/null +++ b/components/drivers/pci/host/pci-host-generic.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include + +#include "../ecam.h" + +static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = +{ + .bus_shift = 16, + .pci_ops = + { + .map = pci_ecam_map, + .read = rt_pci_bus_read_config_uxx, + .write = rt_pci_bus_write_config_uxx, + } +}; + +static void *pci_dw_ecam_map_bus(struct rt_pci_bus *bus, rt_uint32_t devfn, int where) +{ + struct pci_ecam_config_window *conf_win = bus->sysdata; + + if (bus->number == conf_win->bus_range[0] && RT_PCI_SLOT(devfn) > 0) + { + return RT_NULL; + } + + return pci_ecam_map(bus, devfn, where); +} + +static const struct pci_ecam_ops pci_dw_ecam_bus_ops = +{ + .pci_ops = + { + .map = pci_dw_ecam_map_bus, + .read = rt_pci_bus_read_config_uxx, + .write = rt_pci_bus_write_config_uxx, + } +}; + +static const struct rt_ofw_node_id gen_pci_ofw_ids[] = +{ + { .compatible = "pci-host-cam-generic", .data = &gen_pci_cfg_cam_bus_ops }, + { .compatible = "pci-host-ecam-generic", .data = &pci_generic_ecam_ops }, + { .compatible = "marvell,armada8k-pcie-ecam", .data = &pci_dw_ecam_bus_ops }, + { .compatible = "socionext,synquacer-pcie-ecam", .data = &pci_dw_ecam_bus_ops }, + { .compatible = "snps,dw-pcie-ecam", .data = &pci_dw_ecam_bus_ops }, + { /* sentinel */ } +}; + +static struct rt_platform_driver gen_pci_driver = +{ + .name = "pci-host-generic", + .ids = gen_pci_ofw_ids, + + .probe = pci_host_common_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(gen_pci_driver); diff --git a/components/drivers/pci/irq.c b/components/drivers/pci/irq.c new file mode 100644 index 000000000000..c344e2cc0a7d --- /dev/null +++ b/components/drivers/pci/irq.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "pci.irq" +#define DBG_LVL DBG_INFO +#include + +#include + +void rt_pci_assign_irq(struct rt_pci_device *pdev) +{ + int irq = 0; + rt_uint8_t pin, slot = -1; + struct rt_pci_host_bridge *host_bridge = rt_pci_find_host_bridge(pdev->bus); + + if (!host_bridge->irq_map) + { + LOG_D("PCI-Device<%s> runtime IRQ mapping not provided by platform", + rt_dm_dev_get_name(&pdev->parent)); + + return; + } + + /* Must try the swizzle when interrupt line passes through a P2P bridge */ + rt_pci_read_config_u8(pdev, PCIR_INTPIN, &pin); + + if (pin > RT_PCI_INTX_PIN_MAX) + { + pin = 1; + } + + if (pin) + { + if (host_bridge->irq_slot) + { + slot = host_bridge->irq_slot(pdev, &pin); + } + + /* Map IRQ */ + if ((irq = host_bridge->irq_map(pdev, slot, pin)) == -1) + { + irq = 0; + } + } + pdev->irq = irq; + + LOG_D("PCI-Device<%s> assign IRQ: got %d", rt_dm_dev_get_name(&pdev->parent), pdev->irq); + + /* Save IRQ */ + rt_pci_write_config_u8(pdev, PCIR_INTLINE, irq); +} + diff --git a/components/drivers/pci/msi/SConscript b/components/drivers/pci/msi/SConscript new file mode 100644 index 000000000000..3fc141d68dff --- /dev/null +++ b/components/drivers/pci/msi/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_PCI_MSI']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = ['msi.c', 'msi_dev.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/pci/msi/msi.c b/components/drivers/pci/msi/msi.c new file mode 100644 index 000000000000..274202cb3a42 --- /dev/null +++ b/components/drivers/pci/msi/msi.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "pci.msi" +#define DBG_LVL DBG_INFO +#include + +void rt_pci_msi_mask_irq(struct rt_pic_irq *pirq) +{ +} + +void rt_pci_msi_unmask_irq(struct rt_pic_irq *pirq) +{ +} diff --git a/components/drivers/pci/msi/msi_dev.c b/components/drivers/pci/msi/msi_dev.c new file mode 100644 index 000000000000..c03237a9a20d --- /dev/null +++ b/components/drivers/pci/msi/msi_dev.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include + +void rt_pci_msi_init(struct rt_pci_device *pdev) +{ + if (pdev && (pdev->msi_cap = rt_pci_find_capability(pdev, PCIY_MSI))) + { + rt_uint16_t ctrl; + + rt_pci_read_config_u16(pdev, pdev->msi_cap + PCIR_MSI_CTRL, &ctrl); + + if (ctrl & PCIM_MSICTRL_MSI_ENABLE) + { + rt_pci_write_config_u16(pdev, pdev->msi_cap + PCIR_MSI_CTRL, ctrl & ~PCIM_MSICTRL_MSI_ENABLE); + } + + if (!(ctrl & PCIM_MSICTRL_64BIT)) + { + rt_pci_device_set_flag(pdev, PCI_F_NO_64BIT_MSI); + } + } +} + +void rt_pci_msix_init(struct rt_pci_device *pdev) +{ + if (pdev && (pdev->msix_cap = rt_pci_find_capability(pdev, PCIY_MSIX))) + { + rt_uint16_t ctrl; + + rt_pci_read_config_u16(pdev, pdev->msix_cap + PCIR_MSIX_CTRL, &ctrl); + + if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) + { + rt_pci_write_config_u16(pdev, pdev->msix_cap + PCIR_MSIX_CTRL, ctrl & ~PCIM_MSIXCTRL_MSIX_ENABLE); + } + } +} diff --git a/components/drivers/pci/ofw.c b/components/drivers/pci/ofw.c new file mode 100644 index 000000000000..79e2d3c95d9d --- /dev/null +++ b/components/drivers/pci/ofw.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pci.ofw" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include +#include +#include + +static rt_err_t pci_ofw_irq_parse(struct rt_pci_device *pdev, struct rt_ofw_cell_args *out_irq) +{ + rt_err_t err = RT_EOK; + rt_uint8_t pin; + fdt32_t map_addr[4]; + struct rt_pci_device *p2pdev; + struct rt_ofw_node *dev_np, *p2pnode = RT_NULL; + + /* Parse device tree if dev have a device node */ + dev_np = pdev->parent.ofw_node; + + if (dev_np) + { + err = rt_ofw_parse_irq_cells(dev_np, 0, out_irq); + + if (err) + { + return err; + } + } + + /* Assume #interrupt-cells is 1 */ + if ((err = rt_pci_read_config_u8(pdev, PCIR_INTPIN, &pin))) + { + goto _err; + } + + /* No pin, exit with no error message. */ + if (pin == 0) + { + return -RT_ENOSYS; + } + + /* Try local interrupt-map in the device node */ + if (rt_ofw_prop_read_raw(dev_np, "interrupt-map", RT_NULL)) + { + pin = rt_pci_irq_intx(pdev, pin); + p2pnode = dev_np; + } + + /* Walk up the PCI tree */ + while (!p2pnode) + { + p2pdev = pdev->bus->self; + + /* Is the root bus -> host bridge */ + if (rt_pci_is_root_bus(pdev->bus)) + { + struct rt_pci_host_bridge *host_bridge = pdev->bus->host_bridge; + + p2pnode = host_bridge->parent.ofw_node; + + if (!p2pnode) + { + err = -RT_EINVAL; + + goto _err; + } + } + else + { + /* Is P2P bridge */ + p2pnode = p2pdev->parent.ofw_node; + } + + if (p2pnode) + { + break; + } + + /* Try get INTx in P2P */ + pin = rt_pci_irq_intx(pdev, pin); + pdev = p2pdev; + } + + /* For more format detail, please read `components/drivers/ofw/irq.c:ofw_parse_irq_map` */ + out_irq->data = map_addr; + out_irq->args_count = 2; + out_irq->args[0] = 3; + out_irq->args[1] = 1; + + /* In addr cells */ + map_addr[0] = cpu_to_fdt32((pdev->bus->number << 16) | (pdev->devfn << 8)); + map_addr[1] = cpu_to_fdt32(0); + map_addr[2] = cpu_to_fdt32(0); + /* In pin cells */ + map_addr[3] = cpu_to_fdt32(pin); + + err = rt_ofw_parse_irq_map(p2pnode, out_irq); + +_err: + if (err == -RT_EEMPTY) + { + LOG_W("PCI-Device<%s> no interrupt-map found, INTx interrupts not available", + rt_dm_dev_get_name(&pdev->parent)); + LOG_W("PCI-Device<%s> possibly some PCI slots don't have level triggered interrupts capability", + rt_dm_dev_get_name(&pdev->parent)); + } + else if (err && err != -RT_ENOSYS) + { + LOG_E("PCI-Device<%s> irq parse failed with err = %s", + rt_dm_dev_get_name(&pdev->parent), rt_strerror(err)); + } + + return err; +} + +int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev, rt_uint8_t slot, rt_uint8_t pin) +{ + int irq = -1; + rt_err_t status; + struct rt_ofw_cell_args irq_args; + + if (!pdev) + { + goto _end; + } + + status = pci_ofw_irq_parse(pdev, &irq_args); + + if (status) + { + goto _end; + } + + irq = rt_ofw_map_irq(&irq_args); + +_end: + return irq; +} + +rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge) +{ + const fdt32_t *cell; + rt_ssize_t total_cells; + int groups, space_code; + rt_uint32_t phy_addr[3]; + rt_uint64_t cpu_addr, phy_addr_size; + int phy_addr_cells = -1, phy_size_cells = -1, cpu_addr_cells; + + if (!dev_np || !host_bridge) + { + return -RT_EINVAL; + } + + cpu_addr_cells = rt_ofw_io_addr_cells(dev_np); + rt_ofw_prop_read_s32(dev_np, "#address-cells", &phy_addr_cells); + rt_ofw_prop_read_s32(dev_np, "#size-cells", &phy_size_cells); + + if (phy_addr_cells != 3 || phy_size_cells < 1 || cpu_addr_cells < 1) + { + return -RT_EINVAL; + } + + cell = rt_ofw_prop_read_raw(dev_np, "ranges", &total_cells); + + if (!cell) + { + return -RT_EINVAL; + } + + groups = total_cells / sizeof(*cell) / (phy_addr_cells + phy_size_cells + cpu_addr_cells); + host_bridge->bus_regions = rt_malloc(groups * sizeof(struct rt_pci_bus_region)); + + if (!host_bridge->bus_regions) + { + return -RT_ENOMEM; + } + + host_bridge->bus_regions_nr = 0; + + for (int i = 0; i < groups; ++i) + { + /* + * ranges: + * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr + * phys.low cell: llllllll llllllll llllllll llllllll + * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh + * + * n: relocatable region flag (doesn't play a role here) + * p: prefetchable (cacheable) region flag + * t: aliased address flag (doesn't play a role here) + * ss: space code + * 00: configuration space + * 01: I/O space + * 10: 32 bit memory space + * 11: 64 bit memory space + * bbbbbbbb: The PCI bus number + * ddddd: The device number + * fff: The function number. Used for multifunction PCI devices. + * rrrrrrrr: Register number; used for configuration cycles. + */ + + for (int j = 0; j < phy_addr_cells; ++j) + { + phy_addr[j] = rt_fdt_read_number(cell++, 1); + } + + space_code = (phy_addr[0] >> 24) & 0x3; + + cpu_addr = rt_fdt_read_number(cell, cpu_addr_cells); + cell += cpu_addr_cells; + phy_addr_size = rt_fdt_read_number(cell, phy_size_cells); + cell += phy_size_cells; + + host_bridge->bus_regions[i].phy_addr = ((rt_uint64_t)phy_addr[1] << 32) | phy_addr[2]; + host_bridge->bus_regions[i].cpu_addr = cpu_addr; + host_bridge->bus_regions[i].size = phy_addr_size; + + host_bridge->bus_regions[i].bus_start = host_bridge->bus_regions[i].phy_addr; + + if (space_code & 2) + { + host_bridge->bus_regions[i].flags = phy_addr[0] & (1U << 30) ? + PCI_BUS_REGION_F_PREFETCH : PCI_BUS_REGION_F_MEM; + } + else if (space_code & 1) + { + host_bridge->bus_regions[i].flags = PCI_BUS_REGION_F_IO; + } + else + { + continue; + } + + ++host_bridge->bus_regions_nr; + } + + return rt_pci_region_setup(host_bridge); +} + +rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np, struct rt_pci_host_bridge *host_bridge) +{ + rt_err_t err; + + if (!dev_np || !host_bridge) + { + return -RT_EINVAL; + } + + host_bridge->irq_slot = rt_pci_irq_slot; + host_bridge->irq_map = rt_pci_ofw_irq_parse_and_map; + + if (rt_ofw_prop_read_u32_array_index(dev_np, "bus-range", 0, 2, host_bridge->bus_range) < 0) + { + return -RT_EIO; + } + + if (rt_ofw_prop_read_u32(dev_np, "linux,pci-domain", &host_bridge->domain) < 0) + { + rt_ofw_prop_read_u32(dev_np, "rt-thread,pci-domain", &host_bridge->domain); + } + err = rt_pci_ofw_parse_ranges(dev_np, host_bridge); + + return err; +} + +rt_err_t rt_pci_ofw_bus_init(struct rt_pci_bus *bus) +{ + rt_err_t err = RT_EOK; + + return err; +} + +rt_err_t rt_pci_ofw_device_init(struct rt_pci_device *pdev) +{ + struct rt_ofw_node *np = RT_NULL; + + if (!pdev) + { + return -RT_EINVAL; + } + + if (pdev->bus->parent) + { + np = pdev->bus->self->parent.ofw_node; + } + + if (!np) + { + return RT_EOK; + } + + pdev->parent.ofw_node = np; + + return RT_EOK; +} diff --git a/components/drivers/pci/pci.c b/components/drivers/pci/pci.c new file mode 100644 index 000000000000..b73e3ecb960d --- /dev/null +++ b/components/drivers/pci/pci.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "rtdm.pci" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +rt_uint32_t rt_pci_domain(struct rt_pci_device *pdev) +{ + struct rt_pci_host_bridge *host_bridge; + + if (!pdev) + { + return RT_UINT32_MAX; + } + + if ((host_bridge = rt_pci_find_host_bridge(pdev->bus))) + { + return host_bridge->domain; + } + + return RT_UINT32_MAX; +} + +static rt_uint8_t pci_find_next_cap_ttl(struct rt_pci_bus *bus, rt_uint32_t devfn, rt_uint8_t pos, int cap, int *ttl) +{ + rt_uint8_t ret = 0, id; + rt_uint16_t ent; + + rt_pci_bus_read_config_u8(bus, devfn, pos, &pos); + + while ((*ttl)--) + { + if (pos < 0x40) + { + break; + } + + pos &= ~3; + rt_pci_bus_read_config_u16(bus, devfn, pos, &ent); + + id = ent & 0xff; + if (id == 0xff) + { + break; + } + if (id == cap) + { + ret = pos; + break; + } + pos = (ent >> 8); + } + + return ret; +} + +static rt_uint8_t pci_find_next_cap(struct rt_pci_bus *bus, rt_uint32_t devfn, rt_uint8_t pos, int cap) +{ + int ttl = RT_PCI_FIND_CAP_TTL; + + return pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); +} + +static rt_uint8_t pci_bus_find_cap_start(struct rt_pci_bus *bus, rt_uint32_t devfn, rt_uint8_t hdr_type) +{ + rt_uint8_t res = 0; + rt_uint16_t status; + + rt_pci_bus_read_config_u16(bus, devfn, PCIR_STATUS, &status); + + if (status & PCIM_STATUS_CAPPRESENT) + { + switch (hdr_type) + { + case PCIM_HDRTYPE_NORMAL: + case PCIM_HDRTYPE_BRIDGE: + res = PCIR_CAP_PTR; + break; + + case PCIM_HDRTYPE_CARDBUS: + res = PCIR_CAP_PTR_2; + break; + } + } + + return res; +} + +rt_uint8_t rt_pci_bus_find_capability(struct rt_pci_bus *bus, rt_uint32_t devfn, int cap) +{ + rt_uint8_t hdr_type, ret = RT_UINT8_MAX; + + if (bus) + { + rt_pci_bus_read_config_u8(bus, devfn, PCIR_HDRTYPE, &hdr_type); + + ret = pci_bus_find_cap_start(bus, devfn, hdr_type & PCIM_HDRTYPE); + + if (ret) + { + ret = pci_find_next_cap(bus, devfn, ret, cap); + } + } + + return ret; +} + +rt_uint8_t rt_pci_find_capability(struct rt_pci_device *pdev, int cap) +{ + rt_uint8_t res = RT_UINT8_MAX; + + if (pdev) + { + res = pci_bus_find_cap_start(pdev->bus, pdev->devfn, pdev->hdr_type); + + if (res) + { + res = pci_find_next_cap(pdev->bus, pdev->devfn, res, cap); + } + } + + return res; +} + +rt_uint8_t rt_pci_find_next_capability(struct rt_pci_device *pdev, rt_uint8_t pos, int cap) +{ + rt_uint8_t res = RT_UINT8_MAX; + + if (pdev) + { + res = pci_find_next_cap(pdev->bus, pdev->devfn, pos + PCICAP_NEXTPTR, cap); + } + + return res; +} + +void rt_pci_intx(struct rt_pci_device *pdev, rt_bool_t enable) +{ + rt_uint16_t pci_command, new; + + if (!pdev) + { + return; + } + + rt_pci_read_config_u16(pdev, PCIR_COMMAND, &pci_command); + + if (enable) + { + new = pci_command & ~PCIM_CMD_INTxDIS; + } + else + { + new = pci_command | PCIM_CMD_INTxDIS; + } + + if (new != pci_command) + { + rt_pci_write_config_u16(pdev, PCIR_COMMAND, new); + } +} + +static rt_bool_t pci_check_and_set_intx_mask(struct rt_pci_device *pdev, rt_bool_t mask) +{ + rt_ubase_t level; + rt_bool_t irq_pending; + rt_bool_t res = RT_TRUE; + rt_uint16_t origcmd, newcmd; + rt_uint32_t cmd_status_dword; + struct rt_pci_bus *bus = pdev->bus; + + level = rt_spin_lock_irqsave(&rt_pci_lock); + + bus->ops->read(bus, pdev->devfn, PCIR_COMMAND, 4, &cmd_status_dword); + + irq_pending = (cmd_status_dword >> 16) & PCIM_STATUS_INTxSTATE; + + /* + * Check interrupt status register to see whether our device + * triggered the interrupt (when masking) or the next IRQ is + * already pending (when unmasking). + */ + if (mask != irq_pending) + { + res = RT_FALSE; + } + else + { + origcmd = cmd_status_dword; + newcmd = origcmd & ~PCIM_CMD_INTxDIS; + + if (mask) + { + newcmd |= PCIM_CMD_INTxDIS; + } + if (newcmd != origcmd) + { + bus->ops->write(bus, pdev->devfn, PCIR_COMMAND, 2, newcmd); + } + } + + rt_spin_unlock_irqrestore(&rt_pci_lock, level); + + return res; +} + +rt_bool_t rt_pci_check_and_mask_intx(struct rt_pci_device *pdev) +{ + rt_bool_t res = RT_FALSE; + + if (pdev) + { + res = pci_check_and_set_intx_mask(pdev, RT_TRUE); + } + + return res; +} + +rt_bool_t rt_pci_check_and_unmask_intx(struct rt_pci_device *pdev) +{ + rt_bool_t res = RT_FALSE; + + if (pdev) + { + res = pci_check_and_set_intx_mask(pdev, RT_FALSE); + } + + return res; +} + +struct rt_pci_bus *rt_pci_find_root_bus(struct rt_pci_bus *bus) +{ + if (!bus) + { + return RT_NULL; + } + + while (bus->parent) + { + bus = bus->parent; + } + + return bus; +} + +struct rt_pci_host_bridge *rt_pci_find_host_bridge(struct rt_pci_bus *bus) +{ + if (!bus) + { + return RT_NULL; + } + + if ((bus = rt_pci_find_root_bus(bus))) + { + return rt_container_of(bus->host_bridge, struct rt_pci_host_bridge, parent); + } + + return RT_NULL; +} + +rt_uint8_t rt_pci_irq_intx(struct rt_pci_device *pdev, rt_uint8_t pin) +{ + int slot = 0; + + if (!rt_pci_enabled(pdev, PCI_F_ARI)) + { + slot = RT_PCI_SLOT(pdev->devfn); + } + + return (((pin - 1) + slot) % 4) + 1; +} + +rt_uint8_t rt_pci_irq_slot(struct rt_pci_device *pdev, rt_uint8_t *pinp) +{ + rt_uint8_t pin = *pinp; + + while (!rt_pci_is_root_bus(pdev->bus)) + { + pin = rt_pci_irq_intx(pdev, pin); + pdev = pdev->bus->self; + } + + *pinp = pin; + + return RT_PCI_SLOT(pdev->devfn); +} + +rt_err_t rt_pci_region_setup(struct rt_pci_host_bridge *host_bridge) +{ + rt_err_t err = host_bridge->bus_regions_nr == 0 ? -RT_EEMPTY : RT_EOK; + + for (int i = 0; i < host_bridge->bus_regions_nr; ++i) + { + struct rt_pci_bus_region *region = &host_bridge->bus_regions[i]; + /* + * Avoid allocating PCI resources from address 0 -- this is illegal + * according to PCI 2.1 and moreover. Use a reasonable starting value of + * 0x1000 instead if the bus start address is below 0x1000. + */ + region->bus_start = rt_max_t(rt_size_t, 0x1000, region->phy_addr); + + LOG_I("Bus %s region(%d):", + region->flags == PCI_BUS_REGION_F_MEM ? "Memory" : + (region->flags & PCI_BUS_REGION_F_PREFETCH ? "Prefetchable Mem" : + (region->flags & PCI_BUS_REGION_F_IO ? "I/O" : "Unknown")), i); + LOG_I(" cpu: [%p, %p]", region->cpu_addr, (region->cpu_addr + region->size - 1)); + LOG_I(" physical: [%p, %p]", region->phy_addr, (region->phy_addr + region->size - 1)); + } + + return err; +} + +struct rt_pci_bus_region *rt_pci_region_alloc(struct rt_pci_host_bridge *host_bridge, + void **out_addr, rt_size_t size, rt_ubase_t flags, rt_bool_t mem64) +{ + struct rt_pci_bus_region *region = RT_NULL; + + for (int i = 0; i < host_bridge->bus_regions_nr; ++i) + { + if (host_bridge->bus_regions[i].flags == flags && host_bridge->bus_regions[i].size > 0) + { + void *addr; + region = &host_bridge->bus_regions[i]; + addr = (void *)(((region->bus_start - 1) | (size - 1)) + 1); + + if ((rt_uint64_t)addr - region->phy_addr + size <= region->size) + { + if (((rt_uint32_t)((((rt_uint64_t)addr) >> 16) >> 16)) && !mem64) + { + region = RT_NULL; + } + else + { + region->bus_start = ((rt_uint64_t)addr + size); + *out_addr = addr; + } + } + + break; + } + } + + return region; +} + +rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge, struct rt_pci_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_size_t size; + rt_ubase_t addr; + rt_uint32_t cfg; + rt_size_t bars_nr; + rt_uint8_t hdr_type; + rt_bool_t prefetch = RT_FALSE; + rt_uint16_t class, command = 0; + + for (int i = 0; i < host_bridge->bus_regions_nr; ++i) + { + if (host_bridge->bus_regions[i].flags == PCI_BUS_REGION_F_PREFETCH) + { + prefetch = RT_TRUE; + break; + } + } + + rt_pci_read_config_u16(pdev, PCIR_COMMAND, &command); + command = (command & ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) | PCIM_CMD_BUSMASTEREN; + rt_pci_read_config_u8(pdev, PCIR_HDRTYPE, &hdr_type); + + if (pdev->hdr_type != hdr_type) + { + LOG_W("%s may not initialized", rt_dm_dev_get_name(&pdev->parent)); + } + + switch (hdr_type) + { + case PCIM_HDRTYPE_NORMAL: + bars_nr = PCI_STD_NUM_BARS; + break; + + case PCIM_HDRTYPE_BRIDGE: + bars_nr = 2; + break; + + case PCIM_HDRTYPE_CARDBUS: + bars_nr = 0; + break; + + default: + bars_nr = 0; + break; + } + + for (int i = 0; i < bars_nr; ++i) + { + rt_ubase_t flags; + rt_ubase_t bar_base, addr; + rt_bool_t mem64 = RT_FALSE; + struct rt_pci_bus_region *region; + + cfg = 0; + bar_base = PCIR_BAR(i); + + rt_pci_write_config_u32(pdev, bar_base, RT_UINT32_MAX); + rt_pci_read_config_u32(pdev, bar_base, &cfg); + + if (!cfg) + { + continue; + } + else if (cfg == RT_UINT32_MAX) + { + rt_pci_write_config_u32(pdev, bar_base, 0UL); + continue; + } + + if (cfg & PCIM_BAR_SPACE) + { + mem64 = RT_FALSE; + flags = PCI_BUS_REGION_F_IO; + + size = cfg & PCIM_BAR_IO_MASK; + size &= ~(size - 1); + } + else + { + /* memory */ + if ((cfg & PCIM_BAR_MEM_TYPE_MASK) == PCIM_BAR_MEM_TYPE_64) + { + /* 64bits */ + mem64 = RT_TRUE; + rt_uint32_t cfg64; + rt_uint64_t bar64; + + rt_pci_write_config_u32(pdev, bar_base + sizeof(rt_uint32_t), RT_UINT32_MAX); + rt_pci_read_config_u32(pdev, bar_base + sizeof(rt_uint32_t), &cfg64); + + bar64 = ((rt_uint64_t)cfg64 << 32) | cfg; + + size = ~(bar64 & PCIM_BAR_MEM_MASK) + 1; + } + else + { + /* 32bits */ + mem64 = RT_FALSE; + size = (rt_uint32_t)(~(cfg & PCIM_BAR_MEM_MASK) + 1); + } + + if (prefetch && (cfg & PCIM_BAR_MEM_PREFETCH)) + { + flags = PCI_BUS_REGION_F_PREFETCH; + } + else + { + flags = PCI_BUS_REGION_F_MEM; + } + } + + region = rt_pci_region_alloc(host_bridge, (void **)&addr, size, flags, mem64); + + if (region) + { + rt_pci_write_config_u32(pdev, bar_base, addr); + + if (mem64) + { + bar_base += sizeof(rt_uint32_t); + #ifdef RT_PCI_SYS_64BIT + rt_pci_write_config_u32(pdev, bar_base, (rt_uint32_t)(addr >> 32)); + #else + /* + * If we are a 64-bit decoder then increment to the upper 32 bits + * of the bar and force it to locate in the lower 4GB of memory. + */ + rt_pci_write_config_u32(pdev, bar_base, 0UL); + #endif + } + + pdev->resource[i].size = size; + #ifdef ARCH_SUPPORT_PIO + pdev->resource[i].base = addr; + #else + if (flags != PCI_BUS_REGION_F_IO) + { + pdev->resource[i].base = addr; + } + else + { + rt_ubase_t offset = addr - region->phy_addr; + pdev->resource[i].base = region->cpu_addr + offset; + } + #endif + pdev->resource[i].flags = flags; + } + else + { + err = -RT_ERROR; + LOG_W("%s alloc bar(%d) address fail", rt_dm_dev_get_name(&pdev->parent), i); + } + + command |= (cfg & PCIM_BAR_SPACE) ? PCIM_CMD_PORTEN : PCIM_CMD_MEMEN; + } + + if (hdr_type == PCIM_HDRTYPE_NORMAL || hdr_type == PCIM_HDRTYPE_BRIDGE) + { + int rom_addr = (hdr_type == PCIM_HDRTYPE_NORMAL) ? PCIR_BIOS : PCIR_BIOS_1; + + rt_pci_write_config_u32(pdev, rom_addr, 0xfffffffe); + rt_pci_read_config_u32(pdev, rom_addr, &cfg); + + if (cfg) + { + size = -(cfg & ~1); + + if (rt_pci_region_alloc(host_bridge, (void **)&addr, size, PCI_BUS_REGION_F_MEM, RT_FALSE)) + { + rt_pci_write_config_u32(pdev, rom_addr, addr); + } + command |= PCIM_CMD_MEMEN; + } + } + + rt_pci_read_config_u16(pdev, PCIR_SUBCLASS, &class); + + if (class == PCIS_DISPLAY_VGA) + { + command |= PCIM_CMD_PORTEN; + } + + rt_pci_write_config_u16(pdev, PCIR_COMMAND, command); + rt_pci_write_config_u8(pdev, PCIR_CACHELNSZ, RT_PCI_CACHE_LINE_SIZE); + rt_pci_write_config_u8(pdev, PCIR_LATTIMER, 0x80); + + return err; +} + +void rt_pci_enum_device(struct rt_pci_bus *bus, rt_bool_t (callback(struct rt_pci_device *))) +{ + rt_bool_t is_end = RT_FALSE; + struct rt_pci_device *pdev; + struct rt_pci_bus *parent; + + /* Walk tree */ + while (bus && !is_end) + { + /* Goto bottom */ + for (;;) + { + if (rt_list_isempty(&bus->children_nodes)) + { + parent = bus->parent; + break; + } + bus = rt_list_entry(&bus->children_nodes, struct rt_pci_bus, list); + } + + rt_list_for_each_entry(pdev, &bus->devices_nodes, list) + { + if (callback(pdev)) + { + is_end = RT_TRUE; + break; + } + } + + /* Up a level or goto next */ + while (!is_end) + { + if (!parent) + { + /* Root bus, is end */ + bus = RT_NULL; + break; + } + + if (bus->list.next != &parent->children_nodes) + { + /* has next sibling */ + bus = rt_list_entry(bus->list.next, struct rt_pci_bus, list); + break; + } + + /* all device on this buss' parent */ + rt_list_for_each_entry(pdev, &parent->devices_nodes, list) + { + if (callback(pdev)) + { + is_end = RT_TRUE; + break; + } + } + + bus = parent; + parent = parent->parent; + } + } + + /* host bridge */ + if (!is_end) + { + // callback(bus->bridge); + } +} + +const struct rt_pci_device_id *rt_pci_match_id(struct rt_pci_device *pdev, const struct rt_pci_device_id *id) +{ + if ((id->vendor == PCI_ANY_ID || id->vendor == pdev->vendor) && + (id->device == PCI_ANY_ID || id->device == pdev->device) && + (id->subsystem_vendor == PCI_ANY_ID || id->subsystem_vendor == pdev->subsystem_vendor) && + (id->subsystem_device == PCI_ANY_ID || id->subsystem_device == pdev->subsystem_device) && + !((id->class ^ pdev->class) & id->class_mask)) + { + return id; + } + + return RT_NULL; +} + +const struct rt_pci_device_id *rt_pci_match_ids(struct rt_pci_device *pdev, const struct rt_pci_device_id *ids) +{ + while (ids->vendor || ids->subsystem_vendor || ids->class_mask) + { + if (rt_pci_match_id(pdev, ids)) + { + return ids; + } + + ++ids; + } + + return RT_NULL; +} + +static struct rt_bus pci_bus; + +rt_err_t rt_pci_driver_register(struct rt_pci_driver *pdrv) +{ + RT_ASSERT(pdrv != RT_NULL); + + pdrv->parent.bus = &pci_bus; + pdrv->parent.name = pdrv->name; + + return rt_driver_register(&pdrv->parent); +} + +rt_err_t rt_pci_device_register(struct rt_pci_device *pdev) +{ + RT_ASSERT(pdev != RT_NULL); + + rt_list_init(&pdev->list); + + return rt_bus_add_device(&pci_bus, &pdev->parent); +} + +static rt_bool_t pci_match(rt_driver_t drv, rt_device_t dev) +{ + rt_bool_t match = RT_FALSE; + struct rt_pci_driver *pdrv = rt_container_of(drv, struct rt_pci_driver, parent); + struct rt_pci_device *pdev = rt_container_of(dev, struct rt_pci_device, parent); + + if (pdrv->name && pdev->name) + { + match = rt_strcmp(pdrv->name, pdev->name) ? RT_FALSE : RT_TRUE; + } + + if (!match) + { + pdev->id = rt_pci_match_ids(pdev, pdrv->ids); + + match = pdev->id ? RT_TRUE : RT_FALSE; + } + + return match; +} + +static rt_err_t pci_probe(rt_device_t dev) +{ + rt_err_t err = RT_EOK; + struct rt_pci_driver *pdrv = rt_container_of(dev->drv, struct rt_pci_driver, parent); + struct rt_pci_device *pdev = rt_container_of(dev, struct rt_pci_device, parent); + + rt_pci_assign_irq(pdev); + + err = pdrv->probe(pdev); + + return err; +} + +static struct rt_bus pci_bus = +{ + .name = "pci", + .match = pci_match, + .probe = pci_probe, +}; + +static int pci_bus_init(void) +{ + rt_bus_register(&pci_bus); + + return 0; +} +INIT_CORE_EXPORT(pci_bus_init); diff --git a/components/drivers/pci/pci_ids.h b/components/drivers/pci/pci_ids.h new file mode 100644 index 000000000000..d3bcd9fe4ecd --- /dev/null +++ b/components/drivers/pci/pci_ids.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __PCI_IDS_H__ +#define __PCI_IDS_H__ + +#define PCI_VENDOR_ID_LOONGSON 0x0014 +#define PCI_VENDOR_ID_TTTECH 0x0357 +#define PCI_VENDOR_ID_DYNALINK 0x0675 +#define PCI_VENDOR_ID_UBIQUITI 0x0777 +#define PCI_VENDOR_ID_BERKOM 0x0871 +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_VENDOR_ID_NCR 0x1000 +#define PCI_VENDOR_ID_ATI 0x1002 +#define PCI_VENDOR_ID_VLSI 0x1004 +#define PCI_VENDOR_ID_ADL 0x1005 +#define PCI_VENDOR_ID_NS 0x100b +#define PCI_VENDOR_ID_TSENG 0x100c +#define PCI_VENDOR_ID_WEITEK 0x100e +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#define PCI_VENDOR_ID_IBM 0x1014 +#define PCI_VENDOR_ID_UNISYS 0x1018 +#define PCI_VENDOR_ID_COMPEX2 0x101a +#define PCI_VENDOR_ID_WD 0x101c +#define PCI_VENDOR_ID_AMI 0x101e +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_VENDOR_ID_TRIDENT 0x1023 +#define PCI_VENDOR_ID_AI 0x1025 +#define PCI_VENDOR_ID_DELL 0x1028 +#define PCI_VENDOR_ID_MATROX 0x102B +#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 +#define PCI_VENDOR_ID_CT 0x102c +#define PCI_VENDOR_ID_MIRO 0x1031 +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_VENDOR_ID_FD 0x1036 +#define PCI_VENDOR_ID_SI 0x1039 +#define PCI_VENDOR_ID_HP 0x103c +#define PCI_VENDOR_ID_PCTECH 0x1042 +#define PCI_VENDOR_ID_ASUSTEK 0x1043 +#define PCI_VENDOR_ID_DPT 0x1044 +#define PCI_VENDOR_ID_OPTI 0x1045 +#define PCI_VENDOR_ID_ELSA 0x1048 +#define PCI_VENDOR_ID_STMICRO 0x104A +#define PCI_VENDOR_ID_BUSLOGIC 0x104B +#define PCI_VENDOR_ID_TI 0x104c +#define PCI_VENDOR_ID_SONY 0x104d +#define PCI_VENDOR_ID_ANIGMA 0x1051 +#define PCI_VENDOR_ID_EFAR 0x1055 +#define PCI_VENDOR_ID_MOTOROLA 0x1057 +#define PCI_VENDOR_ID_PROMISE 0x105a +#define PCI_VENDOR_ID_FOXCONN 0x105b +#define PCI_VENDOR_ID_UMC 0x1060 +#define PCI_VENDOR_ID_PICOPOWER 0x1066 +#define PCI_VENDOR_ID_MYLEX 0x1069 +#define PCI_VENDOR_ID_APPLE 0x106b +#define PCI_VENDOR_ID_YAMAHA 0x1073 +#define PCI_VENDOR_ID_QLOGIC 0x1077 +#define PCI_VENDOR_ID_CYRIX 0x1078 +#define PCI_VENDOR_ID_CONTAQ 0x1080 +#define PCI_VENDOR_ID_OLICOM 0x108d +#define PCI_VENDOR_ID_SUN 0x108e +#define PCI_VENDOR_ID_NI 0x1093 +#define PCI_VENDOR_ID_CMD 0x1095 +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_VENDOR_ID_WINBOND 0x10ad +#define PCI_VENDOR_ID_PLX 0x10b5 +#define PCI_VENDOR_ID_MADGE 0x10b6 +#define PCI_VENDOR_ID_3COM 0x10b7 +#define PCI_VENDOR_ID_AL 0x10b9 +#define PCI_VENDOR_ID_NEOMAGIC 0x10c8 +#define PCI_VENDOR_ID_TCONRAD 0x10da +#define PCI_VENDOR_ID_ROHM 0x10db +#define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_VENDOR_ID_IMS 0x10e0 +#define PCI_VENDOR_ID_AMCC 0x10e8 +#define PCI_VENDOR_ID_INTERG 0x10ea +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_VENDOR_ID_XILINX 0x10ee +#define PCI_VENDOR_ID_INIT 0x1101 +#define PCI_VENDOR_ID_CREATIVE 0x1102 +#define PCI_VENDOR_ID_ECTIVA PCI_VENDOR_ID_CREATIVE +#define PCI_VENDOR_ID_TTI 0x1103 +#define PCI_VENDOR_ID_SIGMA 0x1105 +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_VENDOR_ID_SIEMENS 0x110A +#define PCI_VENDOR_ID_VORTEX 0x1119 +#define PCI_VENDOR_ID_EF 0x111a +#define PCI_VENDOR_ID_IDT 0x111d +#define PCI_VENDOR_ID_FORE 0x1127 +#define PCI_VENDOR_ID_PHILIPS 0x1131 +#define PCI_VENDOR_ID_EICON 0x1133 +#define PCI_VENDOR_ID_CISCO 0x1137 +#define PCI_VENDOR_ID_ZIATECH 0x1138 +#define PCI_VENDOR_ID_SYSKONNECT 0x1148 +#define PCI_VENDOR_ID_DIGI 0x114f +#define PCI_VENDOR_ID_XIRCOM 0x115d +#define PCI_VENDOR_ID_SERVERWORKS 0x1166 +#define PCI_VENDOR_ID_ALTERA 0x1172 +#define PCI_VENDOR_ID_SBE 0x1176 +#define PCI_VENDOR_ID_TOSHIBA 0x1179 +#define PCI_VENDOR_ID_TOSHIBA_2 0x102f +#define PCI_VENDOR_ID_ATTO 0x117c +#define PCI_VENDOR_ID_RICOH 0x1180 +#define PCI_VENDOR_ID_DLINK 0x1186 +#define PCI_VENDOR_ID_ARTOP 0x1191 +#define PCI_VENDOR_ID_ZEITNET 0x1193 +#define PCI_VENDOR_ID_FUJITSU_ME 0x119e +#define PCI_VENDOR_ID_MARVELL 0x11ab +#define PCI_VENDOR_ID_V3 0x11b0 +#define PCI_VENDOR_ID_ATT 0x11c1 +#define PCI_VENDOR_ID_SPECIALIX 0x11cb +#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 +#define PCI_VENDOR_ID_ZORAN 0x11de +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#define PCI_VENDOR_ID_PMC_Sierra 0x11f8 +#define PCI_VENDOR_ID_RP 0x11fe +#define PCI_VENDOR_ID_CYCLADES 0x120e +#define PCI_VENDOR_ID_ESSENTIAL 0x120f +#define PCI_VENDOR_ID_O2 0x1217 +#define PCI_VENDOR_ID_3DFX 0x121a +#define PCI_VENDOR_ID_AVM 0x1244 +#define PCI_VENDOR_ID_STALLION 0x124d +#define PCI_VENDOR_ID_ESS 0x125d +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#define PCI_VENDOR_ID_ENSONIQ 0x1274 +#define PCI_VENDOR_ID_TRANSMETA 0x1279 +#define PCI_VENDOR_ID_ROCKWELL 0x127A +#define PCI_VENDOR_ID_ITE 0x1283 +#define PCI_VENDOR_ID_ALTEON 0x12ae +#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 +#define PCI_VENDOR_ID_PERICOM 0x12D8 +#define PCI_VENDOR_ID_AUREAL 0x12eb +#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8 +#define PCI_VENDOR_ID_ESDGMBH 0x12fe +#define PCI_VENDOR_ID_CB 0x1307 +#define PCI_VENDOR_ID_SIIG 0x131f +#define PCI_VENDOR_ID_RADISYS 0x1331 +#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +#define PCI_VENDOR_ID_DOMEX 0x134a +#define PCI_VENDOR_ID_INTASHIELD 0x135a +#define PCI_VENDOR_ID_QUATECH 0x135C +#define PCI_VENDOR_ID_SEALEVEL 0x135e +#define PCI_VENDOR_ID_HYPERCOPE 0x1365 +#define PCI_VENDOR_ID_DIGIGRAM 0x1369 +#define PCI_VENDOR_ID_KAWASAKI 0x136b +#define PCI_VENDOR_ID_CNET 0x1371 +#define PCI_VENDOR_ID_LMC 0x1376 +#define PCI_VENDOR_ID_NETGEAR 0x1385 +#define PCI_VENDOR_ID_APPLICOM 0x1389 +#define PCI_VENDOR_ID_MOXA 0x1393 +#define PCI_VENDOR_ID_CCD 0x1397 +#define PCI_VENDOR_ID_EXAR 0x13a8 +#define PCI_VENDOR_ID_MICROGATE 0x13c0 +#define PCI_VENDOR_ID_3WARE 0x13C1 +#define PCI_VENDOR_ID_IOMEGA 0x13ca +#define PCI_VENDOR_ID_ABOCOM 0x13D1 +#define PCI_VENDOR_ID_SUNDANCE 0x13f0 +#define PCI_VENDOR_ID_CMEDIA 0x13f6 +#define PCI_VENDOR_ID_ADVANTECH 0x13fe +#define PCI_VENDOR_ID_MEILHAUS 0x1402 +#define PCI_VENDOR_ID_LAVA 0x1407 +#define PCI_VENDOR_ID_TIMEDIA 0x1409 +#define PCI_VENDOR_ID_ICE 0x1412 +#define PCI_VENDOR_ID_MICROSOFT 0x1414 +#define PCI_VENDOR_ID_OXSEMI 0x1415 +#define PCI_VENDOR_ID_CHELSIO 0x1425 +#define PCI_VENDOR_ID_ADLINK 0x144a +#define PCI_VENDOR_ID_SAMSUNG 0x144d +#define PCI_VENDOR_ID_GIGABYTE 0x1458 +#define PCI_VENDOR_ID_AMBIT 0x1468 +#define PCI_VENDOR_ID_MYRICOM 0x14c1 +#define PCI_VENDOR_ID_MEDIATEK 0x14c3 +#define PCI_VENDOR_ID_TITAN 0x14D2 +#define PCI_VENDOR_ID_PANACOM 0x14d4 +#define PCI_VENDOR_ID_SIPACKETS 0x14d9 +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_VENDOR_ID_AMPLICON 0x14dc +#define PCI_VENDOR_ID_BCM_GVC 0x14a4 +#define PCI_VENDOR_ID_TOPIC 0x151f +#define PCI_VENDOR_ID_MAINPINE 0x1522 +#define PCI_VENDOR_ID_SYBA 0x1592 +#define PCI_VENDOR_ID_MORETON 0x15aa +#define PCI_VENDOR_ID_VMWARE 0x15ad +#define PCI_VENDOR_ID_ZOLTRIX 0x15b0 +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#define PCI_VENDOR_ID_DFI 0x15bd +#define PCI_VENDOR_ID_QUICKNET 0x15e2 +#define PCI_VENDOR_ID_PDC 0x15e9 +#define PCI_VENDOR_ID_FARSITE 0x1619 +#define PCI_VENDOR_ID_ARIMA 0x161f +#define PCI_VENDOR_ID_BROCADE 0x1657 +#define PCI_VENDOR_ID_SIBYTE 0x166d +#define PCI_VENDOR_ID_ATHEROS 0x168c +#define PCI_VENDOR_ID_NETCELL 0x169c +#define PCI_VENDOR_ID_CENATEK 0x16CA +#define PCI_VENDOR_ID_SYNOPSYS 0x16c3 +#define PCI_VENDOR_ID_USR 0x16ec +#define PCI_VENDOR_ID_VITESSE 0x1725 +#define PCI_VENDOR_ID_LINKSYS 0x1737 +#define PCI_VENDOR_ID_ALTIMA 0x173b +#define PCI_VENDOR_ID_CAVIUM 0x177d +#define PCI_VENDOR_ID_TECHWELL 0x1797 +#define PCI_VENDOR_ID_BELKIN 0x1799 +#define PCI_VENDOR_ID_RDC 0x17f3 +#define PCI_VENDOR_ID_GLI 0x17a0 +#define PCI_VENDOR_ID_LENOVO 0x17aa +#define PCI_VENDOR_ID_QCOM 0x17cb +#define PCI_VENDOR_ID_CDNS 0x17cd +#define PCI_VENDOR_ID_ARECA 0x17d3 +#define PCI_VENDOR_ID_S2IO 0x17d5 +#define PCI_VENDOR_ID_SITECOM 0x182d +#define PCI_VENDOR_ID_TOPSPIN 0x1867 +#define PCI_VENDOR_ID_COMMTECH 0x18f7 +#define PCI_VENDOR_ID_SILAN 0x1904 +#define PCI_VENDOR_ID_RENESAS 0x1912 +#define PCI_VENDOR_ID_SOLARFLARE 0x1924 +#define PCI_VENDOR_ID_TDI 0x192E +#define PCI_VENDOR_ID_FREESCALE 0x1957 +#define PCI_VENDOR_ID_NXP PCI_VENDOR_ID_FREESCALE +#define PCI_VENDOR_ID_PASEMI 0x1959 +#define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_VENDOR_ID_JMICRON 0x197B +#define PCI_VENDOR_ID_KORENIX 0x1982 +#define PCI_VENDOR_ID_HUAWEI 0x19e5 +#define PCI_VENDOR_ID_NETRONOME 0x19ee +#define PCI_VENDOR_ID_QMI 0x1a32 +#define PCI_VENDOR_ID_AZWAVE 0x1a3b +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_VENDOR_ID_ASMEDIA 0x1b21 +#define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_VENDOR_ID_SILICOM_DENMARK 0x1c2c +#define PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS 0x1c36 +#define PCI_VENDOR_ID_CIRCUITCO 0x1cc8 +#define PCI_VENDOR_ID_AMAZON 0x1d0f +#define PCI_VENDOR_ID_ZHAOXIN 0x1d17 +#define PCI_VENDOR_ID_HYGON 0x1d94 +#define PCI_VENDOR_ID_FUNGIBLE 0x1dad +#define PCI_VENDOR_ID_HXT 0x1dbf +#define PCI_VENDOR_ID_TEKRAM 0x1de1 +#define PCI_VENDOR_ID_TEHUTI 0x1fc9 +#define PCI_VENDOR_ID_SUNIX 0x1fd4 +#define PCI_VENDOR_ID_HINT 0x3388 +#define PCI_VENDOR_ID_3DLABS 0x3d3d +#define PCI_VENDOR_ID_NETXEN 0x4040 +#define PCI_VENDOR_ID_AKS 0x416c +#define PCI_VENDOR_ID_ACCESSIO 0x494f +#define PCI_VENDOR_ID_S3 0x5333 +#define PCI_VENDOR_ID_DUNORD 0x5544 +#define PCI_VENDOR_ID_DCI 0x6666 +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_VENDOR_ID_SCALEMP 0x8686 +#define PCI_VENDOR_ID_COMPUTONE 0x8e0e +#define PCI_VENDOR_ID_KTI 0x8e2e +#define PCI_VENDOR_ID_ADAPTEC 0x9004 +#define PCI_VENDOR_ID_ADAPTEC2 0x9005 +#define PCI_VENDOR_ID_HOLTEK 0x9412 +#define PCI_VENDOR_ID_NETMOS 0x9710 +#define PCI_VENDOR_ID_3COM_2 0xa727 +#define PCI_VENDOR_ID_DIGIUM 0xd161 +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#define PCI_VENDOR_ID_XILINX_RME 0xea60 +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_VENDOR_ID_OCZ 0x1b85 +#define PCI_VENDOR_ID_NCUBE 0x10ff + +#endif /* __PCI_IDS_H__ */ diff --git a/components/drivers/pci/pci_regs.h b/components/drivers/pci/pci_regs.h new file mode 100644 index 000000000000..95c526ec9c66 --- /dev/null +++ b/components/drivers/pci/pci_regs.h @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __PCI_REGS_H__ +#define __PCI_REGS_H__ + +#include + +/* + * PCI standard defines + * Copyright 1994, Drew Eckhardt + * Copyright 1997--1999 Martin Mares + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI BIOS Specification + * PCI Local Bus Specification + * PCI to PCI Bridge Specification + * PCI System Design Guide + * + * For HyperTransport information, please consult the following manuals + * from http://www.hypertransport.org : + * + * The HyperTransport I/O Link Specification + * + * Mean of prefix: + * + * PCIM_xxx: mask to locate subfield in register + * PCIR_xxx: config register offset + * PCIC_xxx: device class + * PCIS_xxx: device subclass + * PCIP_xxx: device programming interface + * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) + * PCID_xxx: device ID + * PCIY_xxx: capability identification number + * PCIZ_xxx: extended capability identification number + */ + +/* some PCI bus constants */ +#define PCI_DOMAINMAX 65535 /* highest supported domain number */ +#define PCI_BUSMAX 255 /* highest supported bus number */ +#define PCI_SLOTMAX 31 /* highest supported slot number */ +#define PCI_FUNCMAX 7 /* highest supported function number */ +#define PCI_REGMAX 255 /* highest supported config register addr */ +#define PCIE_REGMAX 4095 /* highest supported config register addr */ +#define PCI_MAXHDRTYPE 2 +#define PCI_STD_HEADER_SIZEOF 64 +#define PCI_STD_NUM_BARS 6 /* number of standard BARs */ + +/* PCI config header registers for all devices */ + +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIM_CMD_PORTEN 0x0001 +#define PCIM_CMD_MEMEN 0x0002 +#define PCIM_CMD_BUSMASTEREN 0x0004 +#define PCIM_CMD_SPECIALEN 0x0008 +#define PCIM_CMD_MWRICEN 0x0010 +#define PCIM_CMD_PERRESPEN 0x0040 +#define PCIM_CMD_SERRESPEN 0x0100 +#define PCIM_CMD_BACKTOBACK 0x0200 +#define PCIM_CMD_INTxDIS 0x0400 +#define PCIR_STATUS 0x06 +#define PCIM_STATUS_INTxSTATE 0x0008 +#define PCIM_STATUS_CAPPRESENT 0x0010 +#define PCIM_STATUS_66CAPABLE 0x0020 +#define PCIM_STATUS_BACKTOBACK 0x0080 +#define PCIM_STATUS_MDPERR 0x0100 +#define PCIM_STATUS_SEL_FAST 0x0000 +#define PCIM_STATUS_SEL_MEDIMUM 0x0200 +#define PCIM_STATUS_SEL_SLOW 0x0400 +#define PCIM_STATUS_SEL_MASK 0x0600 +#define PCIM_STATUS_STABORT 0x0800 +#define PCIM_STATUS_RTABORT 0x1000 +#define PCIM_STATUS_RMABORT 0x2000 +#define PCIM_STATUS_SERR 0x4000 +#define PCIM_STATUS_PERR 0x8000 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HDRTYPE 0x0e +#define PCIM_HDRTYPE 0x7f +#define PCIM_HDRTYPE_NORMAL 0x00 +#define PCIM_HDRTYPE_BRIDGE 0x01 +#define PCIM_HDRTYPE_CARDBUS 0x02 +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f + +/* PCI Spec rev 2.2: 0FFFFh is an invalid value for Vendor ID. */ +#define PCIV_INVALID 0xffff + +/* Capability Register Offsets */ + +#define PCICAP_ID 0x0 +#define PCICAP_NEXTPTR 0x1 + +/* Capability Identification Numbers */ + +#define PCIY_PMG 0x01 /* PCI Power Management */ +#define PCIY_AGP 0x02 /* AGP */ +#define PCIY_VPD 0x03 /* Vital Product Data */ +#define PCIY_SLOTID 0x04 /* Slot Identification */ +#define PCIY_MSI 0x05 /* Message Signaled Interrupts */ +#define PCIY_CHSWP 0x06 /* CompactPCI Hot Swap */ +#define PCIY_PCIX 0x07 /* PCI-X */ +#define PCIY_HT 0x08 /* HyperTransport */ +#define PCIY_VENDOR 0x09 /* Vendor Unique */ +#define PCIY_DEBUG 0x0a /* Debug port */ +#define PCIY_CRES 0x0b /* CompactPCI central resource control */ +#define PCIY_HOTPLUG 0x0c /* PCI Hot-Plug */ +#define PCIY_SUBVENDOR 0x0d /* PCI-PCI bridge subvendor ID */ +#define PCIY_AGP8X 0x0e /* AGP 8x */ +#define PCIY_SECDEV 0x0f /* Secure Device */ +#define PCIY_EXPRESS 0x10 /* PCI Express */ +#define PCIY_MSIX 0x11 /* MSI-X */ +#define PCIY_SATA 0x12 /* SATA */ +#define PCIY_PCIAF 0x13 /* PCI Advanced Features */ +#define PCIY_EA 0x14 /* PCI Extended Allocation */ +#define PCIY_FPB 0x15 /* Flattening Portal Bridge */ + +/* Extended Capability Register Fields */ + +#define PCIR_EXTCAP 0x100 +#define PCIM_EXTCAP_ID 0x0000ffff +#define PCIM_EXTCAP_VER 0x000f0000 +#define PCIM_EXTCAP_NEXTPTR 0xfff00000 +#define PCI_EXTCAP_ID(ecap) ((ecap) & PCIM_EXTCAP_ID) +#define PCI_EXTCAP_VER(ecap) (((ecap) & PCIM_EXTCAP_VER) >> 16) +#define PCI_EXTCAP_NEXTPTR(ecap) (((ecap) & PCIM_EXTCAP_NEXTPTR) >> 20) + +/* Extended Capability Identification Numbers */ + +#define PCIZ_AER 0x0001 /* Advanced Error Reporting */ +#define PCIZ_VC 0x0002 /* Virtual Channel if MFVC Ext Cap not set */ +#define PCIZ_SERNUM 0x0003 /* Device Serial Number */ +#define PCIZ_PWRBDGT 0x0004 /* Power Budgeting */ +#define PCIZ_RCLINK_DCL 0x0005 /* Root Complex Link Declaration */ +#define PCIZ_RCLINK_CTL 0x0006 /* Root Complex Internal Link Control */ +#define PCIZ_RCEC_ASSOC 0x0007 /* Root Complex Event Collector Association */ +#define PCIZ_MFVC 0x0008 /* Multi-Function Virtual Channel */ +#define PCIZ_VC2 0x0009 /* Virtual Channel if MFVC Ext Cap set */ +#define PCIZ_RCRB 0x000a /* RCRB Header */ +#define PCIZ_VENDOR 0x000b /* Vendor Unique */ +#define PCIZ_CAC 0x000c /* Configuration Access Correction -- obsolete */ +#define PCIZ_ACS 0x000d /* Access Control Services */ +#define PCIZ_ARI 0x000e /* Alternative Routing-ID Interpretation */ +#define PCIZ_ATS 0x000f /* Address Translation Services */ +#define PCIZ_SRIOV 0x0010 /* Single Root IO Virtualization */ +#define PCIZ_MRIOV 0x0011 /* Multiple Root IO Virtualization */ +#define PCIZ_MULTICAST 0x0012 /* Multicast */ +#define PCIZ_PAGE_REQ 0x0013 /* Page Request */ +#define PCIZ_AMD 0x0014 /* Reserved for AMD */ +#define PCIZ_RESIZE_BAR 0x0015 /* Resizable BAR */ +#define PCIZ_DPA 0x0016 /* Dynamic Power Allocation */ +#define PCIZ_TPH_REQ 0x0017 /* TPH Requester */ +#define PCIZ_LTR 0x0018 /* Latency Tolerance Reporting */ +#define PCIZ_SEC_PCIE 0x0019 /* Secondary PCI Express */ +#define PCIZ_PMUX 0x001a /* Protocol Multiplexing */ +#define PCIZ_PASID 0x001b /* Process Address Space ID */ +#define PCIZ_LN_REQ 0x001c /* LN Requester */ +#define PCIZ_DPC 0x001d /* Downstream Port Containment */ +#define PCIZ_L1PM 0x001e /* L1 PM Substates */ +#define PCIZ_PTM 0x001f /* Precision Time Measurement */ +#define PCIZ_M_PCIE 0x0020 /* PCIe over M-PHY */ +#define PCIZ_FRS 0x0021 /* FRS Queuing */ +#define PCIZ_RTR 0x0022 /* Readiness Time Reporting */ +#define PCIZ_DVSEC 0x0023 /* Designated Vendor-Specific */ +#define PCIZ_VF_REBAR 0x0024 /* VF Resizable BAR */ +#define PCIZ_DLNK 0x0025 /* Data Link Feature */ +#define PCIZ_16GT 0x0026 /* Physical Layer 16.0 GT/s */ +#define PCIZ_LMR 0x0027 /* Lane Margining at Receiver */ +#define PCIZ_HIER_ID 0x0028 /* Hierarchy ID */ +#define PCIZ_NPEM 0x0029 /* Native PCIe Enclosure Management */ +#define PCIZ_PL32 0x002a /* Physical Layer 32.0 GT/s */ +#define PCIZ_AP 0x002b /* Alternate Protocol */ +#define PCIZ_SFI 0x002c /* System Firmware Intermediary */ + +/* config registers for header type 0 devices */ + +#define PCIR_BARS 0x10 +#define PCIR_BAR(x) (PCIR_BARS + (x) * 4) +#define PCI_RID2BAR(rid) (((rid) - PCIR_BARS) / 4) +#define PCI_BAR_IO(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) +#define PCI_BAR_MEM(x) (((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE) +#define PCIM_BAR_SPACE 0x01 /* 0 = memory, 1 = I/O */ +#define PCIM_BAR_SPACE_IO 0x01 +#define PCIM_BAR_SPACE_MEMORY 0x00 +#define PCIM_BAR_MEM_TYPE_MASK 0x06 +#define PCIM_BAR_MEM_TYPE_32 0x00 /* 32 bit address */ +#define PCIM_BAR_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ +#define PCIM_BAR_MEM_TYPE_64 0x04 /* 64 bit address */ +#define PCIM_BAR_MEM_PREFETCH 0x08 /* prefetchable? */ +#define PCIM_BAR_MEM_MASK (~0x0fUL) +#define PCIM_BAR_IO_MASK (~0x03UL) +#define PCIR_CIS 0x28 +#define PCIM_CIS_ASI_MASK 0x00000007 +#define PCIM_CIS_ASI_CONFIG 0 +#define PCIM_CIS_ASI_BAR0 1 +#define PCIM_CIS_ASI_BAR1 2 +#define PCIM_CIS_ASI_BAR2 3 +#define PCIM_CIS_ASI_BAR3 4 +#define PCIM_CIS_ASI_BAR4 5 +#define PCIM_CIS_ASI_BAR5 6 +#define PCIM_CIS_ASI_ROM 7 +#define PCIM_CIS_ADDR_MASK 0x0ffffff8 +#define PCIM_CIS_ROM_MASK 0xf0000000 +#define PCIM_CIS_CONFIG_MASK 0xff +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e +#define PCIR_BIOS 0x30 +#define PCIM_BIOS_ENABLE 0x01 +#define PCIM_BIOS_ADDR_MASK 0xfffff800 +#define PCIR_CAP_PTR 0x34 +#define PCIR_INTLINE 0x3c +#define PCIR_INTPIN 0x3d +#define PCIR_MINGNT 0x3e +#define PCIR_MAXLAT 0x3f + +/* config registers for header type 1 (PCI-to-PCI bridge) devices */ + +#define PCIR_MAX_BAR_1 1 +#define PCIR_SECSTAT_1 0x1e + +#define PCIR_PRIBUS_1 0x18 +#define PCIR_SECBUS_1 0x19 +#define PCIR_SUBBUS_1 0x1a +#define PCIR_SECLAT_1 0x1b + +#define PCIR_IOBASEL_1 0x1c +#define PCIR_IOLIMITL_1 0x1d +#define PCIR_IOBASEH_1 0x30 +#define PCIR_IOLIMITH_1 0x32 +#define PCIM_BRIO_16 0x0 +#define PCIM_BRIO_32 0x1 +#define PCIM_BRIO_MASK 0xf + +#define PCIR_MEMBASE_1 0x20 +#define PCIR_MEMLIMIT_1 0x22 + +#define PCIR_PMBASEL_1 0x24 +#define PCIR_PMLIMITL_1 0x26 +#define PCIR_PMBASEH_1 0x28 +#define PCIR_PMLIMITH_1 0x2c +#define PCIM_BRPM_32 0x0 +#define PCIM_BRPM_64 0x1 +#define PCIM_BRPM_MASK 0xf + +#define PCIR_BIOS_1 0x38 +#define PCIR_BRIDGECTL_1 0x3e + +#define PCI_PPBMEMBASE(h, l) ((((rt_uint64_t)(h) << 32) + ((l) << 16)) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h, l) ((((rt_uint64_t)(h) << 32) + ((l) << 16)) | 0xfffff) +#define PCI_PPBIOBASE(h, l) ((((h) << 16) + ((l) << 8)) & ~0xfff) +#define PCI_PPBIOLIMIT(h, l) ((((h) << 16) + ((l) << 8)) | 0xfff) + +/* config registers for header t ype 2 (CardBus) devices */ + +#define PCIR_MAX_BAR_2 0 +#define PCIR_CAP_PTR_2 0x14 +#define PCIR_SECSTAT_2 0x16 + +#define PCIR_PRIBUS_2 0x18 +#define PCIR_SECBUS_2 0x19 +#define PCIR_SUBBUS_2 0x1a +#define PCIR_SECLAT_2 0x1b + +#define PCIR_MEMBASE0_2 0x1c +#define PCIR_MEMLIMIT0_2 0x20 +#define PCIR_MEMBASE1_2 0x24 +#define PCIR_MEMLIMIT1_2 0x28 +#define PCIR_IOBASE0_2 0x2c +#define PCIR_IOLIMIT0_2 0x30 +#define PCIR_IOBASE1_2 0x34 +#define PCIR_IOLIMIT1_2 0x38 +#define PCIM_CBBIO_16 0x0 +#define PCIM_CBBIO_32 0x1 +#define PCIM_CBBIO_MASK 0x3 + +#define PCIR_BRIDGECTL_2 0x3e + +#define PCIR_SUBVEND_2 0x40 +#define PCIR_SUBDEV_2 0x42 + +#define PCIR_PCCARDIF_2 0x44 + +#define PCI_CBBMEMBASE(l) ((l) & ~0xfffff) +#define PCI_CBBMEMLIMIT(l) ((l) | 0xfffff) +#define PCI_CBBIOBASE(l) ((l) & ~0x3) +#define PCI_CBBIOLIMIT(l) ((l) | 0x3) + +/* PCI device class, subclass and programming interface definitions */ +#define PCIC_NOT_DEFINED 0x0000 +#define PCIS_NOT_DEFINED_VGA 0x0001 + +#define PCIC_STORAGE 0x01 +#define PCIS_STORAGE_SCSI 0x0100 +#define PCIS_STORAGE_IDE 0x0101 +#define PCIS_STORAGE_FLOPPY 0x0102 +#define PCIS_STORAGE_IPI 0x0103 +#define PCIS_STORAGE_RAID 0x0104 +#define PCIS_STORAGE_SATA 0x0106 +#define PCIS_STORAGE_SATA_AHCI 0x010601 +#define PCIS_STORAGE_SAS 0x0107 +#define PCIS_STORAGE_EXPRESS 0x010802 +#define PCIS_STORAGE_OTHER 0x0180 + +#define PCIC_NETWORK 0x02 +#define PCIS_NETWORK_ETHERNET 0x0200 +#define PCIS_NETWORK_TOKEN_RING 0x0201 +#define PCIS_NETWORK_FDDI 0x0202 +#define PCIS_NETWORK_ATM 0x0203 +#define PCIS_NETWORK_OTHER 0x0280 + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x0300 +#define PCIS_DISPLAY_XGA 0x0301 +#define PCIS_DISPLAY_3D 0x0302 +#define PCIS_DISPLAY_OTHER 0x0380 + +#define PCIC_MULTIMEDIA 0x04 +#define PCIS_MULTIMEDIA_VIDEO 0x0400 +#define PCIS_MULTIMEDIA_AUDIO 0x0401 +#define PCIS_MULTIMEDIA_PHONE 0x0402 +#define PCIS_MULTIMEDIA_HD_AUDIO 0x0403 +#define PCIS_MULTIMEDIA_OTHER 0x0480 + +#define PCIC_MEMORY 0x05 +#define PCIS_MEMORY_RAM 0x0500 +#define PCIS_MEMORY_FLASH 0x0501 +#define PCIS_MEMORY_CXL 0x0502 +#define PCIS_MEMORY_OTHER 0x0580 + +#define PCIC_BRIDGE 0x06 +#define PCIS_BRIDGE_HOST 0x0600 +#define PCIS_BRIDGE_ISA 0x0601 +#define PCIS_BRIDGE_EISA 0x0602 +#define PCIS_BRIDGE_MC 0x0603 +#define PCIS_BRIDGE_PCI 0x0604 +#define PCIS_BRIDGE_PCI_NORMAL 0x060400 +#define PCIS_BRIDGE_PCI_SUBTRACTIVE 0x060401 +#define PCIS_BRIDGE_PCMCIA 0x0605 +#define PCIS_BRIDGE_NUBUS 0x0606 +#define PCIS_BRIDGE_CARDBUS 0x0607 +#define PCIS_BRIDGE_RACEWAY 0x0608 +#define PCIS_BRIDGE_OTHER 0x0680 + +#define PCIC_COMMUNICATION 0x07 +#define PCIS_COMMUNICATION_SERIAL 0x0700 +#define PCIS_COMMUNICATION_PARALLEL 0x0701 +#define PCIS_COMMUNICATION_MULTISERIAL 0x0702 +#define PCIS_COMMUNICATION_MODEM 0x0703 +#define PCIS_COMMUNICATION_OTHER 0x0780 + +#define PCIC_SYSTEM 0x08 +#define PCIS_SYSTEM_PIC 0x0800 +#define PCIS_SYSTEM_PIC_IOAPIC 0x080010 +#define PCIS_SYSTEM_PIC_IOXAPIC 0x080020 +#define PCIS_SYSTEM_DMA 0x0801 +#define PCIS_SYSTEM_TIMER 0x0802 +#define PCIS_SYSTEM_RTC 0x0803 +#define PCIS_SYSTEM_PCI_HOTPLUG 0x0804 +#define PCIS_SYSTEM_SDHCI 0x0805 +#define PCIS_SYSTEM_RCEC 0x0807 +#define PCIS_SYSTEM_OTHER 0x0880 + +#define PCIC_INPUT 0x09 +#define PCIS_INPUT_KEYBOARD 0x0900 +#define PCIS_INPUT_PEN 0x0901 +#define PCIS_INPUT_MOUSE 0x0902 +#define PCIS_INPUT_SCANNER 0x0903 +#define PCIS_INPUT_GAMEPORT 0x0904 +#define PCIS_INPUT_OTHER 0x0980 + +#define PCIC_DOCKING 0x0a +#define PCIS_DOCKING_GENERIC 0x0a00 +#define PCIS_DOCKING_OTHER 0x0a80 + +#define PCIC_PROCESSOR 0x0b +#define PCIS_PROCESSOR_386 0x0b00 +#define PCIS_PROCESSOR_486 0x0b01 +#define PCIS_PROCESSOR_PENTIUM 0x0b02 +#define PCIS_PROCESSOR_ALPHA 0x0b10 +#define PCIS_PROCESSOR_POWERPC 0x0b20 +#define PCIS_PROCESSOR_MIPS 0x0b30 +#define PCIS_PROCESSOR_CO 0x0b40 + +#define PCIC_SERIAL 0x0c +#define PCIS_SERIAL_FIREWIRE 0x0c00 +#define PCIS_SERIAL_FIREWIRE_OHCI 0x0c0010 +#define PCIS_SERIAL_ACCESS 0x0c01 +#define PCIS_SERIAL_SSA 0x0c02 +#define PCIS_SERIAL_USB 0x0c03 +#define PCIS_SERIAL_USB_UHCI 0x0c0300 +#define PCIS_SERIAL_USB_OHCI 0x0c0310 +#define PCIS_SERIAL_USB_EHCI 0x0c0320 +#define PCIS_SERIAL_USB_XHCI 0x0c0330 +#define PCIS_SERIAL_USB_DEVICE 0x0c03fe +#define PCIS_SERIAL_FIBER 0x0c04 +#define PCIS_SERIAL_SMBUS 0x0c05 +#define PCIS_SERIAL_IPMI 0x0c07 +#define PCIS_SERIAL_IPMI_SMIC 0x0c0700 +#define PCIS_SERIAL_IPMI_KCS 0x0c0701 +#define PCIS_SERIAL_IPMI_BT 0x0c0702 + +#define PCIC_WIRELESS 0x0d +#define PCIS_WIRELESS_RF_CONTROLLER 0x0d10 +#define PCIS_WIRELESS_WHCI 0x0d1010 + +#define PCIC_INTELLIGENT 0x0e +#define PCIS_INTELLIGENT_I2O 0x0e00 + +#define PCIC_SATELLITE 0x0f +#define PCIS_SATELLITE_TV 0x0f00 +#define PCIS_SATELLITE_AUDIO 0x0f01 +#define PCIS_SATELLITE_VOICE 0x0f03 +#define PCIS_SATELLITE_DATA 0x0f04 + +#define PCIC_CRYPT 0x10 +#define PCIS_CRYPT_NETWORK 0x1000 +#define PCIS_CRYPT_ENTERTAINMENT 0x1001 +#define PCIS_CRYPT_OTHER 0x1080 + +#define PCIC_SIGNAL_PROCESSING 0x11 +#define PCIS_SP_DPIO 0x1100 +#define PCIS_SP_OTHER 0x1180 + +#define PCIS_OTHERS 0xff + +/* Bridge Control Values. */ +#define PCIB_BCR_PERR_ENABLE 0x0001 +#define PCIB_BCR_SERR_ENABLE 0x0002 +#define PCIB_BCR_ISA_ENABLE 0x0004 +#define PCIB_BCR_VGA_ENABLE 0x0008 +#define PCIB_BCR_MASTER_ABORT_MODE 0x0020 +#define PCIB_BCR_SECBUS_RESET 0x0040 +#define PCIB_BCR_SECBUS_BACKTOBACK 0x0080 +#define PCIB_BCR_PRI_DISCARD_TIMEOUT 0x0100 +#define PCIB_BCR_SEC_DISCARD_TIMEOUT 0x0200 +#define PCIB_BCR_DISCARD_TIMER_STATUS 0x0400 +#define PCIB_BCR_DISCARD_TIMER_SERREN 0x0800 + +#define CBB_BCR_PERR_ENABLE 0x0001 +#define CBB_BCR_SERR_ENABLE 0x0002 +#define CBB_BCR_ISA_ENABLE 0x0004 +#define CBB_BCR_VGA_ENABLE 0x0008 +#define CBB_BCR_MASTER_ABORT_MODE 0x0020 +#define CBB_BCR_CARDBUS_RESET 0x0040 +#define CBB_BCR_IREQ_INT_ENABLE 0x0080 +#define CBB_BCR_PREFETCH_0_ENABLE 0x0100 +#define CBB_BCR_PREFETCH_1_ENABLE 0x0200 +#define CBB_BCR_WRITE_POSTING_ENABLE 0x0400 + +/* PCI power manangement */ +#define PCIR_POWER_CAP 0x2 +#define PCIM_PCAP_SPEC 0x0007 +#define PCIM_PCAP_PMEREQCLK 0x0008 +#define PCIM_PCAP_DEVSPECINIT 0x0020 +#define PCIM_PCAP_AUXPWR_0 0x0000 +#define PCIM_PCAP_AUXPWR_55 0x0040 +#define PCIM_PCAP_AUXPWR_100 0x0080 +#define PCIM_PCAP_AUXPWR_160 0x00c0 +#define PCIM_PCAP_AUXPWR_220 0x0100 +#define PCIM_PCAP_AUXPWR_270 0x0140 +#define PCIM_PCAP_AUXPWR_320 0x0180 +#define PCIM_PCAP_AUXPWR_375 0x01c0 +#define PCIM_PCAP_AUXPWRMASK 0x01c0 +#define PCIM_PCAP_D1SUPP 0x0200 +#define PCIM_PCAP_D2SUPP 0x0400 +#define PCIM_PCAP_D0PME 0x0800 +#define PCIM_PCAP_D1PME 0x1000 +#define PCIM_PCAP_D2PME 0x2000 +#define PCIM_PCAP_D3PME_HOT 0x4000 +#define PCIM_PCAP_D3PME_COLD 0x8000 + +#define PCIR_POWER_STATUS 0x4 +#define PCIM_PSTAT_D0 0x0000 +#define PCIM_PSTAT_D1 0x0001 +#define PCIM_PSTAT_D2 0x0002 +#define PCIM_PSTAT_D3 0x0003 +#define PCIM_PSTAT_DMASK 0x0003 +#define PCIM_PSTAT_NOSOFTRESET 0x0008 +#define PCIM_PSTAT_PMEENABLE 0x0100 +#define PCIM_PSTAT_D0POWER 0x0000 +#define PCIM_PSTAT_D1POWER 0x0200 +#define PCIM_PSTAT_D2POWER 0x0400 +#define PCIM_PSTAT_D3POWER 0x0600 +#define PCIM_PSTAT_D0HEAT 0x0800 +#define PCIM_PSTAT_D1HEAT 0x0a00 +#define PCIM_PSTAT_D2HEAT 0x0c00 +#define PCIM_PSTAT_D3HEAT 0x0e00 +#define PCIM_PSTAT_DATASELMASK 0x1e00 +#define PCIM_PSTAT_DATAUNKN 0x0000 +#define PCIM_PSTAT_DATADIV10 0x2000 +#define PCIM_PSTAT_DATADIV100 0x4000 +#define PCIM_PSTAT_DATADIV1000 0x6000 +#define PCIM_PSTAT_DATADIVMASK 0x6000 +#define PCIM_PSTAT_PME 0x8000 + +#define PCIR_POWER_BSE 0x6 +#define PCIM_PMCSR_BSE_D3B3 0x00 +#define PCIM_PMCSR_BSE_D3B2 0x40 +#define PCIM_PMCSR_BSE_BPCCE 0x80 + +#define PCIR_POWER_DATA 0x7 + +/* VPD capability registers */ +#define PCIR_VPD_ADDR 0x2 +#define PCIR_VPD_DATA 0x4 + +/* PCI Message Signalled Interrupts (MSI) */ +#define PCIR_MSI_CTRL 0x2 +#define PCIM_MSICTRL_VECTOR 0x0100 +#define PCIM_MSICTRL_64BIT 0x0080 +#define PCIM_MSICTRL_MME_MASK 0x0070 +#define PCIM_MSICTRL_MME_1 0x0000 +#define PCIM_MSICTRL_MME_2 0x0010 +#define PCIM_MSICTRL_MME_4 0x0020 +#define PCIM_MSICTRL_MME_8 0x0030 +#define PCIM_MSICTRL_MME_16 0x0040 +#define PCIM_MSICTRL_MME_32 0x0050 +#define PCIM_MSICTRL_MMC_MASK 0x000e +#define PCIM_MSICTRL_MMC_1 0x0000 +#define PCIM_MSICTRL_MMC_2 0x0002 +#define PCIM_MSICTRL_MMC_4 0x0004 +#define PCIM_MSICTRL_MMC_8 0x0006 +#define PCIM_MSICTRL_MMC_16 0x0008 +#define PCIM_MSICTRL_MMC_32 0x000a +#define PCIM_MSICTRL_MSI_ENABLE 0x0001 +#define PCIR_MSI_ADDR 0x4 +#define PCIR_MSI_ADDR_HIGH 0x8 +#define PCIR_MSI_DATA 0x8 +#define PCIR_MSI_DATA_64BIT 0xc +#define PCIR_MSI_MASK 0x10 +#define PCIR_MSI_PENDING 0x14 + +/* PCI Enhanced Allocation registers */ +#define PCIR_EA_NUM_ENT 2 /* Number of Capability Entries */ +#define PCIM_EA_NUM_ENT_MASK 0x3f /* Num Entries Mask */ +#define PCIR_EA_FIRST_ENT 4 /* First EA Entry in List */ +#define PCIR_EA_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */ +#define PCIM_EA_ES 0x00000007 /* Entry Size */ +#define PCIM_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */ +#define PCIM_EA_BEI_OFFSET 4 +/* 0-5 map to BARs 0-5 respectively */ +#define PCIM_EA_BEI_BAR_0 0 +#define PCIM_EA_BEI_BAR_5 5 +#define PCIM_EA_BEI_BAR(x) (((x) >> PCIM_EA_BEI_OFFSET) & 0xf) +#define PCIM_EA_BEI_BRIDGE 0x6 /* Resource behind bridge */ +#define PCIM_EA_BEI_ENI 0x7 /* Equivalent Not Indicated */ +#define PCIM_EA_BEI_ROM 0x8 /* Expansion ROM */ +/* 9-14 map to VF BARs 0-5 respectively */ +#define PCIM_EA_BEI_VF_BAR_0 9 +#define PCIM_EA_BEI_VF_BAR_5 14 +#define PCIM_EA_BEI_RESERVED 0xf /* Reserved - Treat like ENI */ +#define PCIM_EA_PP 0x0000ff00 /* Primary Properties */ +#define PCIM_EA_PP_OFFSET 8 +#define PCIM_EA_SP_OFFSET 16 +#define PCIM_EA_SP 0x00ff0000 /* Secondary Properties */ +#define PCIM_EA_P_MEM 0x00 /* Non-Prefetch Memory */ +#define PCIM_EA_P_MEM_PREFETCH 0x01 /* Prefetchable Memory */ +#define PCIM_EA_P_IO 0x02 /* I/O Space */ +#define PCIM_EA_P_VF_MEM_PREFETCH 0x03 /* VF Prefetchable Memory */ +#define PCIM_EA_P_VF_MEM 0x04 /* VF Non-Prefetch Memory */ +#define PCIM_EA_P_BRIDGE_MEM 0x05 /* Bridge Non-Prefetch Memory */ +#define PCIM_EA_P_BRIDGE_MEM_PREFETCH 0x06 /* Bridge Prefetchable Memory */ +#define PCIM_EA_P_BRIDGE_IO 0x07 /* Bridge I/O Space */ +/* 0x08-0xfc reserved */ +#define PCIM_EA_P_MEM_RESERVED 0xfd /* Reserved Memory */ +#define PCIM_EA_P_IO_RESERVED 0xfe /* Reserved I/O Space */ +#define PCIM_EA_P_UNAVAILABLE 0xff /* Entry Unavailable */ +#define PCIM_EA_WRITABLE 0x40000000 /* Writable: 1 = RW, 0 = HwInit */ +#define PCIM_EA_ENABLE 0x80000000 /* Enable for this entry */ +#define PCIM_EA_BASE 4 /* Base Address Offset */ +#define PCIM_EA_MAX_OFFSET 8 /* MaxOffset (resource length) */ +/* bit 0 is reserved */ +#define PCIM_EA_IS_64 0x00000002 /* 64-bit field flag */ +#define PCIM_EA_FIELD_MASK 0xfffffffc /* For Base & Max Offset */ +/* Bridge config register */ +#define PCIM_EA_SEC_NR(reg) ((reg) & 0xff) +#define PCIM_EA_SUB_NR(reg) (((reg) >> 8) & 0xff) + +/* PCI-X definitions */ + +/* For header type 0 devices */ +#define PCIXR_COMMAND 0x2 +#define PCIXM_COMMAND_DPERR_E 0x0001 /* Data Parity Error Recovery */ +#define PCIXM_COMMAND_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCIXM_COMMAND_MAX_READ 0x000c /* Maximum Burst Read Count */ +#define PCIXM_COMMAND_MAX_READ_512 0x0000 +#define PCIXM_COMMAND_MAX_READ_1024 0x0004 +#define PCIXM_COMMAND_MAX_READ_2048 0x0008 +#define PCIXM_COMMAND_MAX_READ_4096 0x000c +#define PCIXM_COMMAND_MAX_SPLITS 0x0070 /* Maximum Split Transactions */ +#define PCIXM_COMMAND_MAX_SPLITS_1 0x0000 +#define PCIXM_COMMAND_MAX_SPLITS_2 0x0010 +#define PCIXM_COMMAND_MAX_SPLITS_3 0x0020 +#define PCIXM_COMMAND_MAX_SPLITS_4 0x0030 +#define PCIXM_COMMAND_MAX_SPLITS_8 0x0040 +#define PCIXM_COMMAND_MAX_SPLITS_12 0x0050 +#define PCIXM_COMMAND_MAX_SPLITS_16 0x0060 +#define PCIXM_COMMAND_MAX_SPLITS_32 0x0070 +#define PCIXM_COMMAND_VERSION 0x3000 +#define PCIXR_STATUS 0x4 +#define PCIXM_STATUS_DEVFN 0x000000ff +#define PCIXM_STATUS_BUS 0x0000ff00 +#define PCIXM_STATUS_64BIT 0x00010000 +#define PCIXM_STATUS_133CAP 0x00020000 +#define PCIXM_STATUS_SC_DISCARDED 0x00040000 +#define PCIXM_STATUS_UNEXP_SC 0x00080000 +#define PCIXM_STATUS_COMPLEX_DEV 0x00100000 +#define PCIXM_STATUS_MAX_READ 0x00600000 +#define PCIXM_STATUS_MAX_READ_512 0x00000000 +#define PCIXM_STATUS_MAX_READ_1024 0x00200000 +#define PCIXM_STATUS_MAX_READ_2048 0x00400000 +#define PCIXM_STATUS_MAX_READ_4096 0x00600000 +#define PCIXM_STATUS_MAX_SPLITS 0x03800000 +#define PCIXM_STATUS_MAX_SPLITS_1 0x00000000 +#define PCIXM_STATUS_MAX_SPLITS_2 0x00800000 +#define PCIXM_STATUS_MAX_SPLITS_3 0x01000000 +#define PCIXM_STATUS_MAX_SPLITS_4 0x01800000 +#define PCIXM_STATUS_MAX_SPLITS_8 0x02000000 +#define PCIXM_STATUS_MAX_SPLITS_12 0x02800000 +#define PCIXM_STATUS_MAX_SPLITS_16 0x03000000 +#define PCIXM_STATUS_MAX_SPLITS_32 0x03800000 +#define PCIXM_STATUS_MAX_CUM_READ 0x1c000000 +#define PCIXM_STATUS_RCVD_SC_ERR 0x20000000 +#define PCIXM_STATUS_266CAP 0x40000000 +#define PCIXM_STATUS_533CAP 0x80000000 + +/* For header type 1 devices (PCI-X bridges) */ +#define PCIXR_SEC_STATUS 0x2 +#define PCIXM_SEC_STATUS_64BIT 0x0001 +#define PCIXM_SEC_STATUS_133CAP 0x0002 +#define PCIXM_SEC_STATUS_SC_DISC 0x0004 +#define PCIXM_SEC_STATUS_UNEXP_SC 0x0008 +#define PCIXM_SEC_STATUS_SC_OVERRUN 0x0010 +#define PCIXM_SEC_STATUS_SR_DELAYED 0x0020 +#define PCIXM_SEC_STATUS_BUS_MODE 0x03c0 +#define PCIXM_SEC_STATUS_VERSION 0x3000 +#define PCIXM_SEC_STATUS_266CAP 0x4000 +#define PCIXM_SEC_STATUS_533CAP 0x8000 +#define PCIXR_BRIDGE_STATUS 0x4 +#define PCIXM_BRIDGE_STATUS_DEVFN 0x000000ff +#define PCIXM_BRIDGE_STATUS_BUS 0x0000ff00 +#define PCIXM_BRIDGE_STATUS_64BIT 0x00010000 +#define PCIXM_BRIDGE_STATUS_133CAP 0x00020000 +#define PCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000 +#define PCIXM_BRIDGE_STATUS_UNEXP_SC 0x00080000 +#define PCIXM_BRIDGE_STATUS_SC_OVERRUN 0x00100000 +#define PCIXM_BRIDGE_STATUS_SR_DELAYED 0x00200000 +#define PCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000 +#define PCIXM_BRIDGE_STATUS_266CAP 0x40000000 +#define PCIXM_BRIDGE_STATUS_533CAP 0x80000000 + +/* HT (HyperTransport) Capability definitions */ +#define PCIR_HT_COMMAND 0x2 +#define PCIM_HTCMD_CAP_MASK 0xf800 /* Capability type. */ +#define PCIM_HTCAP_SLAVE 0x0000 /* 000xx */ +#define PCIM_HTCAP_HOST 0x2000 /* 001xx */ +#define PCIM_HTCAP_SWITCH 0x4000 /* 01000 */ +#define PCIM_HTCAP_INTERRUPT 0x8000 /* 10000 */ +#define PCIM_HTCAP_REVISION_ID 0x8800 /* 10001 */ +#define PCIM_HTCAP_UNITID_CLUMPING 0x9000 /* 10010 */ +#define PCIM_HTCAP_EXT_CONFIG_SPACE 0x9800 /* 10011 */ +#define PCIM_HTCAP_ADDRESS_MAPPING 0xa000 /* 10100 */ +#define PCIM_HTCAP_MSI_MAPPING 0xa800 /* 10101 */ +#define PCIM_HTCAP_DIRECT_ROUTE 0xb000 /* 10110 */ +#define PCIM_HTCAP_VCSET 0xb800 /* 10111 */ +#define PCIM_HTCAP_RETRY_MODE 0xc000 /* 11000 */ +#define PCIM_HTCAP_X86_ENCODING 0xc800 /* 11001 */ +#define PCIM_HTCAP_GEN3 0xd000 /* 11010 */ +#define PCIM_HTCAP_FLE 0xd800 /* 11011 */ +#define PCIM_HTCAP_PM 0xe000 /* 11100 */ +#define PCIM_HTCAP_HIGH_NODE_COUNT 0xe800 /* 11101 */ + +/* HT MSI Mapping Capability definitions. */ +#define PCIM_HTCMD_MSI_ENABLE 0x0001 +#define PCIM_HTCMD_MSI_FIXED 0x0002 +#define PCIR_HTMSI_ADDRESS_LO 0x4 +#define PCIR_HTMSI_ADDRESS_HI 0x8 + +/* PCI Vendor capability definitions */ +#define PCIR_VENDOR_LENGTH 0x2 +#define PCIR_VENDOR_DATA 0x3 + +/* PCI Device capability definitions */ +#define PCIR_DEVICE_LENGTH 0x2 + +/* PCI EHCI Debug Port definitions */ +#define PCIR_DEBUG_PORT 0x2 +#define PCIM_DEBUG_PORT_OFFSET 0x1fff +#define PCIM_DEBUG_PORT_BAR 0xe000 + +/* PCI-PCI Bridge Subvendor definitions */ +#define PCIR_SUBVENDCAP_ID 0x4 +#define PCIR_SUBVENDCAP 0x4 +#define PCIR_SUBDEVCAP 0x6 + +/* PCI Express definitions */ +#define PCIER_FLAGS 0x2 +#define PCIEM_FLAGS_VERSION 0x000f +#define PCIEM_FLAGS_TYPE 0x00f0 +#define PCIEM_TYPE_ENDPOINT 0x0000 +#define PCIEM_TYPE_LEGACY_ENDPOINT 0x0010 +#define PCIEM_TYPE_ROOT_PORT 0x0040 +#define PCIEM_TYPE_UPSTREAM_PORT 0x0050 +#define PCIEM_TYPE_DOWNSTREAM_PORT 0x0060 +#define PCIEM_TYPE_PCI_BRIDGE 0x0070 +#define PCIEM_TYPE_PCIE_BRIDGE 0x0080 +#define PCIEM_TYPE_ROOT_INT_EP 0x0090 +#define PCIEM_TYPE_ROOT_EC 0x00a0 +#define PCIEM_FLAGS_SLOT 0x0100 +#define PCIEM_FLAGS_IRQ 0x3e00 +#define PCIER_DEVICE_CAP 0x4 +#define PCIEM_CAP_MAX_PAYLOAD 0x00000007 +#define PCIEM_CAP_PHANTHOM_FUNCS 0x00000018 +#define PCIEM_CAP_EXT_TAG_FIELD 0x00000020 +#define PCIEM_CAP_L0S_LATENCY 0x000001c0 +#define PCIEM_CAP_L1_LATENCY 0x00000e00 +#define PCIEM_CAP_ROLE_ERR_RPT 0x00008000 +#define PCIEM_CAP_SLOT_PWR_LIM_VAL 0x03fc0000 +#define PCIEM_CAP_SLOT_PWR_LIM_SCALE 0x0c000000 +#define PCIEM_CAP_FLR 0x10000000 +#define PCIER_DEVICE_CTL 0x8 +#define PCIEM_CTL_COR_ENABLE 0x0001 +#define PCIEM_CTL_NFER_ENABLE 0x0002 +#define PCIEM_CTL_FER_ENABLE 0x0004 +#define PCIEM_CTL_URR_ENABLE 0x0008 +#define PCIEM_CTL_RELAXED_ORD_ENABLE 0x0010 +#define PCIEM_CTL_MAX_PAYLOAD 0x00e0 +#define PCIEM_CTL_EXT_TAG_FIELD 0x0100 +#define PCIEM_CTL_PHANTHOM_FUNCS 0x0200 +#define PCIEM_CTL_AUX_POWER_PM 0x0400 +#define PCIEM_CTL_NOSNOOP_ENABLE 0x0800 +#define PCIEM_CTL_MAX_READ_REQUEST 0x7000 +#define PCIEM_CTL_BRDG_CFG_RETRY 0x8000 /* PCI-E - PCI/PCI-X bridges */ +#define PCIEM_CTL_INITIATE_FLR 0x8000 /* FLR capable endpoints */ +#define PCIER_DEVICE_STA 0xa +#define PCIEM_STA_CORRECTABLE_ERROR 0x0001 +#define PCIEM_STA_NON_FATAL_ERROR 0x0002 +#define PCIEM_STA_FATAL_ERROR 0x0004 +#define PCIEM_STA_UNSUPPORTED_REQ 0x0008 +#define PCIEM_STA_AUX_POWER 0x0010 +#define PCIEM_STA_TRANSACTION_PND 0x0020 +#define PCIER_LINK_CAP 0xc +#define PCIEM_LINK_CAP_MAX_SPEED 0x0000000f +#define PCIEM_LINK_CAP_MAX_WIDTH 0x000003f0 +#define PCIEM_LINK_CAP_ASPM 0x00000c00 +#define PCIEM_LINK_CAP_L0S_EXIT 0x00007000 +#define PCIEM_LINK_CAP_L1_EXIT 0x00038000 +#define PCIEM_LINK_CAP_CLOCK_PM 0x00040000 +#define PCIEM_LINK_CAP_SURPRISE_DOWN 0x00080000 +#define PCIEM_LINK_CAP_DL_ACTIVE 0x00100000 +#define PCIEM_LINK_CAP_LINK_BW_NOTIFY 0x00200000 +#define PCIEM_LINK_CAP_ASPM_COMPLIANCE 0x00400000 +#define PCIEM_LINK_CAP_PORT 0xff000000 +#define PCIER_LINK_CTL 0x10 +#define PCIEM_LINK_CTL_ASPMC_DIS 0x0000 +#define PCIEM_LINK_CTL_ASPMC_L0S 0x0001 +#define PCIEM_LINK_CTL_ASPMC_L1 0x0002 +#define PCIEM_LINK_CTL_ASPMC 0x0003 +#define PCIEM_LINK_CTL_RCB 0x0008 +#define PCIEM_LINK_CTL_LINK_DIS 0x0010 +#define PCIEM_LINK_CTL_RETRAIN_LINK 0x0020 +#define PCIEM_LINK_CTL_COMMON_CLOCK 0x0040 +#define PCIEM_LINK_CTL_EXTENDED_SYNC 0x0080 +#define PCIEM_LINK_CTL_ECPM 0x0100 +#define PCIEM_LINK_CTL_HAWD 0x0200 +#define PCIEM_LINK_CTL_LBMIE 0x0400 +#define PCIEM_LINK_CTL_LABIE 0x0800 +#define PCIER_LINK_STA 0x12 +#define PCIEM_LINK_STA_SPEED 0x000f +#define PCIEM_LINK_STA_WIDTH 0x03f0 +#define PCIEM_LINK_STA_TRAINING_ERROR 0x0400 +#define PCIEM_LINK_STA_TRAINING 0x0800 +#define PCIEM_LINK_STA_SLOT_CLOCK 0x1000 +#define PCIEM_LINK_STA_DL_ACTIVE 0x2000 +#define PCIEM_LINK_STA_LINK_BW_MGMT 0x4000 +#define PCIEM_LINK_STA_LINK_AUTO_BW 0x8000 +#define PCIER_SLOT_CAP 0x14 +#define PCIEM_SLOT_CAP_APB 0x00000001 +#define PCIEM_SLOT_CAP_PCP 0x00000002 +#define PCIEM_SLOT_CAP_MRLSP 0x00000004 +#define PCIEM_SLOT_CAP_AIP 0x00000008 +#define PCIEM_SLOT_CAP_PIP 0x00000010 +#define PCIEM_SLOT_CAP_HPS 0x00000020 +#define PCIEM_SLOT_CAP_HPC 0x00000040 +#define PCIEM_SLOT_CAP_SPLV 0x00007f80 +#define PCIEM_SLOT_CAP_SPLS 0x00018000 +#define PCIEM_SLOT_CAP_EIP 0x00020000 +#define PCIEM_SLOT_CAP_NCCS 0x00040000 +#define PCIEM_SLOT_CAP_PSN 0xfff80000 +#define PCIER_SLOT_CTL 0x18 +#define PCIEM_SLOT_CTL_ABPE 0x0001 +#define PCIEM_SLOT_CTL_PFDE 0x0002 +#define PCIEM_SLOT_CTL_MRLSCE 0x0004 +#define PCIEM_SLOT_CTL_PDCE 0x0008 +#define PCIEM_SLOT_CTL_CCIE 0x0010 +#define PCIEM_SLOT_CTL_HPIE 0x0020 +#define PCIEM_SLOT_CTL_AIC 0x00c0 +#define PCIEM_SLOT_CTL_AI_ON 0x0040 +#define PCIEM_SLOT_CTL_AI_BLINK 0x0080 +#define PCIEM_SLOT_CTL_AI_OFF 0x00c0 +#define PCIEM_SLOT_CTL_PIC 0x0300 +#define PCIEM_SLOT_CTL_PI_ON 0x0100 +#define PCIEM_SLOT_CTL_PI_BLINK 0x0200 +#define PCIEM_SLOT_CTL_PI_OFF 0x0300 +#define PCIEM_SLOT_CTL_PCC 0x0400 +#define PCIEM_SLOT_CTL_PC_ON 0x0000 +#define PCIEM_SLOT_CTL_PC_OFF 0x0400 +#define PCIEM_SLOT_CTL_EIC 0x0800 +#define PCIEM_SLOT_CTL_DLLSCE 0x1000 +#define PCIER_SLOT_STA 0x1a +#define PCIEM_SLOT_STA_ABP 0x0001 +#define PCIEM_SLOT_STA_PFD 0x0002 +#define PCIEM_SLOT_STA_MRLSC 0x0004 +#define PCIEM_SLOT_STA_PDC 0x0008 +#define PCIEM_SLOT_STA_CC 0x0010 +#define PCIEM_SLOT_STA_MRLSS 0x0020 +#define PCIEM_SLOT_STA_PDS 0x0040 +#define PCIEM_SLOT_STA_EIS 0x0080 +#define PCIEM_SLOT_STA_DLLSC 0x0100 +#define PCIER_ROOT_CTL 0x1c +#define PCIEM_ROOT_CTL_SERR_CORR 0x0001 +#define PCIEM_ROOT_CTL_SERR_NONFATAL 0x0002 +#define PCIEM_ROOT_CTL_SERR_FATAL 0x0004 +#define PCIEM_ROOT_CTL_PME 0x0008 +#define PCIEM_ROOT_CTL_CRS_VIS 0x0010 +#define PCIER_ROOT_CAP 0x1e +#define PCIEM_ROOT_CAP_CRS_VIS 0x0001 +#define PCIER_ROOT_STA 0x20 +#define PCIEM_ROOT_STA_PME_REQID_MASK 0x0000ffff +#define PCIEM_ROOT_STA_PME_STATUS 0x00010000 +#define PCIEM_ROOT_STA_PME_PEND 0x00020000 +#define PCIER_DEVICE_CAP2 0x24 +#define PCIEM_CAP2_COMP_TIMO_RANGES 0x0000000f +#define PCIEM_CAP2_COMP_TIMO_RANGE_A 0x00000001 +#define PCIEM_CAP2_COMP_TIMO_RANGE_B 0x00000002 +#define PCIEM_CAP2_COMP_TIMO_RANGE_C 0x00000004 +#define PCIEM_CAP2_COMP_TIMO_RANGE_D 0x00000008 +#define PCIEM_CAP2_COMP_TIMO_DISABLE 0x00000010 +#define PCIEM_CAP2_ARI 0x00000020 +#define PCIER_DEVICE_CTL2 0x28 +#define PCIEM_CTL2_COMP_TIMO_VAL 0x000f +#define PCIEM_CTL2_COMP_TIMO_50MS 0x0000 +#define PCIEM_CTL2_COMP_TIMO_100US 0x0001 +#define PCIEM_CTL2_COMP_TIMO_10MS 0x0002 +#define PCIEM_CTL2_COMP_TIMO_55MS 0x0005 +#define PCIEM_CTL2_COMP_TIMO_210MS 0x0006 +#define PCIEM_CTL2_COMP_TIMO_900MS 0x0009 +#define PCIEM_CTL2_COMP_TIMO_3500MS 0x000a +#define PCIEM_CTL2_COMP_TIMO_13S 0x000d +#define PCIEM_CTL2_COMP_TIMO_64S 0x000e +#define PCIEM_CTL2_COMP_TIMO_DISABLE 0x0010 +#define PCIEM_CTL2_ARI 0x0020 +#define PCIEM_CTL2_ATOMIC_REQ_ENABLE 0x0040 +#define PCIEM_CTL2_ATOMIC_EGR_BLOCK 0x0080 +#define PCIEM_CTL2_ID_ORDERED_REQ_EN 0x0100 +#define PCIEM_CTL2_ID_ORDERED_CMP_EN 0x0200 +#define PCIEM_CTL2_LTR_ENABLE 0x0400 +#define PCIEM_CTL2_OBFF 0x6000 +#define PCIEM_OBFF_DISABLE 0x0000 +#define PCIEM_OBFF_MSGA_ENABLE 0x2000 +#define PCIEM_OBFF_MSGB_ENABLE 0x4000 +#define PCIEM_OBFF_WAKE_ENABLE 0x6000 +#define PCIEM_CTL2_END2END_TLP 0x8000 +#define PCIER_DEVICE_STA2 0x2a +#define PCIER_LINK_CAP2 0x2c +#define PCIER_LINK_CTL2 0x30 +#define PCIER_LINK_STA2 0x32 +#define PCIER_SLOT_CAP2 0x34 +#define PCIER_SLOT_CTL2 0x38 +#define PCIER_SLOT_STA2 0x3a + +/* MSI-X definitions */ +#define PCIR_MSIX_CTRL 0x2 +#define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 +#define PCIM_MSIXCTRL_FUNCTION_MASK 0x4000 +#define PCIM_MSIXCTRL_TABLE_SIZE 0x07ff +#define PCIR_MSIX_TABLE 0x4 +#define PCIR_MSIX_PBA 0x8 +#define PCIM_MSIX_BIR_MASK 0x7 +#define PCIM_MSIX_BIR_BAR_10 0 +#define PCIM_MSIX_BIR_BAR_14 1 +#define PCIM_MSIX_BIR_BAR_18 2 +#define PCIM_MSIX_BIR_BAR_1C 3 +#define PCIM_MSIX_BIR_BAR_20 4 +#define PCIM_MSIX_BIR_BAR_24 5 +#define PCIM_MSIX_VCTRL_MASK 0x1 + +/* PCI Advanced Features definitions */ +#define PCIR_PCIAF_CAP 0x3 +#define PCIM_PCIAFCAP_TP 0x01 +#define PCIM_PCIAFCAP_FLR 0x02 +#define PCIR_PCIAF_CTRL 0x4 +#define PCIR_PCIAFCTRL_FLR 0x01 +#define PCIR_PCIAF_STATUS 0x5 +#define PCIR_PCIAFSTATUS_TP 0x01 + +/* Advanced Error Reporting */ +#define PCIR_AER_UC_STATUS 0x04 +#define PCIM_AER_UC_TRAINING_ERROR 0x00000001 +#define PCIM_AER_UC_DL_PROTOCOL_ERROR 0x00000010 +#define PCIM_AER_UC_SURPRISE_LINK_DOWN 0x00000020 +#define PCIM_AER_UC_POISONED_TLP 0x00001000 +#define PCIM_AER_UC_FC_PROTOCOL_ERROR 0x00002000 +#define PCIM_AER_UC_COMPLETION_TIMEOUT 0x00004000 +#define PCIM_AER_UC_COMPLETER_ABORT 0x00008000 +#define PCIM_AER_UC_UNEXPECTED_COMPLETION 0x00010000 +#define PCIM_AER_UC_RECEIVER_OVERFLOW 0x00020000 +#define PCIM_AER_UC_MALFORMED_TLP 0x00040000 +#define PCIM_AER_UC_ECRC_ERROR 0x00080000 +#define PCIM_AER_UC_UNSUPPORTED_REQUEST 0x00100000 +#define PCIM_AER_UC_ACS_VIOLATION 0x00200000 +#define PCIM_AER_UC_INTERNAL_ERROR 0x00400000 +#define PCIM_AER_UC_MC_BLOCKED_TLP 0x00800000 +#define PCIM_AER_UC_ATOMIC_EGRESS_BLK 0x01000000 +#define PCIM_AER_UC_TLP_PREFIX_BLOCKED 0x02000000 +#define PCIR_AER_UC_MASK 0x08 /* Shares bits with UC_STATUS */ +#define PCIR_AER_UC_SEVERITY 0x0c /* Shares bits with UC_STATUS */ +#define PCIR_AER_COR_STATUS 0x10 +#define PCIM_AER_COR_RECEIVER_ERROR 0x00000001 +#define PCIM_AER_COR_BAD_TLP 0x00000040 +#define PCIM_AER_COR_BAD_DLLP 0x00000080 +#define PCIM_AER_COR_REPLAY_ROLLOVER 0x00000100 +#define PCIM_AER_COR_REPLAY_TIMEOUT 0x00001000 +#define PCIM_AER_COR_ADVISORY_NF_ERROR 0x00002000 +#define PCIM_AER_COR_INTERNAL_ERROR 0x00004000 +#define PCIM_AER_COR_HEADER_LOG_OVFLOW 0x00008000 +#define PCIR_AER_COR_MASK 0x14 /* Shares bits with COR_STATUS */ +#define PCIR_AER_CAP_CONTROL 0x18 +#define PCIM_AER_FIRST_ERROR_PTR 0x0000001f +#define PCIM_AER_ECRC_GEN_CAPABLE 0x00000020 +#define PCIM_AER_ECRC_GEN_ENABLE 0x00000040 +#define PCIM_AER_ECRC_CHECK_CAPABLE 0x00000080 +#define PCIM_AER_ECRC_CHECK_ENABLE 0x00000100 +#define PCIM_AER_MULT_HDR_CAPABLE 0x00000200 +#define PCIM_AER_MULT_HDR_ENABLE 0x00000400 +#define PCIM_AER_TLP_PREFIX_LOG_PRESENT 0x00000800 +#define PCIR_AER_HEADER_LOG 0x1c +#define PCIR_AER_ROOTERR_CMD 0x2c /* Only for root complex ports */ +#define PCIM_AER_ROOTERR_COR_ENABLE 0x00000001 +#define PCIM_AER_ROOTERR_NF_ENABLE 0x00000002 +#define PCIM_AER_ROOTERR_F_ENABLE 0x00000004 +#define PCIR_AER_ROOTERR_STATUS 0x30 /* Only for root complex ports */ +#define PCIM_AER_ROOTERR_COR_ERR 0x00000001 +#define PCIM_AER_ROOTERR_MULTI_COR_ERR 0x00000002 +#define PCIM_AER_ROOTERR_UC_ERR 0x00000004 +#define PCIM_AER_ROOTERR_MULTI_UC_ERR 0x00000008 +#define PCIM_AER_ROOTERR_FIRST_UC_FATAL 0x00000010 +#define PCIM_AER_ROOTERR_NF_ERR 0x00000020 +#define PCIM_AER_ROOTERR_F_ERR 0x00000040 +#define PCIM_AER_ROOTERR_INT_MESSAGE 0xf8000000 +#define PCIR_AER_COR_SOURCE_ID 0x34 /* Only for root complex ports */ +#define PCIR_AER_ERR_SOURCE_ID 0x36 /* Only for root complex ports */ +#define PCIR_AER_TLP_PREFIX_LOG 0x38 /* Only for TLP prefix functions */ + +/* Virtual Channel definitions */ +#define PCIR_VC_CAP1 0x04 +#define PCIM_VC_CAP1_EXT_COUNT 0x00000007 +#define PCIM_VC_CAP1_LOWPRI_EXT_COUNT 0x00000070 +#define PCIR_VC_CAP2 0x08 +#define PCIR_VC_CONTROL 0x0c +#define PCIR_VC_STATUS 0x0e +#define PCIR_VC_RESOURCE_CAP(n) (0x10 + (n) * 0x0c) +#define PCIR_VC_RESOURCE_CTL(n) (0x14 + (n) * 0x0c) +#define PCIR_VC_RESOURCE_STA(n) (0x18 + (n) * 0x0c) + +/* Serial Number definitions */ +#define PCIR_SERIAL_LOW 0x04 +#define PCIR_SERIAL_HIGH 0x08 + +/* SR-IOV definitions */ +#define PCIR_SRIOV_CTL 0x08 +#define PCIM_SRIOV_VF_EN 0x01 +#define PCIM_SRIOV_VF_MSE 0x08 /* Memory space enable. */ +#define PCIM_SRIOV_ARI_EN 0x10 +#define PCIR_SRIOV_TOTAL_VFS 0x0e +#define PCIR_SRIOV_NUM_VFS 0x10 +#define PCIR_SRIOV_VF_OFF 0x14 +#define PCIR_SRIOV_VF_STRIDE 0x16 +#define PCIR_SRIOV_VF_DID 0x1a +#define PCIR_SRIOV_PAGE_CAP 0x1c +#define PCIR_SRIOV_PAGE_SIZE 0x20 + +#define PCI_SRIOV_BASE_PAGE_SHIFT 12 + +#define PCIR_SRIOV_BARS 0x24 +#define PCIR_SRIOV_BAR(x) (PCIR_SRIOV_BARS + (x) * 4) + +/* Extended Capability Vendor-Specific definitions */ +#define PCIR_VSEC_HEADER 0x04 +#define PCIR_VSEC_ID(hdr) ((hdr) & 0xffff) +#define PCIR_VSEC_REV(hdr) (((hdr) & 0xf0000) >> 16) +#define PCIR_VSEC_LENGTH(hdr) (((hdr) & 0xfff00000) >> 20) +#define PCIR_VSEC_DATA 0x08 + +/* + * PCI Express Firmware Interface definitions + */ +#define PCI_OSC_STATUS 0 +#define PCI_OSC_SUPPORT 1 +#define PCIM_OSC_SUPPORT_EXT_PCI_CONF 0x01 /* Extended PCI Config Space */ +#define PCIM_OSC_SUPPORT_ASPM 0x02 /* Active State Power Management */ +#define PCIM_OSC_SUPPORT_CPMC 0x04 /* Clock Power Management Cap */ +#define PCIM_OSC_SUPPORT_SEG_GROUP 0x08 /* PCI Segment Groups supported */ +#define PCIM_OSC_SUPPORT_MSI 0x10 /* MSI signalling supported */ +#define PCI_OSC_CTL 2 +#define PCIM_OSC_CTL_PCIE_HP 0x01 /* PCIe Native Hot Plug */ +#define PCIM_OSC_CTL_SHPC_HP 0x02 /* SHPC Native Hot Plug */ +#define PCIM_OSC_CTL_PCIE_PME 0x04 /* PCIe Native Power Mgt Events */ +#define PCIM_OSC_CTL_PCIE_AER 0x08 /* PCIe Advanced Error Reporting */ +#define PCIM_OSC_CTL_PCIE_CAP_STRUCT 0x10 /* Various Capability Structures */ + +#endif /* __PCI_REGS_H__ */ diff --git a/components/drivers/pci/probe.c b/components/drivers/pci/probe.c new file mode 100644 index 000000000000..4303e9029e1c --- /dev/null +++ b/components/drivers/pci/probe.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "pci.probe" +#define DBG_LVL DBG_INFO +#include + +#include + +struct rt_pci_host_bridge *rt_pci_host_bridge_alloc(rt_size_t priv_size) +{ + struct rt_pci_host_bridge *bridge = rt_calloc(1, sizeof(bridge) + priv_size); + + return bridge; +} + +rt_err_t rt_pci_host_bridge_init(struct rt_pci_host_bridge *host_bridge) +{ + rt_err_t err = RT_EOK; + + if (host_bridge->parent.ofw_node) + { + err = rt_pci_ofw_host_bridge_init(host_bridge->parent.ofw_node, host_bridge); + } + + return err; +} + +struct rt_pci_device *rt_pci_alloc_device(struct rt_pci_bus *bus) +{ + struct rt_pci_device *pdev = rt_calloc(1, sizeof(*pdev)); + + if (!pdev) + { + return RT_NULL; + } + + rt_list_init(&pdev->list_in_bus); + pdev->bus = bus; + + if (bus) + { + rt_list_insert_before(&bus->devices_nodes, &pdev->list_in_bus); + } + + pdev->subsystem_vendor = PCI_ANY_ID; + pdev->subsystem_device = PCI_ANY_ID; + + pdev->irq = -1; + + for (int i = 0; i < RT_ARRAY_SIZE(pdev->resource); ++i) + { + pdev->resource[i].flags = PCI_BUS_REGION_F_NONE; + } + +#ifdef RT_PCI_MSI + rt_list_init(&pdev->msi_desc_nodes); + rt_spin_lock_init(&pdev->msi_lock); +#endif + + return pdev; +} + +struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint32_t devfn) +{ + struct rt_pci_device *pdev = RT_NULL; + rt_uint16_t vendor = PCI_ANY_ID, device = PCI_ANY_ID; + + if (!bus) + { + goto _end; + } + + rt_pci_bus_read_config_u16(bus, devfn, PCIR_VENDOR, &vendor); + rt_pci_bus_read_config_u16(bus, devfn, PCIR_DEVICE, &device); + + if (vendor == (typeof(vendor))PCI_ANY_ID) + { + goto _end; + } + + if (!(pdev = rt_pci_alloc_device(bus))) + { + goto _end; + } + + pdev->devfn = devfn; + pdev->vendor = vendor; + pdev->device = device; + + rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%d", + rt_pci_domain(pdev), pdev->bus->number, RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn)); + + if (rt_pci_setup_device(pdev)) + { + rt_free(pdev); + pdev = RT_NULL; + + goto _end; + } + + rt_pci_device_register(pdev); + +_end: + return pdev; +} + +static rt_bool_t pci_intx_mask_broken(struct rt_pci_device *pdev) +{ + rt_bool_t res = RT_FALSE; + rt_uint16_t orig, toggle, new; + + rt_pci_read_config_u16(pdev, PCIR_COMMAND, &orig); + toggle = orig ^ PCIM_CMD_INTxDIS; + rt_pci_write_config_u16(pdev, PCIR_COMMAND, toggle); + rt_pci_read_config_u16(pdev, PCIR_COMMAND, &new); + + rt_pci_write_config_u16(pdev, PCIR_COMMAND, orig); + + if (new != toggle) + { + res = RT_TRUE; + } + + return res; +} + +static void pci_read_irq(struct rt_pci_device *pdev) +{ + rt_uint8_t irq = 0; + + rt_pci_read_config_u8(pdev, PCIR_INTPIN, &irq); + pdev->pin = irq; + + if (irq) + { + rt_pci_read_config_u8(pdev, PCIR_INTLINE, &irq); + } + pdev->irq = irq; +} + +static void pcie_set_port_type(struct rt_pci_device *pdev) +{ + int pos; + + if (!(pos = rt_pci_find_capability(pdev, PCIY_EXPRESS))) + { + return; + } + + pdev->pcie_cap = pos; +} + +static void pci_init_capabilities(struct rt_pci_device *pdev) +{ +#ifdef RT_PCI_MSI + rt_pci_msi_init(pdev); /* Disable MSI */ + rt_pci_msix_init(pdev); /* Disable MSI-X */ +#endif + + pcie_set_port_type(pdev); + + rt_pci_device_clear_flag(pdev, PCI_F_NO_MSI); + rt_pci_device_clear_flag(pdev, PCI_F_MSI); + rt_pci_device_clear_flag(pdev, PCI_F_MSIX); +} + +rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev) +{ + rt_uint8_t pos; + rt_uint32_t class = 0; + struct rt_pci_host_bridge *host_bridge; + + if (!pdev) + { + return -RT_EINVAL; + } + + if (!(host_bridge = rt_pci_find_host_bridge(pdev->bus))) + { + return -RT_EINVAL; + } + + rt_pci_ofw_device_init(pdev); + + rt_pci_read_config_u32(pdev, PCIR_REVID, &class); + + pdev->revision = class & 0xff; + pdev->class = class >> 8; /* Upper 3 bytes */ + rt_pci_read_config_u8(pdev, PCIR_HDRTYPE, &pdev->hdr_type); + + /* Clear errors left from system firmware */ + rt_pci_write_config_u16(pdev, PCIR_STATUS, 0xffff); + + if (pdev->hdr_type & 0x80) + { + rt_pci_device_set_flag(pdev, PCI_F_MULTI_FUNCTION); + } + pdev->hdr_type &= PCIM_HDRTYPE; + + if (pci_intx_mask_broken(pdev)) + { + rt_pci_device_set_flag(pdev, PCI_F_BROKEN_INTX_MASKING); + } + + rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%d", rt_pci_domain(pdev), + pdev->bus->number, RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn)); + + switch (pdev->hdr_type) + { + case PCIM_HDRTYPE_NORMAL: + if (class == PCIS_BRIDGE_PCI) + { + goto error; + } + pci_read_irq(pdev); + rt_pci_device_alloc_resource(host_bridge, pdev); + rt_pci_read_config_u16(pdev, PCIR_SUBVEND_0, &pdev->subsystem_vendor); + rt_pci_read_config_u16(pdev, PCIR_SUBDEV_0, &pdev->subsystem_device); + break; + + case PCIM_HDRTYPE_BRIDGE: + pci_read_irq(pdev); + rt_pci_device_alloc_resource(host_bridge, pdev); + pos = rt_pci_find_capability(pdev, PCIY_SUBVENDOR); + if (pos) + { + rt_pci_read_config_u16(pdev, PCIR_SUBVENDCAP, &pdev->subsystem_vendor); + rt_pci_read_config_u16(pdev, PCIR_SUBDEVCAP, &pdev->subsystem_device); + } + break; + + case PCIM_HDRTYPE_CARDBUS: + if (class != PCIS_BRIDGE_CARDBUS) + { + goto error; + } + pci_read_irq(pdev); + rt_pci_device_alloc_resource(host_bridge, pdev); + rt_pci_read_config_u16(pdev, PCIR_SUBVEND_2, &pdev->subsystem_vendor); + rt_pci_read_config_u16(pdev, PCIR_SUBDEV_2, &pdev->subsystem_device); + break; + + default: + LOG_E("Ignoring device unknown header type %02x", pdev->hdr_type); + return -RT_EIO; + + error: + LOG_E("Ignoring class %08x (doesn't match header type %02x)", pdev->class, pdev->hdr_type); + pdev->class = PCIC_NOT_DEFINED << 8; + } + + pci_init_capabilities(pdev); + + return RT_EOK; +} + +static rt_uint32_t pci_scan_bridge_extend(struct rt_pci_bus *bus, struct rt_pci_device *pdev, + rt_uint32_t bus_no_start, rt_uint32_t buses, rt_bool_t reconfigured) +{ + rt_bool_t broken = RT_FALSE, is_cardbus; + rt_uint8_t primary, secondary, subordinate; + rt_uint32_t value, bus_no = bus_no_start, next_busnr; + + is_cardbus = (pdev->hdr_type == PCIM_HDRTYPE_CARDBUS); + + rt_pci_read_config_u32(pdev, PCIR_PRIBUS_1, &value); + primary = value & 0xff; + secondary = (value >> 8) & 0xff; + subordinate = (value >> 16) & 0xff; + + LOG_D("Scanning [bus %02x-%02x] behind bridge, reconfigured %d", + secondary, subordinate, reconfigured); + + if (!primary && (primary != bus->number) && secondary && subordinate) + { + LOG_W("Primary bus is hard wired to 0"); + + primary = bus->number; + } + + /* Check if setup is sensible at all */ + if (!reconfigured && (primary != bus->number || secondary <= bus->number || + secondary > subordinate)) + { + LOG_I("Bridge configuration invalid ([bus %02x-%02x]), reconfiguring", + secondary, subordinate); + + broken = RT_TRUE; + } + + if ((secondary || subordinate) && !is_cardbus && !broken) + { + next_busnr = secondary; + } + else + { + next_busnr = bus_no_start + 1; + } + + LOG_I("Found: PCI %sBus %04x:%02x", is_cardbus ? "Card" : "", + rt_pci_domain(pdev), next_busnr); + + /* + * We should init bridge here, but the PCI bridges are always used in the PC + * servers. We just output the bridge information to develop. + */ + + return bus_no; +} + +rt_uint32_t rt_pci_scan_bridge(struct rt_pci_bus *bus, struct rt_pci_device *pdev, + rt_uint32_t bus_no_start, rt_bool_t reconfigured) +{ + if (!bus || !pdev) + { + return RT_UINT32_MAX; + } + + return pci_scan_bridge_extend(bus, pdev, bus_no_start, 0, reconfigured); +} + +rt_size_t rt_pci_scan_slot(struct rt_pci_bus *bus, rt_uint32_t devfn) +{ + rt_size_t nr = 0; + + if (!bus) + { + goto _end; + } + + for (int func = 0; func < RT_PCI_FUNCTION_MAX; ++func, ++devfn) + { + struct rt_pci_device *pdev = rt_pci_scan_single_device(bus, devfn); + + if (pdev) + { + ++nr; + + /* If this is a single function device, don't scan past the first function. */ + if (!rt_pci_device_test_flag(pdev, PCI_F_MULTI_FUNCTION)) + { + if (func > 0) + { + rt_pci_device_set_flag(pdev, PCI_F_MULTI_FUNCTION); + } + else + { + break; + } + } + } + else if (func == 0) + { + break; + } + } + +_end: + return nr; +} + +rt_uint32_t rt_pci_scan_child_buses(struct rt_pci_bus *bus, rt_size_t buses) +{ + rt_uint32_t bus_no; + struct rt_pci_device *pdev = RT_NULL; + + if (!bus) + { + bus_no = RT_UINT32_MAX; + + goto _end; + } + + bus_no = bus->number; + + for (rt_uint32_t devfn = 0; + devfn < RT_PCI_DEVFN(RT_PCI_DEVICE_MAX - 1, RT_PCI_FUNCTION_MAX - 1); + devfn += RT_PCI_FUNCTION_MAX) + { + rt_pci_scan_slot(bus, devfn); + } + + rt_pci_foreach_bridge(pdev, bus) + { + int offset; + + bus_no = pci_scan_bridge_extend(bus, pdev, bus_no, buses, RT_FALSE); + offset = bus_no - bus->number; + + if (buses > offset) + { + buses -= offset; + } + else + { + break; + } + } + +_end: + return bus_no; +} + +rt_uint32_t rt_pci_scan_child_bus(struct rt_pci_bus *bus) +{ + return rt_pci_scan_child_buses(bus, 0); +} + +static struct rt_pci_bus *pci_alloc_bus(struct rt_pci_bus *parent) +{ + struct rt_pci_bus *bus = rt_calloc(1, sizeof(*bus)); + + if (!bus) + { + return RT_NULL; + } + + bus->parent = parent; + + rt_list_init(&bus->list); + rt_list_init(&bus->children_nodes); + rt_list_init(&bus->devices_nodes); + + return bus; +} + +rt_err_t rt_pci_host_bridge_register(struct rt_pci_host_bridge *host_bridge) +{ + struct rt_pci_bus *bus = pci_alloc_bus(RT_NULL); + + if (!bus) + { + return -RT_ENOMEM; + } + + host_bridge->root_bus = bus; + + bus->sysdata = host_bridge->sysdata; + bus->host_bridge = host_bridge; + bus->ops = host_bridge->ops; + + rt_sprintf(bus->name, "%04x:%02x", host_bridge->domain, host_bridge->busnr); + + if (bus->ops->add) + { + rt_err_t err = bus->ops->add(bus); + + if (err) + { + LOG_E("PCI-Bus<%s> add bus failed with err = %s", bus->name, rt_strerror(err)); + } + } + + return RT_EOK; +} + +rt_err_t rt_pci_scan_root_bus_bridge(struct rt_pci_host_bridge *host_bridge) +{ + rt_err_t err; + + err = rt_pci_host_bridge_register(host_bridge); + + if (!err) + { + rt_pci_scan_child_bus(host_bridge->root_bus); + } + + return err; +} + +rt_err_t rt_pci_host_bridge_probe(struct rt_pci_host_bridge *host_bridge) +{ + rt_err_t err; + + err = rt_pci_scan_root_bus_bridge(host_bridge); + + return err; +} diff --git a/components/drivers/phy/Kconfig b/components/drivers/phy/Kconfig new file mode 100644 index 000000000000..96d33a75f4ca --- /dev/null +++ b/components/drivers/phy/Kconfig @@ -0,0 +1,7 @@ +menuconfig RT_USING_PHY + bool "Using Port Physical Layer (PHY) device drivers" + default n + +if RT_USING_DM && RT_USING_PHY +source "$RTT_DIR/components/drivers/phy/rockchip/Kconfig" +endif diff --git a/components/drivers/phy/SConscript b/components/drivers/phy/SConscript index 5b6effc98ab5..c5314bd199f2 100644 --- a/components/drivers/phy/SConscript +++ b/components/drivers/phy/SConscript @@ -1,8 +1,26 @@ from building import * -cwd = GetCurrentDir() -src = Glob('*.c') +group = [] +objs = [] + +if not GetDepend(['RT_USING_PHY']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) CPPPATH = [cwd + '/../include'] -group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_PHY'], CPPPATH = CPPPATH) -Return('group') +src = ['phy.c'] + +if GetDepend(['RT_USING_DM']): + src += ['phy_dm.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/components/drivers/phy/phy.c b/components/drivers/phy/phy.c index 363b483c589e..1a24cd509093 100644 --- a/components/drivers/phy/phy.c +++ b/components/drivers/phy/phy.c @@ -74,3 +74,43 @@ rt_err_t rt_hw_phy_register(struct rt_phy_device *phy, const char *name) return ret; } + +rt_phy_status rt_phy_init(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +{ + if (phy->ops->init) + { + return phy->ops->init(phy, object, phy_addr, src_clock_hz); + } + + return PHY_STATUS_OK; +} + +rt_phy_status rt_phy_exit(struct rt_phy_device *phy, void *object, rt_uint32_t phy_addr) +{ + if (phy->ops->exit) + { + return phy->ops->exit(phy, object, phy_addr); + } + + return PHY_STATUS_OK; +} + +rt_phy_status rt_phy_power_on(struct rt_phy_device *phy) +{ + if (phy->ops->power_on) + { + return phy->ops->power_on(phy); + } + + return PHY_STATUS_OK; +} + +rt_phy_status rt_phy_power_off(struct rt_phy_device *phy) +{ + if (phy->ops->power_off) + { + return phy->ops->power_off(phy); + } + + return PHY_STATUS_OK; +} diff --git a/components/drivers/phy/phy_dm.c b/components/drivers/phy/phy_dm.c new file mode 100644 index 000000000000..83cb82a503c9 --- /dev/null +++ b/components/drivers/phy/phy_dm.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include "phy_dm.h" + +#ifdef RT_USING_OFW +static struct rt_phy_device *ofw_phy_get_by_index(struct rt_ofw_node *np, int index) +{ + struct rt_ofw_cell_args phy_args; + struct rt_phy_device *phy_dev = RT_NULL; + + if (!rt_ofw_parse_phandle_cells(np, "phys", "#phy-cells", index, &phy_args)) + { + phy_dev = rt_ofw_data(phy_args.data); + + rt_ofw_node_put(phy_args.data); + + if (phy_dev) + { + if (phy_dev->ops->ofw_parse) + { + phy_dev->ops->ofw_parse(phy_dev, &phy_args); + } + } + } + + return phy_dev; +} +#else +static struct rt_phy_device *ofw_phy_get_by_index(struct rt_ofw_node *np, int index) +{ + return RT_NULL; +} +#endif /* RT_USING_OFW */ + +struct rt_phy_device *rt_phy_get_by_index(struct rt_device *dev, int index) +{ + struct rt_phy_device *phy_dev; + + if (!dev || index < 0) + { + return RT_NULL; + } + + if (dev->ofw_node) + { + phy_dev = ofw_phy_get_by_index(dev->ofw_node, index); + } + + return phy_dev; +} + +struct rt_phy_device *rt_phy_get_by_name(struct rt_device *dev, const char *id) +{ + int index; + + if (!dev || !id) + { + return RT_NULL; + } + + index = rt_dm_dev_prop_index_of_string(dev, "phy-names", id); + + return rt_phy_get_by_index(dev, index); +} diff --git a/components/drivers/phy/phy_dm.h b/components/drivers/phy/phy_dm.h new file mode 100644 index 000000000000..b67ab6a2a40a --- /dev/null +++ b/components/drivers/phy/phy_dm.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#ifndef __PHY_DM_H__ +#define __PHY_DM_H__ + +#include +#include +#include + +#endif /* __PHY_DM_H__ */ diff --git a/components/drivers/phy/rockchip/Kconfig b/components/drivers/phy/rockchip/Kconfig new file mode 100644 index 000000000000..d9de90bcb2de --- /dev/null +++ b/components/drivers/phy/rockchip/Kconfig @@ -0,0 +1,9 @@ +config RT_PHY_ROCKCHIP_NANENG_COMBO + bool "Rockchip NANENG COMBO PHY Driver" + select RT_MFD_SYSCON + default n + +config RT_PHY_ROCKCHIP_SNPS_PCIE3 + bool "Rockchip Snps PCIe3 PHY Driver" + select RT_MFD_SYSCON + default n diff --git a/components/drivers/phy/rockchip/SConscript b/components/drivers/phy/rockchip/SConscript new file mode 100644 index 000000000000..7daf98d914df --- /dev/null +++ b/components/drivers/phy/rockchip/SConscript @@ -0,0 +1,17 @@ +from building import * + +group = [] +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_PHY_ROCKCHIP_NANENG_COMBO']): + src += ['phy-rockchip-naneng-combphy.c'] + +if GetDepend(['RT_PHY_ROCKCHIP_SNPS_PCIE3']): + src += ['phy-rockchip-snps-pcie3.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/components/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c new file mode 100644 index 000000000000..e96f2429dadd --- /dev/null +++ b/components/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#include "../phy_dm.h" + +#define DBG_TAG "phy.rockchip.naneng-combphy" +#define DBG_LVL DBG_INFO +#include + +#define HZ_PER_MHZ 1000000UL +#define BIT_WRITEABLE_SHIFT 16 +#define REF_CLOCK_24MHz (24 * HZ_PER_MHZ) +#define REF_CLOCK_25MHz (25 * HZ_PER_MHZ) +#define REF_CLOCK_100MHz (100 * HZ_PER_MHZ) + +/* COMBO PHY REG */ +#define PHYREG6 0x14 +#define PHYREG6_PLL_DIV_MASK RT_GENMASK(7, 6) +#define PHYREG6_PLL_DIV_SHIFT 6 +#define PHYREG6_PLL_DIV_2 1 + +#define PHYREG7 0x18 +#define PHYREG7_TX_RTERM_MASK RT_GENMASK(7, 4) +#define PHYREG7_TX_RTERM_SHIFT 4 +#define PHYREG7_TX_RTERM_50OHM 8 +#define PHYREG7_RX_RTERM_MASK RT_GENMASK(3, 0) +#define PHYREG7_RX_RTERM_SHIFT 0 +#define PHYREG7_RX_RTERM_44OHM 15 + +#define PHYREG8 0x1c +#define PHYREG8_SSC_EN RT_BIT(4) + +#define PHYREG11 0x28 +#define PHYREG11_SU_TRIM_0_7 0xf0 + +#define PHYREG12 0x2c +#define PHYREG12_PLL_LPF_ADJ_VALUE 4 + +#define PHYREG13 0x30 +#define PHYREG13_RESISTER_MASK RT_GENMASK(5, 4) +#define PHYREG13_RESISTER_SHIFT 0x4 +#define PHYREG13_RESISTER_HIGH_Z 3 +#define PHYREG13_CKRCV_AMP0 RT_BIT(7) + +#define PHYREG14 0x34 +#define PHYREG14_CKRCV_AMP1 RT_BIT(0) + +#define PHYREG15 0x38 +#define PHYREG15_CTLE_EN RT_BIT(0) +#define PHYREG15_SSC_CNT_MASK RT_GENMASK(7, 6) +#define PHYREG15_SSC_CNT_SHIFT 6 +#define PHYREG15_SSC_CNT_VALUE 1 + +#define PHYREG16 0x3c +#define PHYREG16_SSC_CNT_VALUE 0x5f + +#define PHYREG18 0x44 +#define PHYREG18_PLL_LOOP 0x32 + +#define PHYREG27 0x6c +#define PHYREG27_RX_TRIM_RK3588 0x4c + +#define PHYREG32 0x7c +#define PHYREG32_SSC_MASK RT_GENMASK(7, 4) +#define PHYREG32_SSC_DIR_SHIFT 4 +#define PHYREG32_SSC_UPWARD 0 +#define PHYREG32_SSC_DOWNWARD 1 +#define PHYREG32_SSC_OFFSET_SHIFT 6 +#define PHYREG32_SSC_OFFSET_500PPM 1 + +#define PHYREG33 0x80 +#define PHYREG33_PLL_KVCO_MASK RT_GENMASK(4, 2) +#define PHYREG33_PLL_KVCO_SHIFT 2 +#define PHYREG33_PLL_KVCO_VALUE 2 + +struct rockchip_combphy; + +struct combphy_reg +{ + rt_uint16_t offset; + rt_uint16_t bitend; + rt_uint16_t bitstart; + rt_uint16_t disable; + rt_uint16_t enable; +}; + +struct rockchip_combphy_grfcfg +{ + struct combphy_reg pcie_mode_set; + struct combphy_reg usb_mode_set; + struct combphy_reg sgmii_mode_set; + struct combphy_reg qsgmii_mode_set; + struct combphy_reg pipe_rxterm_set; + struct combphy_reg pipe_txelec_set; + struct combphy_reg pipe_txcomp_set; + struct combphy_reg pipe_clk_25m; + struct combphy_reg pipe_clk_100m; + struct combphy_reg pipe_phymode_sel; + struct combphy_reg pipe_rate_sel; + struct combphy_reg pipe_rxterm_sel; + struct combphy_reg pipe_txelec_sel; + struct combphy_reg pipe_txcomp_sel; + struct combphy_reg pipe_clk_ext; + struct combphy_reg pipe_sel_usb; + struct combphy_reg pipe_sel_qsgmii; + struct combphy_reg pipe_phy_status; + struct combphy_reg con0_for_pcie; + struct combphy_reg con1_for_pcie; + struct combphy_reg con2_for_pcie; + struct combphy_reg con3_for_pcie; + struct combphy_reg con0_for_sata; + struct combphy_reg con1_for_sata; + struct combphy_reg con2_for_sata; + struct combphy_reg con3_for_sata; + struct combphy_reg pipe_con0_for_sata; + struct combphy_reg pipe_con1_for_sata; + struct combphy_reg pipe_xpcs_phy_ready; + struct combphy_reg pipe_pcie1l0_sel; + struct combphy_reg pipe_pcie1l1_sel; +}; + +struct rockchip_combphy_cfg +{ + const struct rockchip_combphy_grfcfg *grfcfg; + rt_err_t (*combphy_cfg)(struct rockchip_combphy *rk_cphy); +}; + +struct rockchip_combphy +{ + struct rt_phy_device parent; + + void *regs; + rt_uint8_t type; + rt_bool_t enable_ssc; + rt_bool_t ext_refclk; + + struct rt_syscon *pipe_grf; + struct rt_syscon *phy_grf; + struct rt_reset_control *rstc; + struct rt_clk *refclk; + struct rt_clk_array *clk_arr; + const struct rockchip_combphy_cfg *cfg; +}; + +#define raw_to_rockchip_combphy(raw) rt_container_of(raw, struct rockchip_combphy, parent) + +static void rockchip_combphy_updatel(struct rockchip_combphy *rk_cphy, + int mask, int val, int offset) +{ + rt_uint32_t data; + + data = HWREG32(rk_cphy->regs + offset); + data = (data & ~(mask)) | val; + HWREG32(rk_cphy->regs + offset) = data; +} + +static rt_err_t rockchip_combphy_param_write(struct rt_syscon *regmap, + const struct combphy_reg *reg, bool en) +{ + rt_uint32_t val, mask, tmp; + + tmp = en ? reg->enable : reg->disable; + mask = RT_GENMASK(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); + + return rt_syscon_write(regmap, reg->offset, val); +} + +static rt_uint32_t rockchip_combphy_is_ready(struct rockchip_combphy *rk_cphy) +{ + rt_uint32_t mask, val; + const struct rockchip_combphy_grfcfg *cfg = rk_cphy->cfg->grfcfg; + + mask = RT_GENMASK(cfg->pipe_phy_status.bitend, cfg->pipe_phy_status.bitstart); + + rt_syscon_read(rk_cphy->phy_grf, cfg->pipe_phy_status.offset, &val); + val = (val & mask) >> cfg->pipe_phy_status.bitstart; + + return val; +} + +static rt_err_t rk3568_combphy_cfg(struct rockchip_combphy *rk_cphy) +{ + rt_uint32_t val; + rt_ubase_t rate; + const struct rockchip_combphy_grfcfg *cfg = rk_cphy->cfg->grfcfg; + + switch (rk_cphy->type) + { + case PHY_TYPE_PCIE: + /* Set SSC downward spread spectrum. */ + rockchip_combphy_updatel(rk_cphy, PHYREG32_SSC_MASK, + PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, PHYREG32); + + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con0_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con1_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con2_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con3_for_pcie, RT_TRUE); + break; + + case PHY_TYPE_USB3: + /* Set SSC downward spread spectrum. */ + rockchip_combphy_updatel(rk_cphy, PHYREG32_SSC_MASK, + PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, PHYREG32); + + /* Enable adaptive CTLE for USB3.0 Rx. */ + val = HWREG32(rk_cphy->regs + PHYREG15); + val |= PHYREG15_CTLE_EN; + HWREG32(rk_cphy->regs + PHYREG15) = val; + + /* Set PLL KVCO fine tuning signals. */ + rockchip_combphy_updatel(rk_cphy, PHYREG33_PLL_KVCO_MASK, + PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, PHYREG33); + + /* Enable controlling random jitter. */ + HWREG32(rk_cphy->regs + PHYREG12) = PHYREG12_PLL_LPF_ADJ_VALUE; + + /* Set PLL input clock divider 1/2. */ + rockchip_combphy_updatel(rk_cphy, PHYREG6_PLL_DIV_MASK, + PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, PHYREG6); + + HWREG32(rk_cphy->regs + PHYREG18) = PHYREG18_PLL_LOOP; + HWREG32(rk_cphy->regs + PHYREG11) = PHYREG11_SU_TRIM_0_7; + + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_sel_usb, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_txcomp_sel, RT_FALSE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_txelec_sel, RT_FALSE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->usb_mode_set, RT_TRUE); + break; + + case PHY_TYPE_SATA: + /* Enable adaptive CTLE for SATA Rx. */ + val = HWREG32(rk_cphy->regs + PHYREG15); + val |= PHYREG15_CTLE_EN; + HWREG32(rk_cphy->regs + PHYREG15) = val; + /* + * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. + * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) + */ + val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; + val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; + HWREG32(rk_cphy->regs + PHYREG7) = val; + + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con0_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con1_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con2_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con3_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_con0_for_sata, RT_TRUE); + break; + + case PHY_TYPE_SGMII: + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_xpcs_phy_ready, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_phymode_sel, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_sel_qsgmii, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->sgmii_mode_set, RT_TRUE); + break; + + case PHY_TYPE_QSGMII: + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_xpcs_phy_ready, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_phymode_sel, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_rate_sel, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_sel_qsgmii, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->qsgmii_mode_set, RT_TRUE); + break; + + default: + LOG_E("Incompatible PHY type"); + return -RT_EINVAL; + } + + rate = rt_clk_get_rate(rk_cphy->refclk); + + switch (rate) + { + case REF_CLOCK_24MHz: + if (rk_cphy->type == PHY_TYPE_USB3 || rk_cphy->type == PHY_TYPE_SATA) + { + /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ + val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG15_SSC_CNT_MASK, val, PHYREG15); + + HWREG32(rk_cphy->regs + PHYREG16) = PHYREG16_SSC_CNT_VALUE; + } + break; + + case REF_CLOCK_25MHz: + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_25m, RT_TRUE); + break; + + case REF_CLOCK_100MHz: + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_100m, RT_TRUE); + if (rk_cphy->type == PHY_TYPE_PCIE) + { + /* PLL KVCO fine tuning. */ + val = PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG33_PLL_KVCO_MASK, val, PHYREG33); + + /* Enable controlling random jitter. */ + HWREG32(rk_cphy->regs + PHYREG12) = PHYREG12_PLL_LPF_ADJ_VALUE; + + val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG6_PLL_DIV_MASK, + val, PHYREG6); + + HWREG32(rk_cphy->regs + PHYREG18) = PHYREG18_PLL_LOOP; + HWREG32(rk_cphy->regs + PHYREG11) = PHYREG11_SU_TRIM_0_7; + } + else if (rk_cphy->type == PHY_TYPE_SATA) + { + /* downward spread spectrum +500ppm */ + val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; + val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG32_SSC_MASK, val, PHYREG32); + } + break; + + default: + LOG_E("Unsupported rate: %u", rate); + return -RT_EINVAL; + } + + if (rk_cphy->ext_refclk) + { + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_ext, RT_TRUE); + + if (rk_cphy->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) + { + val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; + val |= PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(rk_cphy, PHYREG13_RESISTER_MASK, val, PHYREG13); + + val = HWREG32(rk_cphy->regs + PHYREG14); + val |= PHYREG14_CKRCV_AMP1; + HWREG32(rk_cphy->regs + PHYREG14) = val; + } + } + + if (rk_cphy->enable_ssc) + { + val = HWREG32(rk_cphy->regs + PHYREG8); + val |= PHYREG8_SSC_EN; + HWREG32(rk_cphy->regs + PHYREG8) = val; + } + + return 0; +} + +static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = +{ + /* pipe-phy-grf */ + .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x0011 }, + .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x0004 }, + .sgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x0001 }, + .qsgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x0021 }, + .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x0001 }, + .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x0001 }, + .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x0001 }, + .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x0001 }, + .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x0002 }, + .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x0001 }, + .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x0001 }, + .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x0001 }, + .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x0001 }, + .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x0001 }, + .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x0001 }, + .pipe_sel_usb = { 0x000c, 14, 13, 0x00, 0x0001 }, + .pipe_sel_qsgmii = { 0x000c, 15, 13, 0x00, 0x0007 }, + .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x0000 }, + .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 }, + .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 }, + .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 }, + .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 }, + .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0119 }, + .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0040 }, + .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c3 }, + .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x4407 }, + /* pipe-grf */ + .pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 }, + .pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x0001 }, +}; + +static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = +{ + .grfcfg = &rk3568_combphy_grfcfgs, + .combphy_cfg = rk3568_combphy_cfg, +}; + +static rt_err_t rk3588_combphy_cfg(struct rockchip_combphy *rk_cphy) +{ + rt_uint32_t val; + rt_ubase_t rate; + const struct rockchip_combphy_grfcfg *cfg = rk_cphy->cfg->grfcfg; + + switch (rk_cphy->type) + { + case PHY_TYPE_PCIE: + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con0_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con1_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con2_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con3_for_pcie, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_pcie1l0_sel, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_pcie1l1_sel, RT_TRUE); + break; + + case PHY_TYPE_USB3: + /* Set SSC downward spread spectrum */ + rockchip_combphy_updatel(rk_cphy, PHYREG32_SSC_MASK, + PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, PHYREG32); + + /* Enable adaptive CTLE for USB3.0 Rx. */ + val = HWREG32(rk_cphy->regs + PHYREG15); + val |= PHYREG15_CTLE_EN; + HWREG32(rk_cphy->regs + PHYREG15) = val; + + /* Set PLL KVCO fine tuning signals. */ + rockchip_combphy_updatel(rk_cphy, PHYREG33_PLL_KVCO_MASK, + PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, PHYREG33); + + /* Enable controlling random jitter. */ + HWREG32(rk_cphy->regs + PHYREG12) = PHYREG12_PLL_LPF_ADJ_VALUE; + + /* Set PLL input clock divider 1/2. */ + rockchip_combphy_updatel(rk_cphy, PHYREG6_PLL_DIV_MASK, + PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, PHYREG6); + + HWREG32(rk_cphy->regs + PHYREG18) = PHYREG18_PLL_LOOP; + HWREG32(rk_cphy->regs + PHYREG11) = PHYREG11_SU_TRIM_0_7; + + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_txcomp_sel, RT_FALSE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_txelec_sel, RT_FALSE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->usb_mode_set, RT_TRUE); + break; + + case PHY_TYPE_SATA: + /* Enable adaptive CTLE for SATA Rx. */ + val = HWREG32(rk_cphy->regs + PHYREG15); + val |= PHYREG15_CTLE_EN; + HWREG32(rk_cphy->regs + PHYREG15) = val; + /* + * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. + * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) + */ + val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; + val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; + HWREG32(rk_cphy->regs + PHYREG7) = val; + + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con0_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con1_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con2_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->con3_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_con0_for_sata, RT_TRUE); + rockchip_combphy_param_write(rk_cphy->pipe_grf, &cfg->pipe_con1_for_sata, RT_TRUE); + break; + + case PHY_TYPE_SGMII: + case PHY_TYPE_QSGMII: + default: + LOG_E("Incompatible PHY type"); + return -RT_EINVAL; + } + + rate = rt_clk_get_rate(rk_cphy->refclk); + + switch (rate) + { + case REF_CLOCK_24MHz: + if (rk_cphy->type == PHY_TYPE_USB3 || rk_cphy->type == PHY_TYPE_SATA) + { + /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ + val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG15_SSC_CNT_MASK, + val, PHYREG15); + + HWREG32(rk_cphy->regs + PHYREG16) = PHYREG16_SSC_CNT_VALUE; + } + break; + + case REF_CLOCK_25MHz: + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_25m, RT_TRUE); + break; + + case REF_CLOCK_100MHz: + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_100m, RT_TRUE); + if (rk_cphy->type == PHY_TYPE_PCIE) + { + /* PLL KVCO fine tuning. */ + val = 4 << PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG33_PLL_KVCO_MASK, val, PHYREG33); + + /* Enable controlling random jitter. */ + HWREG32(rk_cphy->regs + PHYREG12) = PHYREG12_PLL_LPF_ADJ_VALUE; + + /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ + HWREG32(rk_cphy->regs + PHYREG27) = PHYREG27_RX_TRIM_RK3588; + + /* Set up su_trim: */ + HWREG32(rk_cphy->regs + PHYREG11) = PHYREG11_SU_TRIM_0_7; + } + else if (rk_cphy->type == PHY_TYPE_SATA) + { + /* downward spread spectrum +500ppm */ + val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; + val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(rk_cphy, PHYREG32_SSC_MASK, val, PHYREG32); + } + break; + default: + LOG_E("Unsupported rate: %u", rate); + return -RT_EINVAL; + } + + if (rk_cphy->ext_refclk) + { + rockchip_combphy_param_write(rk_cphy->phy_grf, &cfg->pipe_clk_ext, RT_TRUE); + + if (rk_cphy->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) + { + val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; + val |= PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(rk_cphy, PHYREG13_RESISTER_MASK, val, PHYREG13); + + val = HWREG32(rk_cphy->regs + PHYREG14); + val |= PHYREG14_CKRCV_AMP1; + HWREG32(rk_cphy->regs + PHYREG14) = val; + } + } + + if (rk_cphy->enable_ssc) + { + val = HWREG32(rk_cphy->regs + PHYREG8); + val |= PHYREG8_SSC_EN; + HWREG32(rk_cphy->regs + PHYREG8) = val; + } + + return RT_EOK; +} + +static const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = +{ + /* pipe-phy-grf */ + .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x0011 }, + .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x0004 }, + .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x0001 }, + .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x0001 }, + .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x0001 }, + .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x0001 }, + .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x0002 }, + .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x0001 }, + .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x0001 }, + .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x0001 }, + .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x0001 }, + .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x0000 }, + .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 }, + .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 }, + .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 }, + .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 }, + .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 }, + .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 }, + .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 }, + .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 }, + /* pipe-grf */ + .pipe_con0_for_sata = { 0x0000, 11, 5, 0x00, 0x0022 }, + .pipe_con1_for_sata = { 0x0000, 2, 0, 0x00, 0x0002 }, + .pipe_pcie1l0_sel = { 0x0100, 0, 0, 0x01, 0x0000 }, + .pipe_pcie1l1_sel = { 0x0100, 1, 1, 0x01, 0x0000 }, +}; + +static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = +{ + .grfcfg = &rk3588_combphy_grfcfgs, + .combphy_cfg = rk3588_combphy_cfg, +}; + +static rt_phy_status rockchip_combphy_init(struct rt_phy_device *phy_device, + void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +{ + rt_err_t err; + struct rockchip_combphy *rk_cphy = raw_to_rockchip_combphy(phy_device); + const struct rockchip_combphy_grfcfg *cfg = rk_cphy->cfg->grfcfg; + + if ((err = rt_clk_array_prepare_enable(rk_cphy->clk_arr))) + { + LOG_E("Failed to enable clks error = %s", rt_strerror(err)); + + return PHY_STATUS_FAIL; + } + + switch (rk_cphy->type) + { + case PHY_TYPE_PCIE: + case PHY_TYPE_USB3: + case PHY_TYPE_SATA: + case PHY_TYPE_SGMII: + case PHY_TYPE_QSGMII: + if (rk_cphy->cfg->combphy_cfg) + { + err = rk_cphy->cfg->combphy_cfg(rk_cphy); + } + break; + + default: + LOG_E("Incompatible PHY type"); + err = -RT_EINVAL; + break; + } + + if (err) + { + LOG_E("Failed to init PHY for type %d", rk_cphy->type); + + goto _out_clk; + } + + if ((err = rt_reset_control_deassert(rk_cphy->rstc))) + { + goto _out_clk; + } + + if (rk_cphy->type == PHY_TYPE_USB3) + { + rt_uint32_t val; + rt_int32_t timeout_us = 1000; + + while (timeout_us --> 0) + { + val = rockchip_combphy_is_ready(rk_cphy); + + if (val == cfg->pipe_phy_status.enable) + { + break; + } + + rt_hw_us_delay(10); + rt_hw_cpu_relax(); + } + + if (timeout_us <= 0) + { + LOG_W("Wait PHY status ready timeout"); + } + } + + return PHY_STATUS_OK; + +_out_clk: + rt_clk_array_disable_unprepare(rk_cphy->clk_arr); + + return PHY_STATUS_FAIL; +} + +static rt_phy_status rockchip_combphy_exit(struct rt_phy_device *phy_device, + void *object, rt_uint32_t phy_addr) +{ + struct rockchip_combphy *rk_cphy = raw_to_rockchip_combphy(phy_device); + + rt_clk_array_disable_unprepare(rk_cphy->clk_arr); + rt_reset_control_assert(rk_cphy->rstc); + + return PHY_STATUS_OK; +} + +static rt_err_t rockchip_combphy_ofw_parse(struct rt_phy_device *phy_device, + struct rt_ofw_cell_args *phy_args) +{ + struct rockchip_combphy *rk_cphy = raw_to_rockchip_combphy(phy_device); + + if (phy_args->args_count != 1) + { + LOG_E("Invalid number of arguments"); + + return -RT_EINVAL; + } + + if (rk_cphy->type != PHY_NONE && rk_cphy->type != phy_args->args[0]) + { + LOG_W("PHY select type %d from type %d", + phy_args->args[0], rk_cphy->type); + } + + rk_cphy->type = phy_args->args[0]; + + return RT_EOK; +} + +static struct rt_phy_ops rochchip_combphy_ops = +{ + .init = rockchip_combphy_init, + .exit = rockchip_combphy_exit, + .ofw_parse = rockchip_combphy_ofw_parse, +}; + +static rt_err_t rockchip_combphy_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_phy_device *phy; + struct rt_device *dev = &pdev->parent; + struct rockchip_combphy *rk_cphy = rt_calloc(1, sizeof(*rk_cphy)); + const struct rockchip_combphy_cfg *phy_cfg; + + if (!rk_cphy) + { + return -RT_ENOMEM; + } + + phy_cfg = pdev->id->data; + rk_cphy->type = PHY_NONE; + rk_cphy->cfg = phy_cfg; + + rk_cphy->regs = rt_dm_dev_iomap(dev, 0); + if (!rk_cphy->regs) + { + err = -RT_EIO; + goto _fail; + } + + rk_cphy->clk_arr = rt_clk_get_array(dev); + if (!rk_cphy->clk_arr) + { + err = -RT_EIO; + goto _fail; + } + + for (int i = rk_cphy->clk_arr->count - 1; i >= 0; --i) + { + if (!rt_strncmp(rk_cphy->clk_arr->clks[i]->con_id, "ref", 3)) + { + rk_cphy->refclk = rk_cphy->clk_arr->clks[i]; + } + } + + if (!rk_cphy->refclk) + { + err = -RT_EIO; + goto _fail; + } + + rk_cphy->pipe_grf = rt_syscon_find_by_ofw_phandle(dev->ofw_node, "rockchip,pipe-grf"); + if (!rk_cphy->pipe_grf) + { + err = -RT_EIO; + goto _fail; + } + + rk_cphy->phy_grf = rt_syscon_find_by_ofw_phandle(dev->ofw_node, "rockchip,pipe-phy-grf"); + if (!rk_cphy->phy_grf) + { + err = -RT_EIO; + goto _fail; + } + + rk_cphy->enable_ssc = rt_dm_dev_prop_read_bool(dev, "rockchip,enable-ssc"); + rk_cphy->ext_refclk = rt_dm_dev_prop_read_bool(dev, "rockchip,ext-refclk"); + + rk_cphy->rstc = rt_reset_control_get_array(dev); + if (!rk_cphy->rstc) + { + err = -RT_EIO; + goto _fail; + } + + err = rt_reset_control_assert(rk_cphy->rstc); + if (err) + { + goto _fail; + } + + phy = &rk_cphy->parent; + phy->ops = &rochchip_combphy_ops; + + rt_dm_dev_set_name_auto(&phy->parent, "phy"); + dev_name = rt_dm_dev_get_name(&phy->parent); + + if ((err = rt_hw_phy_register(phy, dev_name))) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, phy); + + return RT_EOK; + +_fail: + if (rk_cphy->regs) + { + rt_iounmap(rk_cphy->regs); + } + if (rk_cphy->clk_arr) + { + rt_clk_array_put(rk_cphy->clk_arr); + } + if (rk_cphy->rstc) + { + rt_reset_control_put(rk_cphy->rstc); + } + rt_free(rk_cphy); + + return err; +} + +static const struct rt_ofw_node_id rockchip_combphy_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-naneng-combphy", .data = &rk3568_combphy_cfgs }, + { .compatible = "rockchip,rk3588-naneng-combphy", .data = &rk3588_combphy_cfgs }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_combphy_driver = +{ + .name = "phy-rockchip-naneng-combphy", + .ids = rockchip_combphy_ofw_ids, + + .probe = rockchip_combphy_probe, +}; + +static int rockchip_combphy_drv_register(void) +{ + rt_platform_driver_register(&rockchip_combphy_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(rockchip_combphy_drv_register); diff --git a/components/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/components/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c new file mode 100644 index 000000000000..1f08da6006dc --- /dev/null +++ b/components/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-10-24 GuEe-GUI first version + */ + +#include +#include + +#include "../phy_dm.h" + +#define DBG_TAG "phy.rockchip.snps-pcie3" +#define DBG_LVL DBG_INFO +#include + +#define GRF_ENABLE_SHIFT 16 +#define GRF_ENABLE_MASK RT_GENMASK(31, 16) +#define GRF_ENABLE (GRF_ENABLE_MASK << GRF_ENABLE_SHIFT) + +struct rockchip_pcie3_phy_soc_data; + +struct rockchip_pcie3_phy +{ + struct rt_phy_device parent; + + void *regs; + /* mode: RC, EP */ + int mode; + /* pcie30_phymode: Aggregation, Bifurcation */ + int pcie30_phymode; + rt_bool_t is_bifurcation; + + int num_lanes; + rt_uint32_t lanes[4]; + + struct rt_syscon *phy_grf; + struct rt_syscon *pipe_grf; + struct rt_reset_control *rstc; + struct rt_clk_array *clk_arr; + + const struct rockchip_pcie3_phy_soc_data *soc_data; +}; + +#define raw_to_rockchip_pcie3_phy(raw) rt_container_of(raw, struct rockchip_pcie3_phy, parent) + +struct rockchip_pcie3_phy_soc_data +{ + rt_err_t (*phy_init)(struct rockchip_pcie3_phy *); +}; + +#define RK3568_GRF_PCIE30PHY_CON1 0x4 +#define RK3568_GRF_PCIE30PHY_CON6 0x18 +#define RK3568_GRF_PCIE30PHY_CON9 0x24 +#define RK3568_GRF_PCIE30PHY_DA_OCM (RT_BIT(15) | RT_BIT(GRF_ENABLE_SHIFT + 15)) +#define RK3568_GRF_PCIE30PHY_STATUS0 0x80 +#define RK3568_GRF_PCIE30PHY_WR_EN (0xf << 16) +#define RK3568_SRAM_INIT_DONE(reg) (reg & RT_BIT(14)) +#define RK3568_BIFURCATION_LANE_0_1 RT_BIT(0) + +static rt_err_t rockchip_p3phy_rk3568_init(struct rockchip_pcie3_phy *rk_p3phy) +{ + rt_err_t err; + rt_uint32_t reg = 0, timeout_us; + rt_bool_t bifurcation = RT_FALSE; + + /* Deassert PCIe PMA output clamp mode */ + rt_syscon_write(rk_p3phy->phy_grf, RK3568_GRF_PCIE30PHY_CON9, + RK3568_GRF_PCIE30PHY_DA_OCM); + + for (int i = 0; i < rk_p3phy->num_lanes; ++i) + { + if (rk_p3phy->lanes[i] > 1) + { + bifurcation = RT_TRUE; + break; + } + } + + /* Set bifurcation if needed, and it doesn't care RC/EP */ + if (bifurcation) + { + LOG_D("%s: bifurcation %s", + rt_dm_dev_get_name(&rk_p3phy->parent.parent), "enabled"); + + rt_syscon_write(rk_p3phy->phy_grf, RK3568_GRF_PCIE30PHY_CON6, + RK3568_GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1); + rt_syscon_write(rk_p3phy->phy_grf, RK3568_GRF_PCIE30PHY_CON1, + RK3568_GRF_PCIE30PHY_DA_OCM); + } + else + { + LOG_D("%s: bifurcation %s", + rt_dm_dev_get_name(&rk_p3phy->parent.parent), "disabled"); + + rt_syscon_write(rk_p3phy->phy_grf, RK3568_GRF_PCIE30PHY_CON6, + RK3568_GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1); + } + + rt_reset_control_deassert(rk_p3phy->rstc); + + timeout_us = 500; + while (timeout_us --> 0) + { + err = rt_syscon_read(rk_p3phy->phy_grf, RK3568_GRF_PCIE30PHY_STATUS0, ®); + + if (err || RK3568_SRAM_INIT_DONE(reg)) + { + break; + } + + rt_hw_us_delay(1); + rt_hw_cpu_relax(); + } + + if (err) + { + LOG_E("%s: lock failed 0x%x, check input refclk and power supply", + rt_dm_dev_get_name(&rk_p3phy->parent.parent), reg); + } + + return err; +} + +static const struct rockchip_pcie3_phy_soc_data rk3568_data = +{ + .phy_init = rockchip_p3phy_rk3568_init, +}; + +#define PHP_GRF_PCIESEL_CON 0x100 +#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 +#define RK3588_PCIE3PHY_GRF_DA_OCM (RT_BIT(8) | RT_BIT(GRF_ENABLE_SHIFT + 8)) +#define RK3588_PCIE3PHY_GRF_MODE_SHIFT 0x7 +#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 +#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 +#define RK3588_SRAM_INIT_DONE(reg) (reg & RT_BIT(0)) + +#define RK3588_BIFURCATION_LANE_0_1 RT_BIT(0) +#define RK3588_BIFURCATION_LANE_2_3 RT_BIT(1) +#define RK3588_LANE_AGGREGATION RT_BIT(2) + +static rt_err_t rockchip_p3phy_rk3588_init(struct rockchip_pcie3_phy *rk_p3phy) +{ + rt_uint8_t mode = 0; + rt_uint32_t reg = 0, timeout_us; + rt_err_t err, err_res = RT_EOK; + + /* Deassert PCIe PMA output clamp mode */ + rt_syscon_write(rk_p3phy->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + RK3588_PCIE3PHY_GRF_DA_OCM); + + /* Set bifurcation if needed */ + for (int i = 0; i < rk_p3phy->num_lanes; ++i) + { + if (!rk_p3phy->lanes[i]) + { + mode |= (RT_BIT(i) << 3); + } + if (rk_p3phy->lanes[i] > 1) + { + mode |= (RT_BIT(i) >> 1); + } + } + + if (!mode) + { + reg = RK3588_LANE_AGGREGATION; + } + else + { + if (mode & (RT_BIT(0) | RT_BIT(1))) + { + reg |= RK3588_BIFURCATION_LANE_0_1; + } + if (mode & (RT_BIT(2) | RT_BIT(3))) + { + reg |= RK3588_BIFURCATION_LANE_2_3; + } + } + + rt_syscon_write(rk_p3phy->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + (RK3588_PCIE3PHY_GRF_MODE_SHIFT << GRF_ENABLE_SHIFT) | reg); + + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ + if (rk_p3phy->pipe_grf) + { + reg = (mode & (RT_BIT(6) | RT_BIT(7))) >> 6; + + if (reg) + { + rt_syscon_write(rk_p3phy->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << GRF_ENABLE_SHIFT) | reg); + } + } + + rt_reset_control_deassert(rk_p3phy->rstc); + + timeout_us = 500; + while (timeout_us --> 0) + { + err = rt_syscon_read(rk_p3phy->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_STATUS1, ®); + + if (err || RK3588_SRAM_INIT_DONE(reg)) + { + break; + } + + rt_hw_us_delay(1); + rt_hw_cpu_relax(); + } + err_res |= err; + + timeout_us = 500; + while (timeout_us --> 0) + { + err = rt_syscon_read(rk_p3phy->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_STATUS1, ®); + + if (err || RK3588_SRAM_INIT_DONE(reg)) + { + break; + } + + rt_hw_us_delay(1); + rt_hw_cpu_relax(); + } + err_res |= err; + + if (err_res) + { + LOG_E("%s: lock failed 0x%x, check input refclk and power supply", + rt_dm_dev_get_name(&rk_p3phy->parent.parent), reg); + } + + return err_res; +} + +static const struct rockchip_pcie3_phy_soc_data rk3588_data = +{ + .phy_init = rockchip_p3phy_rk3588_init, +}; + +static rt_phy_status rockchip_pcie3_phy_init(struct rt_phy_device *phy_device, + void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz) +{ + rt_err_t err; + struct rockchip_pcie3_phy *rk_p3phy = raw_to_rockchip_pcie3_phy(phy_device); + + if ((err = rt_clk_array_prepare_enable(rk_p3phy->clk_arr))) + { + LOG_E("Enable PCIe bulk clks erros = %s", rt_strerror(err)); + + return PHY_STATUS_FAIL; + } + + rt_reset_control_assert(rk_p3phy->rstc); + rt_hw_us_delay(1); + + if (rk_p3phy->soc_data->phy_init) + { + if ((err = rk_p3phy->soc_data->phy_init(rk_p3phy))) + { + rt_clk_array_disable_unprepare(rk_p3phy->clk_arr); + + LOG_E("Init PCIe PHY erros = %s", rt_strerror(err)); + + return PHY_STATUS_FAIL; + } + } + + return PHY_STATUS_OK; +} + +static rt_phy_status rockchip_pcie3_phy_exit(struct rt_phy_device *phy_device, + void *object, rt_uint32_t phy_addr) +{ + struct rockchip_pcie3_phy *rk_p3phy = raw_to_rockchip_pcie3_phy(phy_device); + + rt_clk_array_disable_unprepare(rk_p3phy->clk_arr); + rt_reset_control_assert(rk_p3phy->rstc); + + return PHY_STATUS_OK; +} + +static struct rt_phy_ops rockchip_pcie3_phy_ops = +{ + .init = rockchip_pcie3_phy_init, + .exit = rockchip_pcie3_phy_exit, +}; + +static rt_err_t rockchip_pcie3_phy_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + const char *dev_name; + struct rt_phy_device *phy; + struct rt_device *dev = &pdev->parent; + struct rockchip_pcie3_phy *rk_p3phy = rt_calloc(1, sizeof(*rk_p3phy)); + + if (!rk_p3phy) + { + return -RT_ENOMEM; + } + + rk_p3phy->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_p3phy->regs) + { + err = -RT_EIO; + goto _fail; + } + + rk_p3phy->phy_grf = rt_syscon_find_by_ofw_phandle(dev->ofw_node, "rockchip,phy-grf"); + + if (!rk_p3phy->phy_grf) + { + err = -RT_EIO; + goto _fail; + } + + rk_p3phy->pipe_grf = rt_syscon_find_by_ofw_phandle(dev->ofw_node, "rockchip,pipe-grf"); + + if (!rk_p3phy->pipe_grf && rt_dm_dev_prop_read_bool(dev, "rockchip,pipe-grf")) + { + err = -RT_EIO; + goto _fail; + } + + rk_p3phy->num_lanes = rt_dm_dev_prop_read_u32_array_index(dev, + "data-lanes", 0, RT_ARRAY_SIZE(rk_p3phy->lanes), rk_p3phy->lanes); + + if (rk_p3phy->num_lanes == -RT_EEMPTY) + { + rk_p3phy->num_lanes = 1; + rk_p3phy->lanes[0] = 1; + } + else if (rk_p3phy->num_lanes < 0) + { + err = rk_p3phy->num_lanes; + LOG_E("Failed to read \"data-lanes\""); + goto _fail; + } + + rk_p3phy->rstc = rt_reset_control_get_by_name(dev, "phy"); + + rk_p3phy->clk_arr = rt_clk_get_array(dev); + + if (!rk_p3phy->clk_arr) + { + err = -RT_EIO; + goto _fail; + } + + if (!rt_dm_dev_prop_read_u32(dev, "rockchip,pcie30-phymode", &val) && val <= 4) + { + rk_p3phy->pcie30_phymode = val; + } + else + { + rk_p3phy->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; + } + + rt_syscon_write(rk_p3phy->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + GRF_ENABLE | rk_p3phy->pcie30_phymode); + + if (rk_p3phy->pipe_grf) + { + rt_uint32_t reg = rk_p3phy->pcie30_phymode & 3; + + if (reg) + { + rt_syscon_write(rk_p3phy->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << GRF_ENABLE_SHIFT) | reg); + } + } + + rk_p3phy->soc_data = pdev->id->data; + + phy = &rk_p3phy->parent; + phy->ops = &rockchip_pcie3_phy_ops; + + rt_dm_dev_set_name_auto(&phy->parent, "phy"); + dev_name = rt_dm_dev_get_name(&phy->parent); + + if ((err = rt_hw_phy_register(phy, dev_name))) + { + goto _fail; + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, phy); + + return RT_EOK; + +_fail: + if (rk_p3phy->regs) + { + rt_iounmap(rk_p3phy->regs); + } + + rt_free(rk_p3phy); + + return err; +} + +static const struct rt_ofw_node_id rockchip_pcie3_phy_ofw_ids[] = +{ + { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_data }, + { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pcie3_phy_driver = +{ + .name = "phy-rockchip-snps-pcie3", + .ids = rockchip_pcie3_phy_ofw_ids, + + .probe = rockchip_pcie3_phy_probe, +}; + +static int rockchip_pcie3_phy_drv_register(void) +{ + rt_platform_driver_register(&rockchip_pcie3_phy_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(rockchip_pcie3_phy_drv_register); diff --git a/components/drivers/pic/Kconfig b/components/drivers/pic/Kconfig index 0c9686ec8667..7aea9a7b17a8 100755 --- a/components/drivers/pic/Kconfig +++ b/components/drivers/pic/Kconfig @@ -7,35 +7,43 @@ menuconfig RT_USING_PIC config MAX_HANDLERS int "IRQ max handlers" depends on RT_USING_PIC - range 1 4294967294 + range 1 2147483647 default 256 config RT_PIC_BCM2835_INTC bool "BCM2835 intc" depends on RT_USING_PIC + select RT_USING_OFW default n config RT_PIC_BCM2836_L1_INTC bool "BCM2836 L1 intc" depends on RT_USING_PIC + select RT_USING_OFW default n config RT_PIC_ARM_GIC bool "ARM GICv2/v1" depends on RT_USING_PIC + select RT_USING_OFW default n config RT_PIC_ARM_GIC_V2M bool "ARM GIC V2M" if RT_PIC_ARM_GIC && RT_PCI_MSI + select RT_USING_OFW + select RT_USING_ADT_REF + select RT_USING_ADT_BITMAP default n config RT_PIC_ARM_GIC_V3 bool "ARM GICv3" depends on RT_USING_PIC + select RT_USING_OFW default n config RT_PIC_ARM_GIC_V3_ITS bool "ARM GICv3 ITS (Interrupt Translation Service)" if RT_PIC_ARM_GIC_V3 && RT_PCI_MSI + select RT_USING_OFW default n config RT_PIC_ARM_GIC_MAX_NR @@ -44,13 +52,3 @@ config RT_PIC_ARM_GIC_MAX_NR depends on RT_PIC_ARM_GIC default 2 if SOC_REALVIEW default 1 - -config RT_PIC_RISCV_INTC - bool "RISC-V Local Interrupt Controller" - depends on RT_USING_PIC - default n - -config RT_PIC_SIFIVE_PLIC - bool "SiFive Platform-Level Interrupt Controller" - depends on RT_USING_PIC - default n diff --git a/components/drivers/pic/SConscript b/components/drivers/pic/SConscript index 08cdc3847944..d8b5452a5820 100644 --- a/components/drivers/pic/SConscript +++ b/components/drivers/pic/SConscript @@ -16,8 +16,11 @@ if GetDepend(['RT_PIC_BCM2835_INTC']): if GetDepend(['RT_PIC_BCM2836_L1_INTC']): src += ['pic-bcm2836.c'] +if GetDepend(['RT_PIC_ARM_GIC']) or GetDepend(['RT_PIC_ARM_GIC_V3']): + src += ['pic-gic-common.c'] + if GetDepend(['RT_PIC_ARM_GIC']): - src += ['pic-gicv2.c', 'pic-gic-common.c'] + src += ['pic-gicv2.c'] if GetDepend(['RT_PIC_ARM_GIC_V2M']): src += ['pic-gicv2m.c'] @@ -28,12 +31,6 @@ if GetDepend(['RT_PIC_ARM_GIC_V3']): if GetDepend(['RT_PIC_ARM_GIC_V3_ITS']): src += ['pic-gicv3-its.c'] -if GetDepend(['RT_PIC_RISCV_INTC']): - src += ['pic-riscv-intc.c'] - -if GetDepend(['RT_PIC_SIFIVE_PLIC']): - src += ['pic-sifive-plic.c'] - group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/pic/pic-bcm2836.c b/components/drivers/pic/pic-bcm2836.c index 293465447869..0acacfddd8a3 100755 --- a/components/drivers/pic/pic-bcm2836.c +++ b/components/drivers/pic/pic-bcm2836.c @@ -157,7 +157,7 @@ static int bcm2836_arm_l1_intc_irq_map(struct rt_irq_chip_desc *chip_desc, int h 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 ret = RT_EOK; + rt_err_t err = RT_EOK; if (args->args_count == 2) { @@ -166,10 +166,10 @@ static rt_err_t bcm2836_arm_l1_intc_irq_parse(struct rt_pic *pic, } else { - ret = -RT_EINVAL; + err = -RT_EINVAL; } - return ret; + return err; } static struct rt_pic_ops bcm2836_arm_l1_intc_ops = @@ -244,6 +244,11 @@ static rt_err_t bcm2836_arm_l1_intc_init(struct rt_ofw_node *np, const struct rt rt_pic_linear_irq(&intc.parent, LAST_IRQ + 1); + for (int ipi = 0; ipi < 2; ++ipi) + { + rt_pic_config_ipi(&intc.parent, ipi, hwirq); + } + rt_pic_add_traps(bcm2836_arm_l1_intc_handler, &intc); } else diff --git a/components/drivers/pic/pic-gicv2.c b/components/drivers/pic/pic-gicv2.c index e8709ad5b836..21610eab6363 100644 --- a/components/drivers/pic/pic-gicv2.c +++ b/components/drivers/pic/pic-gicv2.c @@ -252,12 +252,16 @@ static int gicv2_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) if (pirq && hwirq >= GIC_SGI_NR) { - pirq->hwirq = hwirq; pirq->mode = mode; pirq->priority = GICD_INT_DEF_PRI; bitmap_set_bit(pirq->affinity, _init_cpu_id); irq = rt_pic_config_irq(pic, irq_index, hwirq); + + if (irq >= 0 && mode != RT_IRQ_MODE_LEVEL_HIGH) + { + gicv2_irq_set_triger_mode(pirq, mode); + } } else { diff --git a/components/drivers/pic/pic-gicv2m.c b/components/drivers/pic/pic-gicv2m.c index a5d0e026f864..3c6f555c519b 100755 --- a/components/drivers/pic/pic-gicv2m.c +++ b/components/drivers/pic/pic-gicv2m.c @@ -10,21 +10,15 @@ #include #include +#include -#define DBG_TAG "irqchip.gic-v2m" +#define DBG_TAG "pic.gic-v2m" #define DBG_LVL DBG_INFO #include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include +#include "pic-gic-common.h" /* * MSI_TYPER: @@ -56,82 +50,79 @@ struct gicv2m { - struct rt_irq_chip_desc parent; + struct rt_pic parent; - rt_list_t list; void *base; void *base_phy; rt_uint32_t spi_start; /* The SPI number that MSIs start */ rt_uint32_t spis_nr; /* The number of SPIs for MSIs */ rt_uint32_t spi_offset; /* Offset to be subtracted from SPI number */ - rt_bitmap_t *vectors; /* MSI vector bitmap */ + bitmap_t *vectors; /* MSI vector bitmap */ rt_uint32_t flags; /* Flags for v2m's specific implementation */ void *gic; + struct rt_spinlock lock; }; -static rt_list_t _v2m_nodes = RT_LIST_OBJECT_INIT(_v2m_nodes); -static struct rt_spinlock _v2m_lock = { 0 }; +#define raw_to_gicv2m(raw) rt_container_of(raw, struct gicv2m, parent) static rt_ubase_t gicv2m_get_msi_addr(struct gicv2m *v2m, int hwirq) { - rt_ubase_t ret; + rt_ubase_t addr; if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) { - ret = (rt_ubase_t)v2m->base_phy | ((hwirq - 32) << 3); + addr = (rt_ubase_t)v2m->base_phy | ((hwirq - 32) << 3); } else { - ret = (rt_ubase_t)v2m->base_phy + V2M_MSI_SETSPI_NS; + addr = (rt_ubase_t)v2m->base_phy + V2M_MSI_SETSPI_NS; } - return ret; + return addr; } static rt_bool_t is_msi_spi_valid(rt_uint32_t base, rt_uint32_t num) { - rt_bool_t ret = RT_TRUE; - if (base < V2M_MIN_SPI) { - LOG_E("Invalid MSI base SPI (base:%u)", base); + LOG_E("Invalid MSI base SPI (base: %u)", base); - ret = RT_FALSE; + return RT_FALSE; } else if ((num == 0) || (base + num > V2M_MAX_SPI)) { LOG_E("Number of SPIs (%u) exceed maximum (%u)", num, V2M_MAX_SPI - V2M_MIN_SPI + 1); - ret = RT_FALSE; + return RT_FALSE; } - return ret; + return RT_TRUE; } -void gicv2m_irq_mask(struct rt_irq_data *data) +static void gicv2m_irq_mask(struct rt_pic_irq *pirq) { - pci_msi_mask_irq(data); - rt_irqchip_irq_parent_mask(data); + rt_pci_msi_mask_irq(pirq); + rt_pic_irq_parent_mask(pirq); } -void gicv2m_irq_unmask(struct rt_irq_data *data) +static void gicv2m_irq_unmask(struct rt_pic_irq *pirq) { - pci_msi_unmask_irq(data); - rt_irqchip_irq_parent_unmask(data); + rt_pci_msi_unmask_irq(pirq); + rt_pic_irq_parent_unmask(pirq); } -void gicv2m_compose_msi_msg(struct rt_irq_data *data, struct msi_msg *msg) +static void gicv2m_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) { - struct gicv2m *v2m = data->chip_data; + struct gicv2m *v2m = raw_to_gicv2m(pirq->pic); if (v2m) { - rt_ubase_t addr = gicv2m_get_msi_addr(v2m, data->hwirq); + rt_ubase_t addr = gicv2m_get_msi_addr(v2m, pirq->hwirq); - msg->address_hi = ((rt_uint32_t)(((addr) >> 16) >> 16)); - msg->address_lo = ((rt_uint32_t)((addr) & RT_UINT32_MAX)); + msg->address_hi = rt_upper_32_bits(addr); + msg->address_lo = rt_lower_32_bits(addr); if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) { @@ -139,7 +130,7 @@ void gicv2m_compose_msi_msg(struct rt_irq_data *data, struct msi_msg *msg) } else { - msg->data = data->hwirq; + msg->data = pirq->hwirq; } if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) @@ -149,229 +140,220 @@ void gicv2m_compose_msi_msg(struct rt_irq_data *data, struct msi_msg *msg) } } -int gicv2m_irq_alloc_msi(struct rt_irq_chip_desc *chip_desc, struct msi_desc *msi_desc) +static int gicv2m_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) { - int irq = -1; - struct gicv2m *v2m; - rt_ubase_t level = rt_spin_lock_irqsave(&_v2m_lock); + rt_ubase_t level; + int irq, hwirq, hwirq_index; + struct rt_pic_irq *pirq, *ppirq; + struct gicv2m *v2m = raw_to_gicv2m(pic); - rt_list_for_each_entry(v2m, &_v2m_nodes, list) - { - int vector = rt_bitmap_next_clear_bit(v2m->vectors, 0, v2m->spis_nr); + level = rt_spin_lock_irqsave(&v2m->lock); - if (vector >= 0) - { - struct rt_irq_info spi = - { - .mode = RT_IRQ_MODE_EDGE_RISING, - .type = RT_IRQ_TYPE_EXTERNAL, - .msi_desc = msi_desc, - }; + hwirq_index = bitmap_next_clear_bit(v2m->vectors, 0, v2m->spis_nr); - irq = rt_irqchip_chip_parent_map(chip_desc, v2m->gic, v2m->spi_start + v2m->spi_offset + vector, &spi); + if (hwirq_index >= v2m->spis_nr) + { + irq = -RT_EEMPTY; + goto _out_lock; + } - if (irq < 0) - { - continue; - } + hwirq = v2m->spi_start + v2m->spi_offset + hwirq_index; - rt_bitmap_set_bit(v2m->vectors, vector); + ppirq = rt_pic_find_irq(v2m->gic, hwirq - GIC_SGI_NR); + if (!ppirq) + { + irq = -RT_EINVAL; + goto _out_lock; + } - break; - } + irq = rt_pic_config_irq(pic, hwirq_index, hwirq); + if (irq < 0) + { + goto _out_lock; } + pirq = rt_pic_find_irq(pic, hwirq_index); + + rt_pic_cascade(pirq, ppirq->irq); + rt_pic_irq_set_triger_mode(irq, RT_IRQ_MODE_EDGE_RISING); - rt_spin_unlock_irqrestore(&_v2m_lock, level); + bitmap_set_bit(v2m->vectors, hwirq_index); + +_out_lock: + rt_spin_unlock_irqrestore(&v2m->lock, level); return irq; } -void gicv2m_irq_free_msi(struct rt_irq_chip_desc *chip_desc, int irq) +static void gicv2m_irq_free_msi(struct rt_pic *pic, int irq) { - rt_ubase_t level = rt_spin_lock_irqsave(&_v2m_lock); - - if (!rt_list_isempty(&_v2m_nodes)) - { - struct rt_irq_data irqdata = { .irq = -1 }; + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct gicv2m *v2m = raw_to_gicv2m(pic); - rt_irqchip_search_irq(irq, &irqdata); + pirq = rt_pic_find_pirq(pic, irq); - if (irqdata.irq >= 0) - { - struct gicv2m *v2m = irqdata.chip_data; + if (!pirq) + { + return; + } - rt_bitmap_clear_bit(v2m->vectors, irqdata.hwirq - (v2m->spi_start + v2m->spi_offset)); + level = rt_spin_lock_irqsave(&v2m->lock); - rt_irqchip_chip_parent_unmap(chip_desc, irq); - } - } + rt_pic_uncascade(pirq); + bitmap_clear_bit(v2m->vectors, pirq->hwirq - (v2m->spi_start + v2m->spi_offset)); - rt_spin_unlock_irqrestore(&_v2m_lock, level); + rt_spin_unlock_irqrestore(&v2m->lock, level); } -static struct rt_irq_chip gicv2m_irq_chip = +static struct rt_pic_ops gicv2m_ops = { .name = "GICv2m", - .irq_ack = rt_irqchip_irq_parent_ack, + .irq_ack = rt_pic_irq_parent_ack, .irq_mask = gicv2m_irq_mask, .irq_unmask = gicv2m_irq_unmask, - .irq_eoi = rt_irqchip_irq_parent_eoi, - .irq_set_priority = rt_irqchip_irq_parent_set_priority, - .irq_set_affinity = rt_irqchip_irq_parent_set_affinity, + .irq_eoi = rt_pic_irq_parent_eoi, + .irq_set_priority = rt_pic_irq_parent_set_priority, + .irq_set_affinity = rt_pic_irq_parent_set_affinity, .irq_compose_msi_msg = gicv2m_compose_msi_msg, .irq_alloc_msi = gicv2m_irq_alloc_msi, .irq_free_msi = gicv2m_irq_free_msi, }; -static const struct rt_of_device_id gicv2m_of_match[] = +static const struct rt_ofw_node_id gicv2m_ofw_match[] = { { .compatible = "arm,gic-v2m-frame" }, { /* sentinel */ } }; -rt_err_t gicv2m_of_probe(struct rt_device_node *node, const struct rt_of_device_id *id) +rt_err_t gicv2m_ofw_probe(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) { - rt_err_t ret = RT_EOK; - rt_uint64_t regs[2]; - struct rt_device_node *v2m_np; + rt_err_t err = RT_EOK; + struct rt_ofw_node *v2m_np; - rt_of_for_each_child_of_node(node, v2m_np) + rt_ofw_foreach_available_child_node(np, v2m_np) { - rt_bool_t init_ok = RT_TRUE; struct gicv2m *v2m; rt_size_t bitmap_size; rt_uint32_t spi_start = 0, spis_nr = 0; - if (!rt_of_device_is_available(v2m_np)) + if (!rt_ofw_node_match(v2m_np, gicv2m_ofw_match)) { continue; } - if (!rt_of_match_node(gicv2m_of_match, v2m_np)) + if (!rt_ofw_prop_read_bool(v2m_np, "msi-controller")) { continue; } - if (!rt_of_find_property(v2m_np, "msi-controller", RT_NULL)) + if (!(v2m = rt_malloc(sizeof(*v2m)))) { - continue; + err = -RT_ENOMEM; + break; } - rt_memset(regs, 0, sizeof(regs)); + v2m->base = rt_ofw_iomap(v2m_np, 0); - if (rt_of_address_to_array(v2m_np, regs) < 0) + if (!v2m->base) { + LOG_E("%s: IO map failed", rt_ofw_node_full_name(v2m_np)); continue; } - if (!(v2m = rt_malloc(sizeof(*v2m)))) - { - ret = -RT_ENOMEM; - break; - } - - rt_list_init(&v2m->list); - v2m->base_phy = (void *)regs[0]; - v2m->base = rt_ioremap(v2m->base_phy, regs[1]); + v2m->base_phy = rt_kmem_v2p(v2m->base); v2m->flags = 0; - if (!rt_of_property_read_u32(v2m_np, "arm,msi-base-spi", &spi_start) && - !rt_of_property_read_u32(v2m_np, "arm,msi-num-spis", &spis_nr)) + if (!rt_ofw_prop_read_u32(v2m_np, "arm,msi-base-spi", &spi_start) && + !rt_ofw_prop_read_u32(v2m_np, "arm,msi-num-spis", &spis_nr)) { LOG_I("DT overriding V2M MSI_TYPER (base:%u, num:%u)", spi_start, spis_nr); } - do { - if (spi_start && spis_nr) - { - v2m->spi_start = spi_start; - v2m->spis_nr = spis_nr; - } - else - { - rt_uint32_t typer; - - /* Graviton should always have explicit spi_start/spis_nr */ - if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) - { - init_ok = RT_FALSE; - break; - } - typer = HWREG32(v2m->base + V2M_MSI_TYPER); - - v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); - v2m->spis_nr = V2M_MSI_TYPER_NUM_SPI(typer); - } + if (spi_start && spis_nr) + { + v2m->spi_start = spi_start; + v2m->spis_nr = spis_nr; + } + else + { + rt_uint32_t typer; - if (!is_msi_spi_valid(v2m->spi_start, v2m->spis_nr)) + /* Graviton should always have explicit spi_start/spis_nr */ + if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) { - init_ok = RT_FALSE; - break; + goto _fail; } + typer = HWREG32(v2m->base + V2M_MSI_TYPER); - /* - * APM X-Gene GICv2m implementation has an erratum where - * the MSI data needs to be the offset from the spi_start - * in order to trigger the correct MSI interrupt. This is - * different from the standard GICv2m implementation where - * the MSI data is the absolute value within the range from - * spi_start to (spi_start + num_spis). - * - * Broadcom NS2 GICv2m implementation has an erratum where the MSI data - * is 'spi_number - 32' - * - * Reading that register fails on the Graviton implementation - */ - if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) - { - switch (HWREG32(v2m->base + V2M_MSI_IIDR)) - { - case XGENE_GICV2M_MSI_IIDR: - v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; - v2m->spi_offset = v2m->spi_start; - break; - case BCM_NS2_GICV2M_MSI_IIDR: - v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; - v2m->spi_offset = 32; - break; - } - } + v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); + v2m->spis_nr = V2M_MSI_TYPER_NUM_SPI(typer); + } - bitmap_size = RT_BITMAP_LEN(v2m->spis_nr) * sizeof(rt_bitmap_t); + if (!is_msi_spi_valid(v2m->spi_start, v2m->spis_nr)) + { + goto _fail; + } - if (!(v2m->vectors = rt_malloc(bitmap_size))) + /* + * APM X-Gene GICv2m implementation has an erratum where + * the MSI data needs to be the offset from the spi_start + * in order to trigger the correct MSI interrupt. This is + * different from the standard GICv2m implementation where + * the MSI data is the absolute value within the range from + * spi_start to (spi_start + num_spis). + * + * Broadcom NS2 GICv2m implementation has an erratum where the MSI data + * is 'spi_number - 32' + * + * Reading that register fails on the Graviton implementation + */ + if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) + { + switch (HWREG32(v2m->base + V2M_MSI_IIDR)) { - ret = -RT_ENOMEM; - init_ok = RT_FALSE; + case XGENE_GICV2M_MSI_IIDR: + v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; + v2m->spi_offset = v2m->spi_start; + break; + + case BCM_NS2_GICV2M_MSI_IIDR: + v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; + v2m->spi_offset = 32; break; } + } - rt_memset(v2m->vectors, 0, bitmap_size); - } while (0); + bitmap_size = BITMAP_LEN(v2m->spis_nr) * sizeof(bitmap_t); - if (!init_ok) + if (!(v2m->vectors = rt_calloc(1, bitmap_size))) { - rt_iounmap(v2m->base); - rt_free(v2m); - - if (ret) - { - break; - } + err = -RT_ENOMEM; + goto _fail; } - v2m->parent.chip = &gicv2m_irq_chip; - v2m->parent.chip_data = v2m; - v2m->gic = rt_of_data(node); + rt_spin_lock_init(&v2m->lock); + + v2m->parent.priv_data = v2m; + v2m->parent.ops = &gicv2m_ops; + v2m->gic = rt_ofw_data(np); + + rt_pic_linear_irq(&v2m->parent, v2m->spis_nr); + rt_pic_user_extends(&v2m->parent); + + rt_ofw_data(v2m_np) = &v2m->parent; + rt_ofw_node_set_flag(v2m_np, RT_OFW_F_READLY); - rt_spin_lock(&_v2m_lock); - rt_list_insert_after(&_v2m_nodes, &v2m->list); - rt_spin_unlock(&_v2m_lock); + continue; - rt_of_data(v2m_np) = &v2m->parent; + _fail: + rt_iounmap(v2m->base); + rt_free(v2m); - rt_of_node_set_flag(v2m_np, OF_F_READY); + if (err) + { + break; + } } - return ret; + return err; } diff --git a/components/drivers/pic/pic-gicv3.c b/components/drivers/pic/pic-gicv3.c index d9249423ce26..a13ce5d2788b 100644 --- a/components/drivers/pic/pic-gicv3.c +++ b/components/drivers/pic/pic-gicv3.c @@ -257,7 +257,20 @@ static void gicv3_dist_init(void) HWREG64(base + GICD_IROUTERnE + i * 8) = affinity; } - _gic.max_irq = rt_min_t(int, MAX_HANDLERS - 1, RT_GENMASK(23, 0)); + if (GICD_TYPER_NUM_LPIS(_gic.gicd_typer)) + { + /* Max LPI = 8192 + Math.pow(2, num_LPIs + 1) - 1 */ + rt_size_t num_lpis = (1 << (GICD_TYPER_NUM_LPIS(_gic.gicd_typer) + 1)) + 1; + + _gic.lpi_nr = rt_min_t(int, num_lpis, 1 << GICD_TYPER_ID_BITS(_gic.gicd_typer)); + } + else + { + _gic.lpi_nr = 1 << GICD_TYPER_ID_BITS(_gic.gicd_typer); + } + + /* SPI + eSPI + LPIs */ + _gic.irq_nr = _gic.line_nr - 32 + _gic.espi_nr + _gic.lpi_nr; } static void gicv3_redist_enable(rt_bool_t enable) @@ -485,7 +498,7 @@ static rt_err_t gicv3_irq_set_priority(struct rt_pic_irq *pirq, rt_uint32_t prio static rt_err_t gicv3_irq_set_affinity(struct rt_pic_irq *pirq, bitmap_t *affinity) { rt_err_t ret = RT_EOK; - rt_uint64_t val; + rt_uint64_t val; rt_ubase_t mpidr; rt_uint32_t offset, index; int hwirq = pirq->hwirq, cpu_id = bitmap_next_set_bit(affinity, 0, RT_CPUS_NR); @@ -581,8 +594,19 @@ static void gicv3_irq_send_ipi(struct rt_pic_irq *pirq, bitmap_t *cpumask) static int gicv3_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) { - int irq, irq_index = hwirq - GIC_SGI_NR; - struct rt_pic_irq *pirq = rt_pic_find_irq(pic, irq_index); + struct rt_pic_irq *pirq; + int irq, hwirq_type, irq_index; + + hwirq_type = gicv3_hwirq_type(hwirq); + if (hwirq_type != LPI_TYPE) + { + irq_index = hwirq - GIC_SGI_NR; + } + else + { + irq_index = _gic.irq_nr - _gic.lpi_nr + hwirq - 8192; + } + pirq = rt_pic_find_irq(pic, irq_index); if (pirq && hwirq >= GIC_SGI_NR) { @@ -599,6 +623,11 @@ static int gicv3_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) } irq = rt_pic_config_irq(pic, irq_index, hwirq); + + if (irq >= 0 && mode != RT_IRQ_MODE_LEVEL_HIGH) + { + gicv3_irq_set_triger_mode(pirq, mode); + } } else { @@ -825,7 +854,7 @@ static void gicv3_init(void) _gic.parent.priv_data = &_gic; _gic.parent.ops = &gicv3_ops; - rt_pic_linear_irq(&_gic.parent, _gic.max_irq + 1 - GIC_SGI_NR); + rt_pic_linear_irq(&_gic.parent, _gic.irq_nr - GIC_SGI_NR); gic_common_sgi_config(_gic.dist_base, &_gic.parent, 0); rt_pic_add_traps(gicv3_handler, &_gic); @@ -857,11 +886,11 @@ static void gicv3_init_fail(void) static rt_err_t gicv3_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) { - rt_err_t ret = RT_EOK; + rt_err_t err = RT_EOK; do { rt_size_t reg_nr_max; - rt_err_t msi_init = -RT_ENOSYS; + rt_err_t msi_init = -RT_ENOSYS; rt_uint32_t redist_regions_nr; rt_uint64_t *regs, redist_stride; @@ -876,14 +905,17 @@ static rt_err_t gicv3_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_ if (!regs) { - ret = -RT_ENOMEM; + err = -RT_ENOMEM; break; } rt_ofw_get_address_array(np, reg_nr_max, regs); _gic.redist_regions_nr = redist_regions_nr; - if ((ret = gicv3_iomap_init(regs))) + err = gicv3_iomap_init(regs); + rt_free(regs); + + if (err) { break; } @@ -891,7 +923,7 @@ static rt_err_t gicv3_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_ if (_gic.version != 3 && _gic.version != 4) { LOG_E("Version = %d is not support", _gic.version); - ret = -RT_EINVAL; + err = -RT_EINVAL; break; } @@ -919,12 +951,12 @@ static rt_err_t gicv3_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_ } } while (0); - if (ret) + if (err) { gicv3_init_fail(); } - return ret; + return err; } static const struct rt_ofw_node_id gicv3_ofw_ids[] = diff --git a/components/drivers/pic/pic-gicv3.h b/components/drivers/pic/pic-gicv3.h index 53c03916090a..240cfe320c51 100644 --- a/components/drivers/pic/pic-gicv3.h +++ b/components/drivers/pic/pic-gicv3.h @@ -269,10 +269,11 @@ struct gicv3 struct rt_pic parent; int version; - int max_irq; + int irq_nr; rt_uint32_t gicd_typer; rt_size_t line_nr; rt_size_t espi_nr; + rt_size_t lpi_nr; rt_ubase_t flags; void *dist_base; diff --git a/components/drivers/pic/pic-riscv-intc.c b/components/drivers/pic/pic-riscv-intc.c deleted file mode 100755 index de6951930e85..000000000000 --- a/components/drivers/pic/pic-riscv-intc.c +++ /dev/null @@ -1,146 +0,0 @@ - interrupt-controller { - #interrupt-cells = <0x01>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - phandle = <0x02>; - }; - -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Regents of the University of California - * Copyright (C) 2017-2018 SiFive - * Copyright (C) 2020 Western Digital Corporation or its affiliates. - */ - -#define pr_fmt(fmt) "riscv-intc: " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct irq_domain *intc_domain; - -static asmlinkage void riscv_intc_irq(struct pt_regs *regs) -{ - unsigned long cause = regs->cause & ~CAUSE_IRQ_FLAG; - - if (unlikely(cause >= BITS_PER_LONG)) - panic("unexpected interrupt cause"); - - switch (cause) { -#ifdef CONFIG_SMP - case RV_IRQ_SOFT: - /* - * We only use software interrupts to pass IPIs, so if a - * non-SMP system gets one, then we don't know what to do. - */ - handle_IPI(regs); - break; -#endif - default: - generic_handle_domain_irq(intc_domain, cause); - break; - } -} - -/* - * On RISC-V systems local interrupts are masked or unmasked by writing - * the SIE (Supervisor Interrupt Enable) CSR. As CSRs can only be written - * on the local hart, these functions can only be called on the hart that - * corresponds to the IRQ chip. - */ - -static void riscv_intc_irq_mask(struct irq_data *d) -{ - csr_clear(CSR_IE, RT_BIT(d->hwirq)); -} - -static void riscv_intc_irq_unmask(struct irq_data *d) -{ - csr_set(CSR_IE, RT_BIT(d->hwirq)); -} - -static int riscv_intc_cpu_starting(unsigned int cpu) -{ - csr_set(CSR_IE, RT_BIT(RV_IRQ_SOFT)); - return 0; -} - -static int riscv_intc_cpu_dying(unsigned int cpu) -{ - csr_clear(CSR_IE, RT_BIT(RV_IRQ_SOFT)); - return 0; -} - -static struct irq_chip riscv_intc_chip = { - .name = "RISC-V INTC", - .irq_mask = riscv_intc_irq_mask, - .irq_unmask = riscv_intc_irq_unmask, -}; - -static int riscv_intc_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hwirq, &riscv_intc_chip, d->host_data, - handle_percpu_devid_irq, NULL, NULL); - - return 0; -} - -static const struct irq_domain_ops riscv_intc_domain_ops = { - .map = riscv_intc_domain_map, - .xlate = irq_domain_xlate_onecell, -}; - -static int __init riscv_intc_init(struct device_node *node, - struct device_node *parent) -{ - int rc; - unsigned long hartid; - - rc = riscv_of_parent_hartid(node, &hartid); - if (rc < 0) { - pr_warn("unable to find hart id for %pOF\n", node); - return 0; - } - - /* - * The DT will have one INTC DT node under each CPU (or HART) - * DT node so riscv_intc_init() function will be called once - * for each INTC DT node. We only need to do INTC initialization - * for the INTC DT node belonging to boot CPU (or boot HART). - */ - if (riscv_hartid_to_cpuid(hartid) != smp_processor_id()) - return 0; - - intc_domain = irq_domain_add_linear(node, BITS_PER_LONG, - &riscv_intc_domain_ops, NULL); - if (!intc_domain) { - pr_err("unable to add IRQ domain\n"); - return -ENXIO; - } - - rc = set_handle_irq(&riscv_intc_irq); - if (rc) { - pr_err("failed to set irq handler\n"); - return rc; - } - - cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_STARTING, - "irqchip/riscv/intc:starting", - riscv_intc_cpu_starting, - riscv_intc_cpu_dying); - - pr_info("%d local interrupts mapped\n", BITS_PER_LONG); - - return 0; -} - -IRQCHIP_DECLARE(riscv, "riscv,cpu-intc", riscv_intc_init); diff --git a/components/drivers/pic/pic-sifive-plic.c b/components/drivers/pic/pic-sifive-plic.c deleted file mode 100755 index a5157a79539b..000000000000 --- a/components/drivers/pic/pic-sifive-plic.c +++ /dev/null @@ -1,500 +0,0 @@ -plic@c000000 { - phandle = <0x09>; - riscv,ndev = <0x35>; - reg = <0x00 0xc000000 0x00 0x600000>; - interrupts-extended = <0x08 0x0b 0x08 0x09 0x06 0x0b 0x06 0x09 0x04 0x0b 0x04 0x09 0x02 0x0b 0x02 0x09>; - interrupt-controller; - compatible = "sifive,plic-1.0.0", "riscv,plic0"; - #interrupt-cells = <0x01>; -}; - -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2017 SiFive - * Copyright (C) 2018 Christoph Hellwig - */ -#define pr_fmt(fmt) "plic: " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This driver implements a version of the RISC-V PLIC with the actual layout - * specified in chapter 8 of the SiFive U5 Coreplex Series Manual: - * - * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf - * - * The largest number supported by devices marked as 'sifive,plic-1.0.0', is - * 1024, of which device 0 is defined as non-existent by the RISC-V Privileged - * Spec. - */ - -#define MAX_DEVICES 1024 -#define MAX_CONTEXTS 15872 - -/* - * Each interrupt source has a priority register associated with it. - * We always hardwire it to one in Linux. - */ -#define PRIORITY_BASE 0 -#define PRIORITY_PER_ID 4 - -/* - * Each hart context has a vector of interrupt enable bits associated with it. - * There's one bit for each interrupt source. - */ -#define CONTEXT_ENABLE_BASE 0x2000 -#define CONTEXT_ENABLE_SIZE 0x80 - -/* - * Each hart context has a set of control registers associated with it. Right - * now there's only two: a source priority threshold over which the hart will - * take an interrupt, and a register to claim interrupts. - */ -#define CONTEXT_BASE 0x200000 -#define CONTEXT_SIZE 0x1000 -#define CONTEXT_THRESHOLD 0x00 -#define CONTEXT_CLAIM 0x04 - -#define PLIC_DISABLE_THRESHOLD 0x7 -#define PLIC_ENABLE_THRESHOLD 0 - -#define PLIC_QUIRK_EDGE_INTERRUPT 0 - -struct plic_priv { - struct cpumask lmask; - struct irq_domain *irqdomain; - void __iomem *regs; - unsigned long plic_quirks; -}; - -struct plic_handler { - bool present; - void __iomem *hart_base; - /* - * Protect mask operations on the registers given that we can't - * assume atomic memory operations work on them. - */ - raw_spinlock_t enable_lock; - void __iomem *enable_base; - struct plic_priv *priv; -}; -static int plic_parent_irq __ro_after_init; -static bool plic_cpuhp_setup_done __ro_after_init; -static DEFINE_PER_CPU(struct plic_handler, plic_handlers); - -static int plic_irq_set_type(struct irq_data *d, unsigned int type); - -static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) -{ - u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32); - u32 hwirq_mask = 1 << (hwirq % 32); - - if (enable) - writel(readl(reg) | hwirq_mask, reg); - else - writel(readl(reg) & ~hwirq_mask, reg); -} - -static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) -{ - raw_spin_lock(&handler->enable_lock); - __plic_toggle(handler->enable_base, hwirq, enable); - raw_spin_unlock(&handler->enable_lock); -} - -static inline void plic_irq_toggle(const struct cpumask *mask, - struct irq_data *d, int enable) -{ - int cpu; - - for_each_cpu(cpu, mask) { - struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - - plic_toggle(handler, d->hwirq, enable); - } -} - -static void plic_irq_enable(struct irq_data *d) -{ - plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 1); -} - -static void plic_irq_disable(struct irq_data *d) -{ - plic_irq_toggle(irq_data_get_effective_affinity_mask(d), d, 0); -} - -static void plic_irq_unmask(struct irq_data *d) -{ - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - writel(1, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); -} - -static void plic_irq_mask(struct irq_data *d) -{ - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - writel(0, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); -} - -static void plic_irq_eoi(struct irq_data *d) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - - writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); -} - -#ifdef CONFIG_SMP -static int plic_set_affinity(struct irq_data *d, - const struct cpumask *mask_val, bool force) -{ - unsigned int cpu; - struct cpumask amask; - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - cpumask_and(&amask, &priv->lmask, mask_val); - - if (force) - cpu = cpumask_first(&amask); - else - cpu = cpumask_any_and(&amask, cpu_online_mask); - - if (cpu >= nr_cpu_ids) - return -EINVAL; - - plic_irq_disable(d); - - irq_data_update_effective_affinity(d, cpumask_of(cpu)); - - if (!irqd_irq_disabled(d)) - plic_irq_enable(d); - - return IRQ_SET_MASK_OK_DONE; -} -#endif - -static struct irq_chip plic_edge_chip = { - .name = "SiFive PLIC", - .irq_enable = plic_irq_enable, - .irq_disable = plic_irq_disable, - .irq_ack = plic_irq_eoi, - .irq_mask = plic_irq_mask, - .irq_unmask = plic_irq_unmask, -#ifdef CONFIG_SMP - .irq_set_affinity = plic_set_affinity, -#endif - .irq_set_type = plic_irq_set_type, - .flags = IRQCHIP_AFFINITY_PRE_STARTUP, -}; - -static struct irq_chip plic_chip = { - .name = "SiFive PLIC", - .irq_enable = plic_irq_enable, - .irq_disable = plic_irq_disable, - .irq_mask = plic_irq_mask, - .irq_unmask = plic_irq_unmask, - .irq_eoi = plic_irq_eoi, -#ifdef CONFIG_SMP - .irq_set_affinity = plic_set_affinity, -#endif - .irq_set_type = plic_irq_set_type, - .flags = IRQCHIP_AFFINITY_PRE_STARTUP, -}; - -static int plic_irq_set_type(struct irq_data *d, unsigned int type) -{ - struct plic_priv *priv = irq_data_get_irq_chip_data(d); - - if (!test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks)) - return IRQ_SET_MASK_OK_NOCOPY; - - switch (type) { - case IRQ_TYPE_EDGE_RISING: - irq_set_chip_handler_name_locked(d, &plic_edge_chip, - handle_edge_irq, NULL); - break; - case IRQ_TYPE_LEVEL_HIGH: - irq_set_chip_handler_name_locked(d, &plic_chip, - handle_fasteoi_irq, NULL); - break; - default: - return -EINVAL; - } - - return IRQ_SET_MASK_OK; -} - -static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct plic_priv *priv = d->host_data; - - irq_domain_set_info(d, irq, hwirq, &plic_chip, d->host_data, - handle_fasteoi_irq, NULL, NULL); - irq_set_noprobe(irq); - irq_set_affinity(irq, &priv->lmask); - return 0; -} - -static int plic_irq_domain_translate(struct irq_domain *d, - struct irq_fwspec *fwspec, - unsigned long *hwirq, - unsigned int *type) -{ - struct plic_priv *priv = d->host_data; - - if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks)) - return irq_domain_translate_twocell(d, fwspec, hwirq, type); - - return irq_domain_translate_onecell(d, fwspec, hwirq, type); -} - -static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, - unsigned int nr_irqs, void *arg) -{ - int i, ret; - irq_hw_number_t hwirq; - unsigned int type; - struct irq_fwspec *fwspec = arg; - - ret = plic_irq_domain_translate(domain, fwspec, &hwirq, &type); - if (ret) - return ret; - - for (i = 0; i < nr_irqs; i++) { - ret = plic_irqdomain_map(domain, virq + i, hwirq + i); - if (ret) - return ret; - } - - return 0; -} - -static const struct irq_domain_ops plic_irqdomain_ops = { - .translate = plic_irq_domain_translate, - .alloc = plic_irq_domain_alloc, - .free = irq_domain_free_irqs_top, -}; - -/* - * Handling an interrupt is a two-step process: first you claim the interrupt - * by reading the claim register, then you complete the interrupt by writing - * that source ID back to the same claim register. This automatically enables - * and disables the interrupt, so there's nothing else to do. - */ -static void plic_handle_irq(struct irq_desc *desc) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - struct irq_chip *chip = irq_desc_get_chip(desc); - void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; - irq_hw_number_t hwirq; - - WARN_ON_ONCE(!handler->present); - - chained_irq_enter(chip, desc); - - while ((hwirq = readl(claim))) { - int err = generic_handle_domain_irq(handler->priv->irqdomain, - hwirq); - if (unlikely(err)) - pr_warn_ratelimited("can't find mapping for hwirq %lu\n", - hwirq); - } - - chained_irq_exit(chip, desc); -} - -static void plic_set_threshold(struct plic_handler *handler, u32 threshold) -{ - /* priority must be > threshold to trigger an interrupt */ - writel(threshold, handler->hart_base + CONTEXT_THRESHOLD); -} - -static int plic_dying_cpu(unsigned int cpu) -{ - if (plic_parent_irq) - disable_percpu_irq(plic_parent_irq); - - return 0; -} - -static int plic_starting_cpu(unsigned int cpu) -{ - struct plic_handler *handler = this_cpu_ptr(&plic_handlers); - - if (plic_parent_irq) - enable_percpu_irq(plic_parent_irq, - irq_get_trigger_type(plic_parent_irq)); - else - pr_warn("cpu%d: parent irq not available\n", cpu); - plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD); - - return 0; -} - -static int __init __plic_init(struct device_node *node, - struct device_node *parent, - unsigned long plic_quirks) -{ - int error = 0, nr_contexts, nr_handlers = 0, i; - u32 nr_irqs; - struct plic_priv *priv; - struct plic_handler *handler; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->plic_quirks = plic_quirks; - - priv->regs = of_iomap(node, 0); - if (WARN_ON(!priv->regs)) { - error = -EIO; - goto out_free_priv; - } - - error = -EINVAL; - of_property_read_u32(node, "riscv,ndev", &nr_irqs); - if (WARN_ON(!nr_irqs)) - goto out_iounmap; - - nr_contexts = of_irq_count(node); - if (WARN_ON(!nr_contexts)) - goto out_iounmap; - - error = -ENOMEM; - priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1, - &plic_irqdomain_ops, priv); - if (WARN_ON(!priv->irqdomain)) - goto out_iounmap; - - for (i = 0; i < nr_contexts; i++) { - struct of_phandle_args parent; - irq_hw_number_t hwirq; - int cpu; - unsigned long hartid; - - if (of_irq_parse_one(node, i, &parent)) { - pr_err("failed to parse parent for context %d.\n", i); - continue; - } - - /* - * Skip contexts other than external interrupts for our - * privilege level. - */ - if (parent.args[0] != RV_IRQ_EXT) { - /* Disable S-mode enable bits if running in M-mode. */ - if (IS_ENABLED(CONFIG_RISCV_M_MODE)) { - void __iomem *enable_base = priv->regs + - CONTEXT_ENABLE_BASE + - i * CONTEXT_ENABLE_SIZE; - - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) - __plic_toggle(enable_base, hwirq, 0); - } - continue; - } - - error = riscv_of_parent_hartid(parent.np, &hartid); - if (error < 0) { - pr_warn("failed to parse hart ID for context %d.\n", i); - continue; - } - - cpu = riscv_hartid_to_cpuid(hartid); - if (cpu < 0) { - pr_warn("Invalid cpuid for context %d\n", i); - continue; - } - - /* Find parent domain and register chained handler */ - if (!plic_parent_irq && irq_find_host(parent.np)) { - plic_parent_irq = irq_of_parse_and_map(node, i); - if (plic_parent_irq) - irq_set_chained_handler(plic_parent_irq, - plic_handle_irq); - } - - /* - * When running in M-mode we need to ignore the S-mode handler. - * Here we assume it always comes later, but that might be a - * little fragile. - */ - handler = per_cpu_ptr(&plic_handlers, cpu); - if (handler->present) { - pr_warn("handler already present for context %d.\n", i); - plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD); - goto done; - } - - cpumask_set_cpu(cpu, &priv->lmask); - handler->present = true; - handler->hart_base = priv->regs + CONTEXT_BASE + - i * CONTEXT_SIZE; - raw_spin_lock_init(&handler->enable_lock); - handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE + - i * CONTEXT_ENABLE_SIZE; - handler->priv = priv; -done: - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { - plic_toggle(handler, hwirq, 0); - writel(1, priv->regs + PRIORITY_BASE + - hwirq * PRIORITY_PER_ID); - } - nr_handlers++; - } - - /* - * We can have multiple PLIC instances so setup cpuhp state only - * when context handler for current/boot CPU is present. - */ - handler = this_cpu_ptr(&plic_handlers); - if (handler->present && !plic_cpuhp_setup_done) { - cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - "irqchip/sifive/plic:starting", - plic_starting_cpu, plic_dying_cpu); - plic_cpuhp_setup_done = true; - } - - pr_info("%pOFP: mapped %d interrupts with %d handlers for" - " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts); - return 0; - -out_iounmap: - iounmap(priv->regs); -out_free_priv: - kfree(priv); - return error; -} - -static int __init plic_init(struct device_node *node, - struct device_node *parent) -{ - return __plic_init(node, parent, 0); -} - -IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init); -IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */ - -static int __init plic_edge_init(struct device_node *node, - struct device_node *parent) -{ - return __plic_init(node, parent, RT_BIT(PLIC_QUIRK_EDGE_INTERRUPT)); -} - -IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init); -IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init); diff --git a/components/drivers/pic/pic.c b/components/drivers/pic/pic.c index 240fcaa47c17..e9974fe267f4 100644 --- a/components/drivers/pic/pic.c +++ b/components/drivers/pic/pic.c @@ -54,9 +54,9 @@ static rt_list_t _traps_nodes = RT_LIST_OBJECT_INIT(_traps_nodes); static struct rt_pic_irq *irq2pirq(int irq) { - struct rt_pic_irq *pirq; + struct rt_pic_irq *pirq = RT_NULL; - if (irq >= 0 && irq < MAX_HANDLERS) + if ((irq >= 0) && (irq < MAX_HANDLERS)) { pirq = &_pirq_hash[irq]; @@ -86,6 +86,48 @@ static void append_pic(struct rt_pic *pic) } } +void rt_pic_default_name(struct rt_pic *pic) +{ + if (pic) + { + #if RT_NAME_MAX > 0 + rt_strncpy(pic->parent.name, "PIC", RT_NAME_MAX); + #else + pic->parent.name = "PIC"; + #endif + } +} + +struct rt_pic *rt_pic_dynamic_cast(void *ptr) +{ + struct rt_pic *pic = RT_NULL, *tmp = RT_NULL; + + if (ptr) + { + struct rt_object *obj = ptr; + + if (obj->type == RT_Object_Class_Unknown) + { + tmp = (void *)obj; + } + else if (obj->type == RT_Object_Class_Device) + { + tmp = (void *)obj + sizeof(struct rt_device); + } + else + { + tmp = (void *)obj + sizeof(struct rt_object); + } + + if (tmp && !rt_strcmp(tmp->parent.name, "PIC")) + { + pic = tmp; + } + } + + return pic; +} + rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr) { rt_err_t err = RT_EOK; @@ -98,6 +140,9 @@ rt_err_t rt_pic_linear_irq(struct rt_pic *pic, rt_size_t irq_nr) { rt_list_init(&pic->list); + rt_pic_default_name(pic); + pic->parent.type = RT_Object_Class_Unknown; + pic->irq_start = _pirq_hash_idx; pic->irq_nr = irq_nr; pic->pirqs = &_pirq_hash[_pirq_hash_idx]; @@ -195,91 +240,63 @@ struct rt_pic_irq *rt_pic_find_ipi(struct rt_pic *pic, int ipi_index) return pirq; } -int rt_pic_cascade(struct rt_pic *pic, struct rt_pic *parent_pic, int hwirq, rt_uint32_t mode) +struct rt_pic_irq *rt_pic_find_pirq(struct rt_pic *pic, int irq) { - int irq = -RT_EINVAL; - - if (pic && parent_pic && hwirq >= 0) + if (pic && irq >= pic->irq_start && irq <= pic->irq_start + pic->irq_nr) { - struct rt_pic *ppic = parent_pic; - rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock); - - while (!ppic->ops->irq_map && ppic->parent) - { - ppic = ppic->parent; - } - - rt_spin_unlock_irqrestore(&_pic_lock, level); - - if (ppic->ops->irq_map) - { - struct rt_pic_irq *pirq; - - irq = ppic->ops->irq_map(ppic, hwirq, mode); + return &pic->pirqs[irq - pic->irq_start]; + } - if (irq >= 0 && (pirq = irq2pirq(irq))) - { - rt_spin_lock(&pirq->rw_lock); + return RT_NULL; +} - pirq->pic = pic; - pic->parent = parent_pic; +rt_err_t rt_pic_cascade(struct rt_pic_irq *pirq, int parent_irq) +{ + rt_err_t err = RT_EOK; - rt_spin_unlock(&pirq->rw_lock); + if (pirq && !pirq->parent && parent_irq >= 0) + { + struct rt_pic_irq *parent; - if (rt_list_isempty(&pic->list)) - { - rt_ubase_t level = rt_spin_lock_irqsave(&_pic_lock); + rt_spin_lock(&pirq->rw_lock); - append_pic(pic); + parent = irq2pirq(parent_irq); - rt_spin_unlock_irqrestore(&_pic_lock, level); - } - } - } - else + if (parent) { - irq = -RT_ENOSYS; + pirq->parent = parent; + pirq->priority = parent->priority; + rt_memcpy(&pirq->affinity, &parent->affinity, sizeof(pirq->affinity)); } + + rt_spin_unlock(&pirq->rw_lock); + } + else + { + err = -RT_EINVAL; } - return irq; + return err; } -void rt_pic_uncascade(struct rt_pic *pic, int irq) +rt_err_t rt_pic_uncascade(struct rt_pic_irq *pirq) { - struct rt_pic_irq *pirq; + rt_err_t err = RT_EOK; - if (pic && pic->parent && irq >= 0 && (pirq = irq2pirq(irq))) + if (pirq && pirq->parent) { - struct rt_pic *ppic, *prev = RT_NULL; - rt_spin_lock(&pirq->rw_lock); - ppic = pirq->pic; - - while (ppic && pic->parent != ppic->parent) - { - prev = ppic; - ppic = ppic->parent; - } - - if (ppic) - { - if (prev) - { - pirq->pic = prev; - prev->parent = pic->parent; - } - else - { - pirq->pic = pic->parent; - } - - pic->parent = RT_NULL; - } + pirq->parent = RT_NULL; rt_spin_unlock(&pirq->rw_lock); } + else + { + err = -RT_EINVAL; + } + + return err; } rt_err_t rt_pic_attach_irq(int irq, rt_isr_handler_t handler, void *uid, const char *name, int flags) @@ -453,7 +470,7 @@ rt_err_t rt_pic_do_traps(void) rt_err_t rt_pic_handle_isr(struct rt_pic_irq *pirq) { - rt_err_t err; + rt_err_t err = RT_EOK; rt_list_t *handler_nodes; struct rt_irq_desc *action; @@ -547,49 +564,101 @@ rt_err_t rt_pic_irq_finit(void) return err; } -#define _irq_call_helper(irq, fn) \ -({ \ - struct rt_pic_irq *pirq; \ - if ((pirq = irq2pirq(irq))) \ - { \ - rt_spin_lock(&pirq->rw_lock); \ - if (pirq->pic->ops->fn) \ - pirq->pic->ops->fn(pirq); \ - rt_spin_unlock(&pirq->rw_lock); \ - } \ -}) - void rt_pic_irq_enable(int irq) { - _irq_call_helper(irq, irq_enable); + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_enable) + { + pirq->pic->ops->irq_enable(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); } void rt_pic_irq_disable(int irq) { - _irq_call_helper(irq, irq_disable); + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_disable) + { + pirq->pic->ops->irq_disable(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); } void rt_pic_irq_ack(int irq) { - _irq_call_helper(irq, irq_ack); + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_ack) + { + pirq->pic->ops->irq_ack(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); } void rt_pic_irq_mask(int irq) { - _irq_call_helper(irq, irq_mask); + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_mask) + { + pirq->pic->ops->irq_mask(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); } void rt_pic_irq_unmask(int irq) { - _irq_call_helper(irq, irq_unmask); + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_unmask) + { + pirq->pic->ops->irq_unmask(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); } void rt_pic_irq_eoi(int irq) { - _irq_call_helper(irq, irq_eoi); -} + struct rt_pic_irq *pirq = irq2pirq(irq); -#undef _irq_call_helper + RT_ASSERT(pirq != RT_NULL); + + rt_spin_lock(&pirq->rw_lock); + + if (pirq->pic->ops->irq_eoi) + { + pirq->pic->ops->irq_eoi(pirq); + } + + rt_spin_unlock(&pirq->rw_lock); +} rt_err_t rt_pic_irq_set_priority(int irq, rt_uint32_t priority) { @@ -747,82 +816,126 @@ void rt_pic_irq_send_ipi(int irq, bitmap_t *cpumask) } } -#define _pirq_parent_call_helper(ppic, pirq, fn, ret,...) \ -({ \ - if (ppic && pirq) \ - { \ - rt_spin_lock(&pirq->rw_lock); \ - if (ppic->ops->fn) \ - { \ - struct rt_pic *cpic; \ - cpic = pirq->pic; /* push old pic */ \ - pirq->pic = ppic; \ - ret ppic->ops->fn(pirq __VA_ARGS__); \ - pirq->pic = cpic; /* pop old pic */ \ - } \ - rt_spin_unlock(&pirq->rw_lock); \ - } \ -}) - -void rt_pic_irq_parent_enable(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_enable(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_enable,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_enable) + { + pirq->pic->ops->irq_enable(pirq); + } } -void rt_pic_irq_parent_disable(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_disable(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_disable,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_disable) + { + pirq->pic->ops->irq_disable(pirq); + } } -void rt_pic_irq_parent_ack(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_ack(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_ack,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_ack) + { + pirq->pic->ops->irq_ack(pirq); + } } -void rt_pic_irq_parent_mask(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_mask(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_mask,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_mask) + { + pirq->pic->ops->irq_mask(pirq); + } } -void rt_pic_irq_parent_unmask(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_unmask(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_unmask,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_unmask) + { + pirq->pic->ops->irq_unmask(pirq); + } } -void rt_pic_irq_parent_eoi(struct rt_pic *ppic, struct rt_pic_irq *pirq) +void rt_pic_irq_parent_eoi(struct rt_pic_irq *pirq) { - _pirq_parent_call_helper(ppic, pirq, irq_eoi,,); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_eoi) + { + pirq->pic->ops->irq_eoi(pirq); + } } -rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t priority) +rt_err_t rt_pic_irq_parent_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority) { rt_err_t err = -RT_ENOSYS; - _pirq_parent_call_helper(ppic, pirq, irq_set_priority, err = , ,priority); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_set_priority) + { + if (!(err = pirq->pic->ops->irq_set_priority(pirq, priority))) + { + pirq->priority = priority; + } + } return err; } -rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic *ppic, struct rt_pic_irq *pirq, bitmap_t *affinity) +rt_err_t rt_pic_irq_parent_set_affinity(struct rt_pic_irq *pirq, bitmap_t *affinity) { rt_err_t err = -RT_ENOSYS; - _pirq_parent_call_helper(ppic, pirq, irq_set_affinity, err = , ,affinity); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_set_affinity) + { + if (!(err = pirq->pic->ops->irq_set_affinity(pirq, affinity))) + { + rt_memcpy(pirq->affinity, affinity, sizeof(pirq->affinity)); + } + } return err; } -rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic *ppic, struct rt_pic_irq *pirq, rt_uint32_t mode) +rt_err_t rt_pic_irq_parent_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode) { rt_err_t err = -RT_ENOSYS; - _pirq_parent_call_helper(ppic, pirq, irq_set_triger_mode, err = , ,mode); + RT_ASSERT(pirq != RT_NULL); + pirq = pirq->parent; + + if (pirq->pic->ops->irq_set_triger_mode) + { + if (!(err = pirq->pic->ops->irq_set_triger_mode(pirq, mode))) + { + pirq->mode = mode; + } + } return err; } -#undef _pirq_parent_call_helper - #ifdef RT_USING_OFW RT_OFW_STUB_RANGE_EXPORT(pic, _pic_ofw_start, _pic_ofw_end); diff --git a/components/drivers/pin/Kconfig b/components/drivers/pin/Kconfig index 2d359718085c..2f1912b83075 100755 --- a/components/drivers/pin/Kconfig +++ b/components/drivers/pin/Kconfig @@ -1,5 +1,5 @@ menuconfig RT_USING_PIN - bool "Using generic GPIO device drivers" + bool "Using Generic GPIO device drivers" default y config RT_PIN_PL061 @@ -7,3 +7,10 @@ config RT_PIN_PL061 depends on RT_USING_DM depends on RT_USING_PIN default n + +config RT_PIN_ROCKCHIP + bool "Rockchip GPIO support" + depends on RT_USING_DM + depends on RT_USING_PIN + select RT_USING_OFW + default n diff --git a/components/drivers/pin/SConscript b/components/drivers/pin/SConscript index 0cfe2790d513..652955fe7459 100755 --- a/components/drivers/pin/SConscript +++ b/components/drivers/pin/SConscript @@ -10,9 +10,18 @@ CPPPATH = [cwd + '/../include'] src = ['pin.c'] +if GetDepend(['RT_USING_DM']): + src += ['pin_dm.c'] + +if GetDepend(['RT_USING_OFW']): + src += ['pin_ofw.c'] + if GetDepend(['RT_PIN_PL061']): src += ['pin-pl061.c'] +if GetDepend(['RT_PIN_ROCKCHIP']): + src += ['pin-rockchip.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/pin/pin-pl061.c b/components/drivers/pin/pin-pl061.c index dc5bc899f6df..770a3c8d2d5b 100755 --- a/components/drivers/pin/pin-pl061.c +++ b/components/drivers/pin/pin-pl061.c @@ -12,6 +12,8 @@ #include #include +#include "pin_dm.h" + #define PL061_DIR 0x400 #define PL061_IS 0x404 #define PL061_IBE 0x408 @@ -25,13 +27,15 @@ struct pl061 { - void *base; + struct rt_device_pin parent; + int irq; + void *base; + struct rt_clk *pclk; struct rt_spinlock spinlock; - void (*hdr[PL061_GPIO_NR])(void *args); - void *args[PL061_GPIO_NR]; + struct rt_pin_irq_hdr hdr[PL061_GPIO_NR]; }; #define raw_to_pl061(raw) ((struct pl061 *)((raw)->user_data)) @@ -64,11 +68,15 @@ static void pl061_isr(int irqno, void *param) { if (pending & RT_BIT(pin)) { + struct rt_pin_irq_hdr *hdr_info = &pl061->hdr[pin]; + mask |= RT_BIT(pin); - if (pl061->hdr[pin]) + pin_pic_handle_isr(&pl061->parent, pin); + + if (hdr_info->hdr) { - pl061->hdr[pin](pl061->args[pin]); + hdr_info->hdr(hdr_info->args); } } } @@ -141,8 +149,93 @@ static rt_int8_t pl061_pin_read(struct rt_device *device, rt_base_t pin) return value; } +static rt_err_t pl061_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); + static rt_err_t pl061_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) +{ + rt_err_t err; + rt_ubase_t level; + struct rt_pin_irq_hdr *hdr_info; + struct pl061 *pl061 = raw_to_pl061(device); + + if (pin < 0 || pin >= PL061_GPIO_NR) + { + return -RT_EINVAL; + } + + if ((err = pl061_pin_irq_mode(device, pin, mode))) + { + return err; + } + + level = rt_spin_lock_irqsave(&pl061->spinlock); + + hdr_info = &pl061->hdr[pin]; + hdr_info->hdr = hdr; + hdr_info->args = args; + + rt_spin_unlock_irqrestore(&pl061->spinlock, level); + + return err; +} + +static rt_err_t pl061_pin_detach_irq(struct rt_device *device, rt_base_t pin) +{ + rt_err_t err = RT_EOK; + struct rt_pin_irq_hdr *hdr_info; + struct pl061 *pl061 = raw_to_pl061(device); + + if (pin >= 0 && pin < PL061_GPIO_NR) + { + rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock); + + hdr_info = &pl061->hdr[pin]; + hdr_info->hdr = RT_NULL; + hdr_info->args = RT_NULL; + + rt_spin_unlock_irqrestore(&pl061->spinlock, level); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t pl061_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_err_t err = RT_EOK; + struct pl061 *pl061 = raw_to_pl061(device); + + if (pin >= 0 && pin < PL061_GPIO_NR) + { + rt_uint8_t gpioie, mask = RT_BIT(pin); + rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock); + + if (enabled) + { + gpioie = pl061_read(pl061, PL061_IE) | mask; + } + else + { + gpioie = pl061_read(pl061, PL061_IE) & ~mask; + } + + pl061_write(pl061, PL061_IE, gpioie); + + rt_spin_unlock_irqrestore(&pl061->spinlock, level); + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static rt_err_t pl061_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) { rt_err_t err = RT_EOK; struct pl061 *pl061 = raw_to_pl061(device); @@ -213,62 +306,6 @@ static rt_err_t pl061_pin_attach_irq(struct rt_device *device, rt_base_t pin, pl061_write(pl061, PL061_IBE, gpioibe); pl061_write(pl061, PL061_IEV, gpioiev); - pl061->hdr[pin] = hdr; - pl061->args[pin] = args; - - rt_spin_unlock_irqrestore(&pl061->spinlock, level); - } - else - { - err = -RT_EINVAL; - } - - return err; -} - -static rt_err_t pl061_pin_detach_irq(struct rt_device *device, rt_base_t pin) -{ - rt_err_t err = RT_EOK; - struct pl061 *pl061 = raw_to_pl061(device); - - if (pin >= 0 && pin < PL061_GPIO_NR) - { - rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock); - - pl061->hdr[pin] = RT_NULL; - pl061->args[pin] = RT_NULL; - - rt_spin_unlock_irqrestore(&pl061->spinlock, level); - } - else - { - err = -RT_EINVAL; - } - - return err; -} - -static rt_err_t pl061_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) -{ - rt_err_t err = RT_EOK; - struct pl061 *pl061 = raw_to_pl061(device); - - if (pin >= 0 && pin < PL061_GPIO_NR) - { - rt_uint8_t gpioie, mask = RT_BIT(pin); - rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock); - - if (enabled) - { - gpioie = pl061_read(pl061, PL061_IE) | mask; - } - else - { - gpioie = pl061_read(pl061, PL061_IE) & ~mask; - } - - pl061_write(pl061, PL061_IE, gpioie); - rt_spin_unlock_irqrestore(&pl061->spinlock, level); } else @@ -287,60 +324,83 @@ static const struct rt_pin_ops pl061_pin_ops = .pin_attach_irq = pl061_pin_attach_irq, .pin_detach_irq = pl061_pin_detach_irq, .pin_irq_enable = pl061_pin_irq_enable, + .pin_irq_mode = pl061_pin_irq_mode, }; -static rt_err_t pl061_ofw_init(struct rt_platform_device *pdev, struct pl061 *pl061) +static rt_err_t pl061_probe(struct rt_platform_device *pdev) { - rt_err_t err = RT_EOK; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - pl061->base = rt_ofw_iomap(np, 0); + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct pl061 *pl061 = rt_calloc(1, sizeof(*pl061)); - if (pl061->base) + if (!pl061) { - pl061->irq = rt_ofw_get_irq(np, 0); - - if (pl061->irq < 0) - { - err = -RT_ERROR; - } + return -RT_ENOMEM; } - else + + pl061->base = rt_dm_dev_iomap(dev, 0); + + if (!pl061->base) { err = -RT_EIO; - } - return err; -} + goto _fail; + } -static rt_err_t pl061_probe(struct rt_platform_device *pdev) -{ - rt_err_t err = RT_EOK; - struct pl061 *pl061 = rt_calloc(1, sizeof(*pl061)); + pl061->irq = rt_dm_dev_get_irq(dev, 0); - if (pl061) + if (pl061->irq < 0) { - err = pl061_ofw_init(pdev, pl061); + err = pl061->irq; + + goto _fail; } - else + + pl061->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!pl061->pclk) { - err = -RT_ENOMEM; + err = -RT_EIO; + + goto _fail; } - if (!err) + if ((err = rt_clk_prepare_enable(pl061->pclk))) { - rt_spin_lock_init(&pl061->spinlock); + goto _fail; + } - rt_device_pin_register("gpio", &pl061_pin_ops, pl061); + rt_dm_dev_bind_fwdata(dev, RT_NULL, &pl061->parent); - rt_hw_interrupt_install(pl061->irq, pl061_isr, pl061, "gpio-pl061"); - rt_hw_interrupt_umask(pl061->irq); + rt_spin_lock_init(&pl061->spinlock); + + pl061->parent.irqchip.irq = pl061->irq; + pl061->parent.irqchip.pin_range[0] = 0; + pl061->parent.irqchip.pin_range[1] = PL061_GPIO_NR - 1; + pl061->parent.ops = &pl061_pin_ops; + pin_pic_init(&pl061->parent); + + rt_device_pin_register("gpio", &pl061_pin_ops, pl061); + + rt_hw_interrupt_install(pl061->irq, pl061_isr, pl061, "gpio-pl061"); + rt_hw_interrupt_umask(pl061->irq); + + return RT_EOK; + +_fail: + if (pl061->base) + { + rt_iounmap(pl061->base); } - else + + if (pl061->pclk) { - rt_free(pl061); + rt_clk_disable_unprepare(pl061->pclk); + rt_clk_put(pl061->pclk); } + rt_free(pl061); + return err; } diff --git a/components/drivers/pin/pin-rockchip.c b/components/drivers/pin/pin-rockchip.c new file mode 100644 index 000000000000..de46459d0df8 --- /dev/null +++ b/components/drivers/pin/pin-rockchip.c @@ -0,0 +1,678 @@ +/* + * 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 "pin_dm.h" +#include "../pinctrl/pinctrl-rockchip.h" + +#define RK_PIN_MAX RK_GPIO4_D7 + +struct rk_gpio +{ + struct rt_device parent; + rt_bool_t init_ok; + + struct + { + struct rt_pin_irq_hdr hdr; + rt_uint32_t mask_cache; + } irq_info[RK_PIN_MAX]; + + struct rockchip_pinctrl_device *pinctrl_dev; +}; + +static struct rk_gpio rk_gpio = +{ + .init_ok = RT_FALSE, + .irq_info[0 ... RK_PIN_MAX - 1] = + { + .mask_cache = 0xffffffffU, + } +}; + +#define raw_pin_to_bank(raw, pin) \ +({ \ + struct rockchip_pin_bank *___pin_bank = RT_NULL; \ + struct rockchip_pinctrl_device *___pinctrl_dev = (raw)->user_data; \ + struct rockchip_pin_ctrl *___pinctrl = ___pinctrl_dev->pinctrl; \ + if (pin <= RK_PIN_MAX && ___pinctrl->pin_banks[(pin) / 32].gpio_regs) \ + { \ + ___pin_bank = &___pinctrl->pin_banks[(pin) / 32]; \ + } \ + ___pin_bank; \ +}) +#define raw_pin_to_id(pin) (pin % 32) + +#define GPIO_TYPE_V1 0 +#define GPIO_TYPE_V2 0x01000c2b +#define GPIO_TYPE_V2_1 0x0101157c + +static const struct rockchip_gpio_regs _gpio_regs_v1 = +{ + .port_dr = 0x00, + .port_ddr = 0x04, + .int_en = 0x30, + .int_mask = 0x34, + .int_type = 0x38, + .int_polarity = 0x3c, + .int_status = 0x40, + .int_rawstatus = 0x44, + .debounce = 0x48, + .port_eoi = 0x4c, + .ext_port = 0x50, +}; + +static const struct rockchip_gpio_regs _gpio_regs_v2 = +{ + .port_dr = 0x00, + .port_ddr = 0x08, + .int_en = 0x10, + .int_mask = 0x18, + .int_type = 0x20, + .int_polarity = 0x28, + .int_bothedge = 0x30, + .int_status = 0x50, + .int_rawstatus = 0x58, + .debounce = 0x38, + .dbclk_div_en = 0x40, + .dbclk_div_con = 0x48, + .port_eoi = 0x60, + .ext_port = 0x70, + .version_id = 0x78, +}; + +rt_inline void gpio_writel_v2(void *base, rt_uint32_t val) +{ + HWREG32(base) = (val & 0xffff) | 0xffff0000U; + HWREG32(base + 0x4) = (val >> 16) | 0xffff0000U; +} + +rt_inline rt_uint32_t gpio_readl_v2(void *base) +{ + return HWREG32(base + 0x4) << 16 | HWREG32(base); +} + +rt_inline void rockchip_gpio_writel(struct rockchip_pin_bank *pin_bank, rt_uint32_t value, int offset) +{ + void *base = pin_bank->reg_base + offset; + + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + gpio_writel_v2(base, value); + } + else + { + HWREG32(base) = value; + } +} + +rt_inline rt_uint32_t rockchip_gpio_readl(struct rockchip_pin_bank *pin_bank, int offset) +{ + rt_uint32_t value; + void *base = pin_bank->reg_base + offset; + + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + value = gpio_readl_v2(base); + } + else + { + value = HWREG32(base); + } + + return value; +} + +rt_inline void rockchip_gpio_writel_bit(struct rockchip_pin_bank *pin_bank, + rt_uint32_t bit, rt_uint32_t value, int offset) +{ + rt_uint32_t data; + void *base = pin_bank->reg_base + offset; + + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + if (value) + { + data = RT_BIT(bit % 16) | RT_BIT(bit % 16 + 16); + } + else + { + data = RT_BIT(bit % 16 + 16); + } + HWREG32(bit >= 16 ? base + 0x4 : base) = data; + } + else + { + data = HWREG32(base); + data &= ~RT_BIT(bit); + + if (value) + { + data |= RT_BIT(bit); + } + HWREG32(base) = data; + } +} + +rt_inline rt_uint32_t rockchip_gpio_readl_bit(struct rockchip_pin_bank *pin_bank, + rt_uint32_t bit, int offset) +{ + rt_uint32_t data; + void *base = pin_bank->reg_base + offset; + + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + data = HWREG32(bit >= 16 ? base + 0x4 : base); + data >>= bit % 16; + } + else + { + data = HWREG32(base); + data >>= bit; + } + + return data & (0x1); +} + +static void rk_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_base_t level; + struct rockchip_pinctrl_device *pinctrl_dev = device->user_data; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return; + } + + switch (mode) + { + case PIN_MODE_OUTPUT: + case PIN_MODE_OUTPUT_OD: + pinctrl_dev->pinctrl->set_mux(pin_bank, pin, RK_FUNC_GPIO); + + level = rt_spin_lock_irqsave(&pin_bank->spinlock); + rockchip_gpio_writel_bit(pin_bank, raw_pin_to_id(pin), 1, pin_bank->gpio_regs->port_ddr); + rt_spin_unlock_irqrestore(&pin_bank->spinlock, level); + break; + + case PIN_MODE_INPUT: + case PIN_MODE_INPUT_PULLUP: + case PIN_MODE_INPUT_PULLDOWN: + pinctrl_dev->pinctrl->set_mux(pin_bank, pin, RK_FUNC_GPIO); + + level = rt_spin_lock_irqsave(&pin_bank->spinlock); + rockchip_gpio_writel_bit(pin_bank, raw_pin_to_id(pin), 0, pin_bank->gpio_regs->port_ddr); + rt_spin_unlock_irqrestore(&pin_bank->spinlock, level); + break; + + default: + break; + } +} + +static void rk_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) +{ + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return; + } + + rockchip_gpio_writel_bit(pin_bank, raw_pin_to_id(pin), value, pin_bank->gpio_regs->port_dr); +} + +static rt_int8_t rk_pin_read(struct rt_device *device, rt_base_t pin) +{ + rt_uint32_t data; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return -1; + } + + data = HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->ext_port); + data >>= raw_pin_to_id(pin); + data &= 1; + + return data; +} + +static rt_err_t rk_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); + +static rt_err_t rk_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, + void (*hdr)(void *args), void *args) +{ + rt_err_t err; + typeof(rk_gpio.irq_info[0]) *irq_info; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank || !hdr) + { + return -RT_EINVAL; + } + + if ((err = rk_pin_irq_mode(device, pin, mode))) + { + return err; + } + + irq_info = &rk_gpio.irq_info[pin]; + + irq_info->hdr.mode = mode; + irq_info->hdr.args = args; + irq_info->hdr.hdr = hdr; + + return RT_EOK; +} + +static rt_err_t rk_pin_detach_irq(struct rt_device *device, rt_base_t pin) +{ + typeof(rk_gpio.irq_info[0]) *irq_info; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return -RT_EINVAL; + } + + irq_info = &rk_gpio.irq_info[pin]; + + irq_info->hdr.hdr = RT_NULL; + irq_info->hdr.args = RT_NULL; + + return RT_EOK; +} + +static rt_err_t rk_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) +{ + rt_base_t level; + typeof(rk_gpio.irq_info[0]) *irq_info; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&pin_bank->spinlock); + irq_info = &rk_gpio.irq_info[pin]; + + if (enabled) + { + irq_info->mask_cache &= ~RT_BIT(raw_pin_to_id(pin)); + } + else + { + irq_info->mask_cache |= RT_BIT(raw_pin_to_id(pin)); + } + rockchip_gpio_writel(pin_bank, irq_info->mask_cache, pin_bank->gpio_regs->int_mask); + + rt_spin_unlock_irqrestore(&pin_bank->spinlock, level); + + return RT_EOK; +} + +static rt_err_t rk_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) +{ + rt_base_t level; + rt_err_t err = RT_EOK; + rt_uint32_t mask, int_level, polarity, data; + struct rockchip_pin_bank *pin_bank = raw_pin_to_bank(device, pin); + + if (!pin_bank) + { + return -RT_EINVAL; + } + + level = rt_spin_lock_irqsave(&pin_bank->spinlock); + + mask = RT_BIT(raw_pin_to_id(pin)); + int_level = rockchip_gpio_readl(pin_bank, pin_bank->gpio_regs->int_type); + polarity = rockchip_gpio_readl(pin_bank, pin_bank->gpio_regs->int_polarity); + + if (mode == PIN_IRQ_MODE_RISING_FALLING) + { + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + rockchip_gpio_writel_bit(pin_bank, raw_pin_to_id(pin), 1, pin_bank->gpio_regs->int_bothedge); + goto _end; + } + else + { + pin_bank->toggle_edge_mode |= mask; + int_level &= ~mask; + + /* + * Determine gpio state. If 1 next interrupt should be + * low otherwise high. + */ + data = HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->ext_port); + + if (data & mask) + { + polarity &= ~mask; + } + else + { + polarity |= mask; + } + } + } + else + { + if (pin_bank->gpio_type == GPIO_TYPE_V2) + { + rockchip_gpio_writel_bit(pin_bank, raw_pin_to_id(pin), 0, pin_bank->gpio_regs->int_bothedge); + } + else + { + pin_bank->toggle_edge_mode &= ~mask; + } + + switch (mode) + { + case PIN_IRQ_MODE_RISING: + int_level |= mask; + polarity |= mask; + break; + + case PIN_IRQ_MODE_FALLING: + int_level |= mask; + polarity &= ~mask; + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + int_level &= ~mask; + polarity |= mask; + break; + + case PIN_IRQ_MODE_LOW_LEVEL: + int_level &= ~mask; + polarity &= ~mask; + break; + + default: + err = -RT_EINVAL; + goto _end; + } + } + + rockchip_gpio_writel(pin_bank, int_level, pin_bank->gpio_regs->int_type); + rockchip_gpio_writel(pin_bank, polarity, pin_bank->gpio_regs->int_polarity); + +_end: + rt_spin_unlock_irqrestore(&pin_bank->spinlock, level); + + return err; +} + +static rt_ssize_t rk_pin_parse(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags) +{ + rt_ssize_t pin; + struct rt_device_pin *pin_dev = rt_ofw_data(args->data); + + pin = pin_dev->irqchip.pin_range[0] + args->args[0]; + + if (flags) + { + *flags = args->args[1]; + } + + return pin; +} + +static const struct rt_pin_ops rk_pin_ops = +{ + .pin_mode = rk_pin_mode, + .pin_write = rk_pin_write, + .pin_read = rk_pin_read, + .pin_attach_irq = rk_pin_attach_irq, + .pin_detach_irq = rk_pin_detach_irq, + .pin_irq_enable = rk_pin_irq_enable, + .pin_irq_mode = rk_pin_irq_mode, + .pin_parse = rk_pin_parse, +}; + +static void rk_pin_isr(int irqno, void *param) +{ + rt_uint32_t pending; + struct rockchip_pin_bank *pin_bank = param; + + pending = rockchip_gpio_readl(pin_bank, pin_bank->gpio_regs->int_status); + + for (rt_ubase_t pin = 0; pin < 32 && pending; ++pin) + { + rt_uint32_t clr = RT_BIT(pin); + typeof(rk_gpio.irq_info[0]) *irq_info; + + if (!(clr & pending)) + { + continue; + } + + if (clr & pin_bank->toggle_edge_mode) + { + rt_uint32_t data, data_old, polarity; + + data = HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->ext_port); + + do { + rt_ubase_t level = rt_spin_lock_irqsave(&pin_bank->spinlock); + + polarity = HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->int_polarity); + + if (data & clr) + { + polarity &= ~clr; + } + else + { + polarity |= clr; + } + HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->int_polarity) = polarity; + + rt_spin_unlock_irqrestore(&pin_bank->spinlock, level); + + data_old = data; + data = HWREG32(pin_bank->reg_base + pin_bank->gpio_regs->ext_port); + } while ((data & clr) != (data_old & clr)); + + /* clear this pin irq */ + pending &= ~clr; + } + + pin_pic_handle_isr(&pin_bank->parent, pin); + + irq_info = &rk_gpio.irq_info[pin_bank->parent.irqchip.pin_range[0] + pin]; + + if (irq_info->hdr.hdr) + { + irq_info->hdr.hdr(irq_info->hdr.args); + } + } +} + +static rt_err_t rockchip_gpio_probe(struct rt_platform_device *pdev) +{ + int id, version; + const char *name; + rt_err_t err = RT_EOK; + struct rockchip_pin_bank *pin_bank; + struct rt_ofw_node *np = pdev->parent.ofw_node; + struct rt_ofw_node *npp = rt_ofw_get_parent(np); + struct rockchip_pinctrl_device *pinctrl_dev = rt_ofw_data(npp); + struct rockchip_pin_ctrl *pinctrl = pinctrl_dev->pinctrl; + static int gpio_uid = 0; + + rt_ofw_node_put(npp); + + id = rt_ofw_get_alias_id(np, "gpio"); + + if (id < 0) + { + id = gpio_uid++; + } + + pin_bank = &pinctrl->pin_banks[id]; + + pin_bank->reg_base = rt_ofw_iomap(np, 0); + + if (!pin_bank->reg_base) + { + goto _out_res; + } + + pin_bank->irq = rt_ofw_get_irq(np, 0); + + if (pin_bank->irq < 0) + { + goto _out_res; + } + + pin_bank->clk = rt_ofw_get_clk(np, 0); + + if (!pin_bank->clk) + { + goto _out_res; + } + + rt_clk_prepare_enable(pin_bank->clk); + + version = HWREG32(pin_bank->reg_base + _gpio_regs_v2.version_id); + + if (version == GPIO_TYPE_V2 || version == GPIO_TYPE_V2_1) + { + pin_bank->gpio_regs = &_gpio_regs_v2; + pin_bank->gpio_type = GPIO_TYPE_V2; + + pin_bank->db_clk = rt_ofw_get_clk(np, 1); + + if (!pin_bank->db_clk) + { + goto _out_res; + } + } + else + { + pin_bank->gpio_regs = &_gpio_regs_v1; + pin_bank->gpio_type = GPIO_TYPE_V1; + } + + rt_dm_dev_set_name_auto(&rk_gpio.parent, "gpio"); + name = rt_dm_dev_get_name(&rk_gpio.parent); + + rt_hw_interrupt_install(pin_bank->irq, rk_pin_isr, pin_bank, name); + rt_hw_interrupt_umask(pin_bank->irq); + + rockchip_gpio_writel(pin_bank, 0xffffffffU, pin_bank->gpio_regs->int_mask); + rockchip_gpio_writel(pin_bank, 0xffffffffU, pin_bank->gpio_regs->port_eoi); + rockchip_gpio_writel(pin_bank, 0xffffffffU, pin_bank->gpio_regs->int_en); + + rt_spin_lock_init(&pin_bank->spinlock); + + pin_bank->parent.irqchip.irq = pin_bank->irq; + pin_bank->parent.irqchip.pin_range[0] = id * 32; + pin_bank->parent.irqchip.pin_range[1] = pin_bank->parent.irqchip.pin_range[0] + RK_PD7; + pin_bank->parent.ops = &rk_pin_ops; + pin_bank->parent.parent.user_data = pinctrl_dev; + pin_pic_init(&pin_bank->parent); + + rt_ofw_data(np) = &pin_bank->parent; + + if (!rk_gpio.init_ok) + { + rk_gpio.init_ok = RT_TRUE; + rk_gpio.pinctrl_dev = pinctrl_dev; + + rt_device_pin_register("gpio", &rk_pin_ops, pinctrl_dev); + } + + return err; + +_out_res: + if (pin_bank->reg_base) + { + rt_iounmap(pin_bank->reg_base); + } + if (pin_bank->clk) + { + rt_clk_disable_unprepare(pin_bank->clk); + rt_clk_put(pin_bank->clk); + } + if (pin_bank->db_clk) + { + rt_clk_disable_unprepare(pin_bank->db_clk); + rt_clk_put(pin_bank->db_clk); + } + + return err; +} + +static const struct rt_ofw_node_id rockchip_gpio_ofw_ids[] = +{ + { .compatible = "rockchip,gpio-bank" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_gpio_driver = +{ + .name = "rockchip-gpio", + .ids = rockchip_gpio_ofw_ids, + + .probe = rockchip_gpio_probe, +}; + +static int rockchip_gpio_register(void) +{ + int idx = 0; + struct rt_ofw_node *np = rt_ofw_find_node_by_path("/pinctrl"), *gpio_np; + + if (!np || !rt_ofw_data(np)) + { + goto _end; + } + + rt_platform_driver_register(&rockchip_gpio_driver); + + rt_ofw_foreach_available_child_node(np, gpio_np) + { + if (idx > RK_GPIO4) + { + rt_ofw_node_put(gpio_np); + + break; + } + + if (!rt_ofw_prop_read_bool(gpio_np, "compatible")) + { + continue; + } + + if (rt_ofw_data(gpio_np)) + { + continue; + } + + ++idx; + rt_platform_ofw_device_probe_child(gpio_np); + } + +_end: + rt_ofw_node_put(np); + + return 0; +} +INIT_SUBSYS_EXPORT(rockchip_gpio_register); diff --git a/components/drivers/pin/pin_dm.c b/components/drivers/pin/pin_dm.c new file mode 100644 index 000000000000..52dd47fd9753 --- /dev/null +++ b/components/drivers/pin/pin_dm.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 "pin_dm.h" + +static void pin_dm_irq_mask(struct rt_pic_irq *pirq) +{ + struct rt_device_pin *gpio = pirq->pic->priv_data; + + gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 0); +} + +static void pin_dm_irq_unmask(struct rt_pic_irq *pirq) +{ + struct rt_device_pin *gpio = pirq->pic->priv_data; + + gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 1); +} + +static rt_err_t pin_dm_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode) +{ + rt_uint8_t pin_mode; + struct rt_device_pin *gpio = pirq->pic->priv_data; + + switch (mode) + { + case RT_IRQ_MODE_EDGE_RISING: + pin_mode = PIN_IRQ_MODE_RISING; + break; + + case RT_IRQ_MODE_EDGE_FALLING: + pin_mode = PIN_IRQ_MODE_FALLING; + break; + + case RT_IRQ_MODE_EDGE_BOTH: + pin_mode = PIN_IRQ_MODE_RISING_FALLING; + break; + + case RT_IRQ_MODE_LEVEL_HIGH: + pin_mode = PIN_IRQ_MODE_HIGH_LEVEL; + break; + + case RT_IRQ_MODE_LEVEL_LOW: + pin_mode = PIN_IRQ_MODE_LOW_LEVEL; + break; + + default: + return -RT_ENOSYS; + } + + return gpio->ops->pin_irq_mode(&gpio->parent, pirq->hwirq, pin_mode); +} + +static int pin_dm_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq = -1; + struct rt_device_pin *gpio = pic->priv_data; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + irq = rt_pic_config_irq(pic, hwirq, hwirq); + + if (irq >= 0) + { + rt_pic_cascade(pirq, gpio->irqchip.irq); + rt_pic_irq_set_triger_mode(irq, mode); + } + } + + return irq; +} + +static rt_err_t pin_dm_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] & RT_IRQ_MODE_MASK; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static struct rt_pic_ops pin_dm_ops = +{ + .name = "GPIO", + .irq_enable = pin_dm_irq_mask, + .irq_disable = pin_dm_irq_unmask, + .irq_mask = pin_dm_irq_mask, + .irq_unmask = pin_dm_irq_unmask, + .irq_set_triger_mode = pin_dm_irq_set_triger_mode, + .irq_map = pin_dm_irq_map, + .irq_parse = pin_dm_irq_parse, +}; + +rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin) +{ + rt_err_t err; + + if (gpio) + { + struct rt_pin_irqchip *irqchip = &gpio->irqchip; + + if (pin >= irqchip->pin_range[0] && pin <= irqchip->pin_range[1]) + { + struct rt_pic_irq *pirq; + + pirq = rt_pic_find_irq(&irqchip->parent, pin - irqchip->pin_range[0]); + + if (pirq->irq >= 0) + { + err = rt_pic_handle_isr(pirq); + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t pin_pic_init(struct rt_device_pin *gpio) +{ + rt_err_t err; + + if (gpio) + { + struct rt_pin_irqchip *irqchip = &gpio->irqchip; + + if (irqchip->pin_range[0] >= 0 && irqchip->pin_range[1] >= irqchip->pin_range[0]) + { + struct rt_pic *pic = &irqchip->parent; + rt_size_t pin_nr = irqchip->pin_range[1] - irqchip->pin_range[0] + 1; + + pic->priv_data = gpio; + pic->ops = &pin_dm_ops; + /* Make sure the type of gpio for pic */ + gpio->parent.parent.type = RT_Object_Class_Device; + rt_pic_default_name(&irqchip->parent); + + err = rt_pic_linear_irq(pic, pin_nr); + rt_pic_user_extends(pic); + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value) +{ + rt_ssize_t res = -RT_ENOSYS; + + RT_ASSERT(dev != RT_NULL); + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + res = rt_ofw_get_named_pin(dev->ofw_node, propname, index, out_mode, out_value); + } + else + { + res = -RT_EINVAL; + } +#endif /* RT_USING_OFW */ + + return res; +} + +rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname) +{ + rt_ssize_t count = -RT_ENOSYS; + + RT_ASSERT(dev != RT_NULL); + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + count = rt_ofw_get_named_pin_count(dev->ofw_node, propname); + } + else + { + count = -RT_EINVAL; + } +#endif /* RT_USING_OFW */ + + return count; +} diff --git a/components/drivers/pin/pin_dm.h b/components/drivers/pin/pin_dm.h new file mode 100644 index 000000000000..b5146a2795c5 --- /dev/null +++ b/components/drivers/pin/pin_dm.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 __PIN_DM_H__ +#define __PIN_DM_H__ + +#include +#include +#include + +rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin); +rt_err_t pin_pic_init(struct rt_device_pin *gpio); + +#endif /* __PIN_DM_H__ */ diff --git a/components/drivers/pin/pin_ofw.c b/components/drivers/pin/pin_ofw.c new file mode 100644 index 000000000000..d76f54743328 --- /dev/null +++ b/components/drivers/pin/pin_ofw.c @@ -0,0 +1,125 @@ +/* + * 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 "pin_dm.h" + +rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value) +{ + rt_ssize_t pin; + rt_uint8_t mode; + rt_uint8_t value; + rt_uint32_t flags; + struct rt_ofw_node *pin_dev_np; + struct rt_ofw_cell_args pin_args; + struct rt_device_pin *pin_dev; + + if (!np && !propname && index < 0) + { + return -RT_EINVAL; + } + + pin = rt_ofw_parse_phandle_cells(np, propname, "#gpio-cells", index, &pin_args); + + if (pin < 0) + { + return pin; + } + + pin_dev_np = pin_args.data; + pin_dev = rt_ofw_data(pin_dev_np); + + if (!pin_dev) + { + pin = -RT_ERROR; + + goto _out_converts; + } + + value = PIN_LOW; + mode = PIN_MODE_OUTPUT; + + if (pin_dev->ops->pin_parse) + { + pin = pin_dev->ops->pin_parse(&pin_dev->parent, &pin_args, &flags); + } + else + { + /* + * We always assume that the args[0] is the pin number if driver not + * implemented `pin_parse`. + */ + pin = pin_args.args[0]; + + goto _out_converts; + } + + if (out_mode) + { + if (flags & PIN_OPEN_DRAIN) + { + mode = PIN_MODE_OUTPUT_OD; + } + + switch (flags & RT_GENMASK(6, 4)) + { + case PIN_PULL_UP: + mode = PIN_MODE_INPUT_PULLUP; + break; + + case PIN_PULL_DOWN: + mode = PIN_MODE_INPUT_PULLDOWN; + break; + + case PIN_PULL_DISABLE: + mode = PIN_MODE_INPUT; + break; + } + } + + if (out_value) + { + if (flags == (PIN_ACTIVE_HIGH | PIN_PUSH_PULL)) + { + value = PIN_HIGH; + } + else if (flags == (PIN_ACTIVE_LOW | PIN_PUSH_PULL)) + { + value = PIN_LOW; + } + } + +_out_converts: + rt_ofw_node_put(pin_dev_np); + + if (out_mode) + { + *out_mode = mode; + } + + if (out_value) + { + *out_value = value; + } + + return pin; +} + +rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname) +{ + if (!np || !propname) + { + return -RT_EINVAL; + } + + return rt_ofw_count_phandle_cells(np, propname, "#gpio-cells"); +} diff --git a/components/drivers/pinctrl/Kconfig b/components/drivers/pinctrl/Kconfig new file mode 100644 index 000000000000..c630228717f6 --- /dev/null +++ b/components/drivers/pinctrl/Kconfig @@ -0,0 +1,11 @@ +menuconfig RT_USING_PINCTRL + bool "Using Pin controllers device drivers" + depends on RT_USING_DM + depends on RT_USING_PIN + default n + +config RT_PINCTRL_ROCKCHIP + bool "Rockchip gpio and pinctrl driver" + depends on RT_USING_PINCTRL + select RT_MFD_SYSCON + default n diff --git a/components/drivers/pinctrl/SConscript b/components/drivers/pinctrl/SConscript new file mode 100644 index 000000000000..dc9a8ec059df --- /dev/null +++ b/components/drivers/pinctrl/SConscript @@ -0,0 +1,26 @@ +from building import * + +group = [] +objs = [] + +if not GetDepend(['RT_USING_PINCTRL']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = ['pinctrl.c'] + +if GetDepend(['RT_PINCTRL_ROCKCHIP']): + src += ['pinctrl-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/components/drivers/pinctrl/pinctrl-rockchip.c b/components/drivers/pinctrl/pinctrl-rockchip.c new file mode 100644 index 000000000000..7f9b6bd72992 --- /dev/null +++ b/components/drivers/pinctrl/pinctrl-rockchip.c @@ -0,0 +1,1258 @@ +/* + * 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 + +#define DBG_TAG "pinctrl.rockchip" +#define DBG_LVL DBG_INFO +#include + +#include "pinctrl-rockchip.h" + +/* + * Encode variants of iomux registers into a type variable + */ +#define IOMUX_GPIO_ONLY RT_BIT(0) +#define IOMUX_WIDTH_4BIT RT_BIT(1) +#define IOMUX_SOURCE_PMU RT_BIT(2) +#define IOMUX_UNROUTED RT_BIT(3) +#define IOMUX_WIDTH_3BIT RT_BIT(4) +#define IOMUX_WIDTH_2BIT RT_BIT(5) +#define IOMUX_L_SOURCE_PMU RT_BIT(6) + +#define PIN_BANK_IOMUX_FLAGS(ID, PINS, \ + LABEL, IOM0, IOM1, IOM2, IOM3) \ +{ \ + .bank_num = ID, \ + .nr_pins = PINS, \ + .name = LABEL, \ + .iomux = \ + { \ + { .type = IOM0, .offset = -1 }, \ + { .type = IOM1, .offset = -1 }, \ + { .type = IOM2, .offset = -1 }, \ + { .type = IOM3, .offset = -1 }, \ + }, \ +} + +#define PIN_BANK_MUX_ROUTE_FLAGS( \ + ID, PIN, FUNC, REG, VAL, FLAG) \ +{ \ + .bank_num = ID, \ + .pin = PIN, \ + .func = FUNC, \ + .route_offset = REG, \ + .route_val = VAL, \ + .route_location = FLAG, \ +} + +#define PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, \ + PINS, LABEL, IOM0, IOM1, IOM2, IOM3, \ + PULL0, PULL1, PULL2, PULL3) \ +{ \ + .bank_num = ID, \ + .nr_pins = PINS, \ + .name = LABEL, \ + .iomux = \ + { \ + { .type = IOM0, .offset = -1 }, \ + { .type = IOM1, .offset = -1 }, \ + { .type = IOM2, .offset = -1 }, \ + { .type = IOM3, .offset = -1 }, \ + }, \ + .pull_type[0] = PULL0, \ + .pull_type[1] = PULL1, \ + .pull_type[2] = PULL2, \ + .pull_type[3] = PULL3, \ +} + +#define RK_MUXROUTE_SAME(ID, PIN, FUNC, REG, VAL) \ + PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_SAME) + +#define RK_MUXROUTE_GRF(ID, PIN, FUNC, REG, VAL) \ + PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_GRF) + +#define RK_MUXROUTE_PMU(ID, PIN, FUNC, REG, VAL) \ + PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_PMU) + +#define PIN_BANK_FLAGS_IOMUX_PULL(ID, PIN, LABEL, M, P) \ + PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, PIN, LABEL, M, M, M, M, P, P, P, P) + +#define RK_RECALCED_DATA( \ + NUM, PIN, REG, BIT, MASK) \ +{ \ + .num = NUM, \ + .pin = PIN, \ + .reg = REG, \ + .bit = BIT, \ + .mask = MASK, \ +} + +static int rockchip_pull_list[PULL_TYPE_MAX][4] = +{ + { + PIN_CONFIG_BIAS_DISABLE, + PIN_CONFIG_BIAS_PULL_UP, + PIN_CONFIG_BIAS_PULL_DOWN, + PIN_CONFIG_BIAS_BUS_HOLD + }, + { + PIN_CONFIG_BIAS_DISABLE, + PIN_CONFIG_BIAS_PULL_DOWN, + PIN_CONFIG_BIAS_DISABLE, + PIN_CONFIG_BIAS_PULL_UP + }, +}; + +static int rockchip_translate_pull_value(int type, int pull) +{ + int res = -RT_EINVAL; + + for (int i = 0; i < RT_ARRAY_SIZE(rockchip_pull_list[type]); ++i) + { + if (rockchip_pull_list[type][i] == pull) + { + res = i; + break; + } + } + + return res; +} + +static void rockchip_translate_recalced_mux(struct rockchip_pin_bank *pin_bank, + int pin, int *reg, rt_uint8_t *bit, int *mask) +{ + int i; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + struct rockchip_pin_ctrl *pinctrl = drvdata->pinctrl; + struct rockchip_mux_recalced_data *data; + + for (i = 0; i < pinctrl->niomux_recalced; ++i) + { + data = &pinctrl->iomux_recalced[i]; + + if (data->num == pin_bank->bank_num && data->pin == pin) + { + break; + } + } + + if (i >= pinctrl->niomux_recalced) + { + return; + } + + *reg = data->reg; + *mask = data->mask; + *bit = data->bit; +} + +static struct rockchip_mux_route_data rk3308_mux_route_data[] = +{ + RK_MUXROUTE_SAME(0, RK_PC3, 1, 0x314, RT_BIT(16 + 0) | RT_BIT(0)), /* rtc_clk */ + RK_MUXROUTE_SAME(1, RK_PC6, 2, 0x314, RT_BIT(16 + 2) | RT_BIT(16 + 3)), /* uart2_rxm0 */ + RK_MUXROUTE_SAME(4, RK_PD2, 2, 0x314, RT_BIT(16 + 2) | RT_BIT(16 + 3) | RT_BIT(2)), /* uart2_rxm1 */ + RK_MUXROUTE_SAME(0, RK_PB7, 2, 0x608, RT_BIT(16 + 8) | RT_BIT(16 + 9)), /* i2c3_sdam0 */ + RK_MUXROUTE_SAME(3, RK_PB4, 2, 0x608, RT_BIT(16 + 8) | RT_BIT(16 + 9) | RT_BIT(8)), /* i2c3_sdam1 */ + RK_MUXROUTE_SAME(2, RK_PA0, 3, 0x608, RT_BIT(16 + 8) | RT_BIT(16 + 9) | RT_BIT(9)), /* i2c3_sdam2 */ + RK_MUXROUTE_SAME(1, RK_PA3, 2, 0x308, RT_BIT(16 + 3)), /* i2s-8ch-1-sclktxm0 */ + RK_MUXROUTE_SAME(1, RK_PA4, 2, 0x308, RT_BIT(16 + 3)), /* i2s-8ch-1-sclkrxm0 */ + RK_MUXROUTE_SAME(1, RK_PB5, 2, 0x308, RT_BIT(16 + 3) | RT_BIT(3)), /* i2s-8ch-1-sclktxm1 */ + RK_MUXROUTE_SAME(1, RK_PB6, 2, 0x308, RT_BIT(16 + 3) | RT_BIT(3)), /* i2s-8ch-1-sclkrxm1 */ + RK_MUXROUTE_SAME(1, RK_PA4, 3, 0x308, RT_BIT(16 + 12) | RT_BIT(16 + 13)), /* pdm-clkm0 */ + RK_MUXROUTE_SAME(1, RK_PB6, 4, 0x308, RT_BIT(16 + 12) | RT_BIT(16 + 13) | RT_BIT(12)), /* pdm-clkm1 */ + RK_MUXROUTE_SAME(2, RK_PA6, 2, 0x308, RT_BIT(16 + 12) | RT_BIT(16 + 13) | RT_BIT(13)), /* pdm-clkm2 */ + RK_MUXROUTE_SAME(2, RK_PA4, 3, 0x600, RT_BIT(16 + 2) | RT_BIT(2)), /* pdm-clkm-m2 */ + RK_MUXROUTE_SAME(3, RK_PB2, 3, 0x314, RT_BIT(16 + 9)), /* spi1_miso */ + RK_MUXROUTE_SAME(2, RK_PA4, 2, 0x314, RT_BIT(16 + 9) | RT_BIT(9)), /* spi1_miso_m1 */ + RK_MUXROUTE_SAME(0, RK_PB3, 3, 0x314, RT_BIT(16 + 10) | RT_BIT(16 + 11)), /* owire_m0 */ + RK_MUXROUTE_SAME(1, RK_PC6, 7, 0x314, RT_BIT(16 + 10) | RT_BIT(16 + 11) | RT_BIT(10)), /* owire_m1 */ + RK_MUXROUTE_SAME(2, RK_PA2, 5, 0x314, RT_BIT(16 + 10) | RT_BIT(16 + 11) | RT_BIT(11)), /* owire_m2 */ + RK_MUXROUTE_SAME(0, RK_PB3, 2, 0x314, RT_BIT(16 + 12) | RT_BIT(16 + 13)), /* can_rxd_m0 */ + RK_MUXROUTE_SAME(1, RK_PC6, 5, 0x314, RT_BIT(16 + 12) | RT_BIT(16 + 13) | RT_BIT(12)), /* can_rxd_m1 */ + RK_MUXROUTE_SAME(2, RK_PA2, 4, 0x314, RT_BIT(16 + 12) | RT_BIT(16 + 13) | RT_BIT(13)), /* can_rxd_m2 */ + RK_MUXROUTE_SAME(1, RK_PC4, 3, 0x314, RT_BIT(16 + 14)), /* mac_rxd0_m0 */ + RK_MUXROUTE_SAME(4, RK_PA2, 2, 0x314, RT_BIT(16 + 14) | RT_BIT(14)), /* mac_rxd0_m1 */ + RK_MUXROUTE_SAME(3, RK_PB4, 4, 0x314, RT_BIT(16 + 15)), /* uart3_rx */ + RK_MUXROUTE_SAME(0, RK_PC1, 3, 0x314, RT_BIT(16 + 15) | RT_BIT(15)), /* uart3_rx_m1 */ +}; + +static struct rockchip_mux_recalced_data rk3308_mux_recalced_data[] = +{ + RK_RECALCED_DATA(1, 14, 0x28, 12, 0xf), /* gpio1b6_sel */ + RK_RECALCED_DATA(1, 15, 0x2c, 0, 0x3), /* gpio1b7_sel */ + RK_RECALCED_DATA(1, 18, 0x30, 4, 0xf), /* gpio1c2_sel */ + RK_RECALCED_DATA(1, 19, 0x30, 8, 0xf), /* gpio1c3_sel */ + RK_RECALCED_DATA(1, 20, 0x30, 12, 0xf), /* gpio1c4_sel */ + RK_RECALCED_DATA(1, 21, 0x34, 0, 0xf), /* gpio1c5_sel */ + RK_RECALCED_DATA(1, 22, 0x34, 4, 0xf), /* gpio1c6_sel */ + RK_RECALCED_DATA(1, 23, 0x34, 8, 0xf), /* gpio1c7_sel */ + RK_RECALCED_DATA(2, 2, 0x40, 4, 0x3), /* gpio2a2_sel */ + RK_RECALCED_DATA(2, 3, 0x40, 6, 0x3), /* gpio2a3_sel */ + RK_RECALCED_DATA(2, 16, 0x50, 0, 0x3), /* gpio2c0_sel */ + RK_RECALCED_DATA(3, 10, 0x68, 4, 0x3), /* gpio3b2_sel */ + RK_RECALCED_DATA(3, 11, 0x68, 6, 0x3), /* gpio3b3_sel */ + RK_RECALCED_DATA(3, 12, 0x68, 8, 0xf), /* gpio3b4_sel */ + RK_RECALCED_DATA(3, 13, 0x68, 12, 0xf), /* gpio3b5_sel */ +}; + +static rt_err_t rk3308_set_mux(struct rockchip_pin_bank *pin_bank, int pin, int mux) +{ + rt_uint8_t bit; + rt_uint32_t data; + int iomux_num = (pin / 8), reg, mask; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if ((pin_bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)) + { + regmap = drvdata->regmap_pmu; + } + else + { + regmap = drvdata->regmap_base; + } + + reg = pin_bank->iomux[iomux_num].offset; + if (pin_bank->iomux[iomux_num].type & IOMUX_WIDTH_4BIT) + { + if ((pin % 8) >= 4) + { + reg += 0x4; + } + bit = (pin % 4) * 4; + mask = 0xf; + } + else + { + bit = (pin % 8) * 2; + mask = 0x3; + } + + if (pin_bank->recalced_mask & RT_BIT(pin)) + { + rockchip_translate_recalced_mux(pin_bank, pin, ®, &bit, &mask); + } + + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3308_PULL_OFFSET 0xa0 +#define RK3308_PULL_BITS_PER_PIN 2 +#define RK3308_PULL_PINS_PER_REG 8 +#define RK3308_PULL_BANK_STRIDE 16 + +static rt_err_t rk3308_set_pull(struct rockchip_pin_bank *pin_bank, int pin, int pull) +{ + int reg, pull_value; + rt_uint32_t data; + rt_uint8_t bit, type; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + { + return -RT_ENOSYS; + } + + regmap = drvdata->regmap_base; + reg = RK3308_PULL_OFFSET; + reg += pin_bank->bank_num * RK3308_PULL_BANK_STRIDE; + reg += ((pin / RK3308_PULL_PINS_PER_REG) * 4); + + bit = (pin % RK3308_PULL_PINS_PER_REG); + bit *= RK3308_PULL_BITS_PER_PIN; + + type = pin_bank->pull_type[pin / 8]; + pull_value = rockchip_translate_pull_value(type, pull); + + if (pull_value < 0) + { + LOG_E("Not supported pull = %d, fixup the code or firmware", pull); + + return pull_value; + } + + /* enable the write to the equivalent lower bits */ + data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16); + data |= (pull_value << bit); + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3308_DRV_GRF_OFFSET 0x100 +#define RK3308_DRV_BITS_PER_PIN 2 +#define RK3308_DRV_PINS_PER_REG 8 +#define RK3308_DRV_BANK_STRIDE 16 + +static rt_err_t rk3308_set_drive(struct rockchip_pin_bank *pin_bank, int pin, int strength) +{ + int reg; + rt_uint8_t bit; + rt_uint32_t data; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + regmap = drvdata->regmap_base; + reg = RK3308_DRV_GRF_OFFSET; + reg += pin_bank->bank_num * RK3308_DRV_BANK_STRIDE; + reg += ((pin / RK3308_DRV_PINS_PER_REG) * 4); + + bit = (pin % RK3308_DRV_PINS_PER_REG); + bit *= RK3308_DRV_BITS_PER_PIN; + + /* enable the write to the equivalent lower bits */ + data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16); + data |= (strength << bit); + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3308_SCHMITT_PINS_PER_REG 8 +#define RK3308_SCHMITT_BANK_STRIDE 16 +#define RK3308_SCHMITT_GRF_OFFSET 0x1a0 + +static rt_err_t rk3308_set_schmitt(struct rockchip_pin_bank *pin_bank, int pin, int enable) +{ + int reg; + rt_uint8_t bit; + rt_uint32_t data; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + regmap = drvdata->regmap_base; + reg = RK3308_SCHMITT_GRF_OFFSET; + + reg += pin_bank->bank_num * RK3308_SCHMITT_BANK_STRIDE; + reg += ((pin / RK3308_SCHMITT_PINS_PER_REG) * 4); + bit = pin % RK3308_SCHMITT_PINS_PER_REG; + + /* enable the write to the equivalent lower bits */ + data = RT_BIT(bit + 16) | (enable << bit); + + return rt_syscon_write(regmap, reg, data); +} + +static struct rockchip_pin_bank rk3308_pin_banks[] = +{ + PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT), + PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT), + PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT), + PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT), + PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT, IOMUX_WIDTH_2BIT), +}; + +static struct rockchip_pin_ctrl rk3308_pin_ctrl = +{ + .pin_banks = rk3308_pin_banks, + .banks_nr = RT_ARRAY_SIZE(rk3308_pin_banks), + .label = "RK3308-GPIO", + .type = RK3308, + .grf_mux_offset = 0x0, + .grf_drv_offset = RK3308_DRV_GRF_OFFSET, + .iomux_recalced = rk3308_mux_recalced_data, + .niomux_recalced = RT_ARRAY_SIZE(rk3308_mux_recalced_data), + .iomux_routes = rk3308_mux_route_data, + .niomux_routes = RT_ARRAY_SIZE(rk3308_mux_route_data), + .set_mux = rk3308_set_mux, + .set_pull = rk3308_set_pull, + .set_drive = rk3308_set_drive, + .set_schmitt = rk3308_set_schmitt, +}; + +static rt_err_t rk3568_set_mux(struct rockchip_pin_bank *pin_bank, int pin, int mux) +{ + rt_uint8_t bit; + rt_uint32_t data; + int iomux_num = (pin / 8), reg, mask; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if ((pin_bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)) + { + regmap = drvdata->regmap_pmu; + } + else + { + regmap = drvdata->regmap_base; + } + + reg = pin_bank->iomux[iomux_num].offset; + if ((pin % 8) >= 4) + { + reg += 0x4; + } + bit = (pin % 4) * 4; + mask = 0xf; + + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3568_PULL_PMU_OFFSET 0x20 +#define RK3568_PULL_GRF_OFFSET 0x80 +#define RK3568_PULL_BITS_PER_PIN 2 +#define RK3568_PULL_PINS_PER_REG 8 +#define RK3568_PULL_BANK_STRIDE 0x10 + +static rt_err_t rk3568_set_pull(struct rockchip_pin_bank *pin_bank, int pin, int pull) +{ + int reg, pull_value; + rt_uint32_t data; + rt_uint8_t bit, type; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + { + return -RT_ENOSYS; + } + + if (pin_bank->bank_num == 0) + { + regmap = drvdata->regmap_pmu; + reg = RK3568_PULL_PMU_OFFSET; + reg += pin_bank->bank_num * RK3568_PULL_BANK_STRIDE; + } + else + { + regmap = drvdata->regmap_base; + reg = RK3568_PULL_GRF_OFFSET; + reg += (pin_bank->bank_num - 1) * RK3568_PULL_BANK_STRIDE; + } + + reg += ((pin / RK3568_PULL_PINS_PER_REG) * 4); + bit = (pin % RK3568_PULL_PINS_PER_REG); + bit *= RK3568_PULL_BITS_PER_PIN; + + type = pin_bank->pull_type[pin / 8]; + pull_value = rockchip_translate_pull_value(type, pull); + + /* + * pull-up being 1 for everything except the GPIO0_D3-D6, + * where that pull up value becomes 3 + */ + if (pin_bank->bank_num == 0 && pin >= RK_GPIO0_D3 && pin <= RK_GPIO0_D6) + { + if (pull_value == 1) + { + pull_value = 3; + } + } + + if (pull_value < 0) + { + LOG_E("Not supported pull = %d, fixup the code or firmware", pull); + + return pull_value; + } + + /* enable the write to the equivalent lower bits */ + data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16); + data |= (pull_value << bit); + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3568_DRV_PMU_OFFSET 0x70 +#define RK3568_DRV_GRF_OFFSET 0x200 +#define RK3568_DRV_BITS_PER_PIN 8 +#define RK3568_DRV_PINS_PER_REG 2 +#define RK3568_DRV_BANK_STRIDE 0x40 + +#define RK3568_GRF_GPIO1C5_DS 0x840 +#define RK3568_GRF_GPIO2A2_DS 0x844 +#define RK3568_GRF_GPIO2B0_DS 0x848 +#define RK3568_GRF_GPIO3A0_DS 0x84c +#define RK3568_GRF_GPIO3A6_DS 0x850 +#define RK3568_GRF_GPIO4A0_DS 0x854 + +static rt_err_t rk3568_set_drive(struct rockchip_pin_bank *pin_bank, int pin, int strength) +{ + rt_err_t err; + rt_uint8_t bit; + rt_uint32_t data; + int reg, drv = (1 << (strength + 1)) - 1; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if (pin_bank->bank_num == 0) + { + regmap = drvdata->regmap_pmu; + reg = RK3568_DRV_PMU_OFFSET; + } + else + { + regmap = drvdata->regmap_base; + reg = RK3568_DRV_GRF_OFFSET; + reg += (pin_bank->bank_num - 1) * RK3568_DRV_BANK_STRIDE; + } + + reg += ((pin / RK3568_DRV_PINS_PER_REG) * 4); + bit = (pin % RK3568_DRV_PINS_PER_REG); + bit *= RK3568_DRV_BITS_PER_PIN; + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3568_DRV_BITS_PER_PIN) - 1) << (bit + 16); + data |= (drv << bit); + + if ((err = rt_syscon_write(regmap, reg, data))) + { + return err; + } + + if (pin_bank->bank_num == RK_GPIO1 && pin == RK_PC5) + { + reg = RK3568_GRF_GPIO1C5_DS; + } + else if (pin_bank->bank_num == RK_GPIO2 && pin == RK_PA2) + { + reg = RK3568_GRF_GPIO2A2_DS; + } + else if (pin_bank->bank_num == RK_GPIO2 && pin == RK_PB0) + { + reg = RK3568_GRF_GPIO2B0_DS; + } + else if (pin_bank->bank_num == RK_GPIO3 && pin == RK_PA0) + { + reg = RK3568_GRF_GPIO3A0_DS; + } + else if (pin_bank->bank_num == RK_GPIO3 && pin == RK_PA6) + { + reg = RK3568_GRF_GPIO3A6_DS; + } + else if (pin_bank->bank_num == RK_GPIO4 && pin == RK_PA0) + { + reg = RK3568_GRF_GPIO4A0_DS; + } + else + { + return RT_EOK; + } + + data = ((1 << RK3568_DRV_BITS_PER_PIN) - 1) << 16; + data |= drv; + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3568_SCHMITT_BITS_PER_PIN 2 +#define RK3568_SCHMITT_PINS_PER_REG 8 +#define RK3568_SCHMITT_BANK_STRIDE 0x10 +#define RK3568_SCHMITT_GRF_OFFSET 0xc0 +#define RK3568_SCHMITT_PMUGRF_OFFSET 0x30 + +static rt_err_t rk3568_set_schmitt(struct rockchip_pin_bank *pin_bank, int pin, int enable) +{ + int reg; + rt_uint8_t bit; + rt_uint32_t data; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if (pin_bank->bank_num == 0) + { + regmap = drvdata->regmap_pmu; + reg = RK3568_SCHMITT_PMUGRF_OFFSET; + } + else + { + regmap = drvdata->regmap_base; + reg = RK3568_SCHMITT_GRF_OFFSET; + reg += (pin_bank->bank_num - 1) * RK3568_SCHMITT_BANK_STRIDE; + } + + reg += ((pin / RK3568_SCHMITT_PINS_PER_REG) * 4); + bit = pin % RK3568_SCHMITT_PINS_PER_REG; + bit *= RK3568_SCHMITT_BITS_PER_PIN; + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3568_SCHMITT_BITS_PER_PIN) - 1) << (bit + 16); + data |= (enable << bit); + + return rt_syscon_write(regmap, reg, data); +} + +static struct rockchip_pin_bank rk3568_pin_banks[] = +{ + PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT, IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT, + IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT, IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT), + PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT), + PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT), + PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT), + PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT, IOMUX_WIDTH_4BIT), +}; + +static struct rockchip_pin_ctrl rk3568_pin_ctrl = +{ + .pin_banks = rk3568_pin_banks, + .banks_nr = RT_ARRAY_SIZE(rk3568_pin_banks), + .label = "RK3568-GPIO", + .type = RK3568, + .grf_mux_offset = 0x0, + .pmu_mux_offset = 0x0, + .grf_drv_offset = RK3568_DRV_GRF_OFFSET, + .pmu_drv_offset = RK3568_DRV_PMU_OFFSET, + .set_mux = rk3568_set_mux, + .set_pull = rk3568_set_pull, + .set_drive = rk3568_set_drive, + .set_schmitt = rk3568_set_schmitt, +}; + +static rt_err_t rk3588_set_mux(struct rockchip_pin_bank *pin_bank, int pin, int mux) +{ + rt_err_t err; + rt_uint8_t bit; + rt_uint32_t data; + int iomux_num = (pin / 8), reg, mask; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + regmap = drvdata->regmap_base; + reg = pin_bank->iomux[iomux_num].offset; + if ((pin % 8) >= 4) + { + reg += 0x4; + } + bit = (pin % 4) * 4; + mask = 0xf; + + if (pin_bank->bank_num == 0) + { + if ((pin >= RK_PB4) && (pin <= RK_PD7)) + { + if (mux < 8) + { + /* PMU2_IOC_BASE */ + reg += 0x4000 - 0xc; + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + err = rt_syscon_write(regmap, reg, data); + } + else + { + rt_uint32_t reg0 = 0; + + /* PMU2_IOC_BASE */ + reg0 = reg + 0x4000 - 0xc; + data = (mask << (bit + 16)); + data |= 8 << bit; + err = rt_syscon_write(regmap, reg0, data); + + /* BUS_IOC_BASE */ + reg0 = reg + 0x8000; + data = (mask << (bit + 16)); + data |= mux << bit; + rt_syscon_write(regmap, reg0, data); + } + } + else + { + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + err = rt_syscon_write(regmap, reg, data); + } + + return err; + } + else if (pin_bank->bank_num > 0) + { + /* BUS_IOC_BASE */ + reg += 0x8000; + } + + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3588_PMU1_IOC_REG 0x0000 +#define RK3588_PMU2_IOC_REG 0x4000 +#define RK3588_BUS_IOC_REG 0x8000 +#define RK3588_VCCIO1_4_IOC_REG 0x9000 +#define RK3588_VCCIO3_5_IOC_REG 0xa000 +#define RK3588_VCCIO2_IOC_REG 0xb000 +#define RK3588_VCCIO6_IOC_REG 0xc000 +#define RK3588_EMMC_IOC_REG 0xd000 + +#define RK3588_PULL_BITS_PER_PIN 2 +#define RK3588_PULL_PINS_PER_REG 8 + +static const rt_uint32_t rk3588_pull_regs[][2] = +{ + { RK_GPIO0_A0, RK3588_PMU1_IOC_REG + 0x0020 }, + { RK_GPIO0_B0, RK3588_PMU1_IOC_REG + 0x0024 }, + { RK_GPIO0_B5, RK3588_PMU2_IOC_REG + 0x0028 }, + { RK_GPIO0_C0, RK3588_PMU2_IOC_REG + 0x002c }, + { RK_GPIO0_D0, RK3588_PMU2_IOC_REG + 0x0030 }, + { RK_GPIO1_A0, RK3588_VCCIO1_4_IOC_REG + 0x0110 }, + { RK_GPIO1_B0, RK3588_VCCIO1_4_IOC_REG + 0x0114 }, + { RK_GPIO1_C0, RK3588_VCCIO1_4_IOC_REG + 0x0118 }, + { RK_GPIO1_D0, RK3588_VCCIO1_4_IOC_REG + 0x011c }, + { RK_GPIO2_A0, RK3588_EMMC_IOC_REG + 0x0120 }, + { RK_GPIO2_A6, RK3588_VCCIO3_5_IOC_REG + 0x0120 }, + { RK_GPIO2_B0, RK3588_VCCIO3_5_IOC_REG + 0x0124 }, + { RK_GPIO2_C0, RK3588_VCCIO3_5_IOC_REG + 0x0128 }, + { RK_GPIO2_D0, RK3588_EMMC_IOC_REG + 0x012c }, + { RK_GPIO3_A0, RK3588_VCCIO3_5_IOC_REG + 0x0130 }, + { RK_GPIO3_B0, RK3588_VCCIO3_5_IOC_REG + 0x0134 }, + { RK_GPIO3_C0, RK3588_VCCIO3_5_IOC_REG + 0x0138 }, + { RK_GPIO3_D0, RK3588_VCCIO3_5_IOC_REG + 0x013c }, + { RK_GPIO4_A0, RK3588_VCCIO6_IOC_REG + 0x0140 }, + { RK_GPIO4_B0, RK3588_VCCIO6_IOC_REG + 0x0144 }, + { RK_GPIO4_C0, RK3588_VCCIO6_IOC_REG + 0x0148 }, + { RK_GPIO4_C2, RK3588_VCCIO3_5_IOC_REG + 0x0148 }, + { RK_GPIO4_D0, RK3588_VCCIO2_IOC_REG + 0x014c }, +}; + +static rt_err_t rk3588_set_pull(struct rockchip_pin_bank *pin_bank, int pin, int pull) +{ + int reg, pull_value; + rt_uint32_t data; + rt_uint8_t bit, type; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + { + return -RT_ENOSYS; + } + + for (int i = RT_ARRAY_SIZE(rk3588_pull_regs) - 1; i >= 0; --i) + { + if (pin >= rk3588_pull_regs[i][0]) + { + reg = rk3588_pull_regs[i][1]; + bit = ((pin % 32) % RK3588_PULL_PINS_PER_REG) * RK3588_PULL_BITS_PER_PIN; + + goto _find; + } + } + + return -RT_EINVAL; + +_find: + regmap = drvdata->regmap_base; + + type = pin_bank->pull_type[pin / 8]; + pull_value = rockchip_translate_pull_value(type, pull); + + if (pull_value < 0) + { + LOG_E("Not supported pull = %d, fixup the code or firmware", pull); + + return pull_value; + } + + /* enable the write to the equivalent lower bits */ + data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16); + data |= (pull_value << bit); + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3588_DRV_BITS_PER_PIN 4 +#define RK3588_DRV_PINS_PER_REG 4 + +static const rt_uint32_t rk3588_drive_regs[][2] = +{ + { RK_GPIO0_A0, RK3588_PMU1_IOC_REG + 0x0010 }, + { RK_GPIO0_A4, RK3588_PMU1_IOC_REG + 0x0014 }, + { RK_GPIO0_B0, RK3588_PMU1_IOC_REG + 0x0018 }, + { RK_GPIO0_B4, RK3588_PMU2_IOC_REG + 0x0014 }, + { RK_GPIO0_C0, RK3588_PMU2_IOC_REG + 0x0018 }, + { RK_GPIO0_C4, RK3588_PMU2_IOC_REG + 0x001c }, + { RK_GPIO0_D0, RK3588_PMU2_IOC_REG + 0x0020 }, + { RK_GPIO0_D4, RK3588_PMU2_IOC_REG + 0x0024 }, + { RK_GPIO1_A0, RK3588_VCCIO1_4_IOC_REG + 0x0020 }, + { RK_GPIO1_A4, RK3588_VCCIO1_4_IOC_REG + 0x0024 }, + { RK_GPIO1_B0, RK3588_VCCIO1_4_IOC_REG + 0x0028 }, + { RK_GPIO1_B4, RK3588_VCCIO1_4_IOC_REG + 0x002c }, + { RK_GPIO1_C0, RK3588_VCCIO1_4_IOC_REG + 0x0030 }, + { RK_GPIO1_C4, RK3588_VCCIO1_4_IOC_REG + 0x0034 }, + { RK_GPIO1_D0, RK3588_VCCIO1_4_IOC_REG + 0x0038 }, + { RK_GPIO1_D4, RK3588_VCCIO1_4_IOC_REG + 0x003c }, + { RK_GPIO2_A0, RK3588_EMMC_IOC_REG + 0x0040 }, + { RK_GPIO2_A4, RK3588_VCCIO3_5_IOC_REG + 0x0044 }, + { RK_GPIO2_B0, RK3588_VCCIO3_5_IOC_REG + 0x0048 }, + { RK_GPIO2_B4, RK3588_VCCIO3_5_IOC_REG + 0x004c }, + { RK_GPIO2_C0, RK3588_VCCIO3_5_IOC_REG + 0x0050 }, + { RK_GPIO2_C4, RK3588_VCCIO3_5_IOC_REG + 0x0054 }, + { RK_GPIO2_D0, RK3588_EMMC_IOC_REG + 0x0058 }, + { RK_GPIO2_D4, RK3588_EMMC_IOC_REG + 0x005c }, + { RK_GPIO3_A0, RK3588_VCCIO3_5_IOC_REG + 0x0060 }, + { RK_GPIO3_A4, RK3588_VCCIO3_5_IOC_REG + 0x0064 }, + { RK_GPIO3_B0, RK3588_VCCIO3_5_IOC_REG + 0x0068 }, + { RK_GPIO3_B4, RK3588_VCCIO3_5_IOC_REG + 0x006c }, + { RK_GPIO3_C0, RK3588_VCCIO3_5_IOC_REG + 0x0070 }, + { RK_GPIO3_C4, RK3588_VCCIO3_5_IOC_REG + 0x0074 }, + { RK_GPIO3_D0, RK3588_VCCIO3_5_IOC_REG + 0x0078 }, + { RK_GPIO3_D4, RK3588_VCCIO3_5_IOC_REG + 0x007c }, + { RK_GPIO4_A0, RK3588_VCCIO6_IOC_REG + 0x0080 }, + { RK_GPIO4_A4, RK3588_VCCIO6_IOC_REG + 0x0084 }, + { RK_GPIO4_B0, RK3588_VCCIO6_IOC_REG + 0x0088 }, + { RK_GPIO4_B4, RK3588_VCCIO6_IOC_REG + 0x008c }, + { RK_GPIO4_C0, RK3588_VCCIO6_IOC_REG + 0x0090 }, + { RK_GPIO4_C2, RK3588_VCCIO3_5_IOC_REG + 0x0090 }, + { RK_GPIO4_C4, RK3588_VCCIO3_5_IOC_REG + 0x0094 }, + { RK_GPIO4_D0, RK3588_VCCIO2_IOC_REG + 0x0098 }, + { RK_GPIO4_D4, RK3588_VCCIO2_IOC_REG + 0x009c }, +}; + +static rt_err_t rk3588_set_drive(struct rockchip_pin_bank *pin_bank, int pin, int strength) +{ + int reg; + rt_uint8_t bit; + rt_uint32_t data; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + for (int i = RT_ARRAY_SIZE(rk3588_drive_regs) - 1; i >= 0; --i) + { + if (pin >= rk3588_drive_regs[i][0]) + { + reg = rk3588_drive_regs[i][1]; + bit = ((pin % 32) % RK3588_DRV_PINS_PER_REG) * RK3588_DRV_BITS_PER_PIN; + + goto _find; + } + } + + return -RT_EINVAL; + +_find: + regmap = drvdata->regmap_base; + + /* enable the write to the equivalent lower bits */ + data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16); + data |= (strength << bit); + + return rt_syscon_write(regmap, reg, data); +} + +#define RK3588_SMT_BITS_PER_PIN 1 +#define RK3588_SMT_PINS_PER_REG 8 + +static const rt_uint32_t rk3588_schmitt_regs[][2] = +{ + { RK_GPIO0_A0, RK3588_PMU1_IOC_REG + 0x0030 }, + { RK_GPIO0_B0, RK3588_PMU1_IOC_REG + 0x0034 }, + { RK_GPIO0_B5, RK3588_PMU2_IOC_REG + 0x0040 }, + { RK_GPIO0_C0, RK3588_PMU2_IOC_REG + 0x0044 }, + { RK_GPIO0_D0, RK3588_PMU2_IOC_REG + 0x0048 }, + { RK_GPIO1_A0, RK3588_VCCIO1_4_IOC_REG + 0x0210 }, + { RK_GPIO1_B0, RK3588_VCCIO1_4_IOC_REG + 0x0214 }, + { RK_GPIO1_C0, RK3588_VCCIO1_4_IOC_REG + 0x0218 }, + { RK_GPIO1_D0, RK3588_VCCIO1_4_IOC_REG + 0x021c }, + { RK_GPIO2_A0, RK3588_EMMC_IOC_REG + 0x0220 }, + { RK_GPIO2_A6, RK3588_VCCIO3_5_IOC_REG + 0x0220 }, + { RK_GPIO2_B0, RK3588_VCCIO3_5_IOC_REG + 0x0224 }, + { RK_GPIO2_C0, RK3588_VCCIO3_5_IOC_REG + 0x0228 }, + { RK_GPIO2_D0, RK3588_EMMC_IOC_REG + 0x022c }, + { RK_GPIO3_A0, RK3588_VCCIO3_5_IOC_REG + 0x0230 }, + { RK_GPIO3_B0, RK3588_VCCIO3_5_IOC_REG + 0x0234 }, + { RK_GPIO3_C0, RK3588_VCCIO3_5_IOC_REG + 0x0238 }, + { RK_GPIO3_D0, RK3588_VCCIO3_5_IOC_REG + 0x023c }, + { RK_GPIO4_A0, RK3588_VCCIO6_IOC_REG + 0x0240 }, + { RK_GPIO4_B0, RK3588_VCCIO6_IOC_REG + 0x0244 }, + { RK_GPIO4_C0, RK3588_VCCIO6_IOC_REG + 0x0248 }, + { RK_GPIO4_C2, RK3588_VCCIO3_5_IOC_REG + 0x0248 }, + { RK_GPIO4_D0, RK3588_VCCIO2_IOC_REG + 0x024c }, +}; + +static rt_err_t rk3588_set_schmitt(struct rockchip_pin_bank *pin_bank, int pin, int enable) +{ + int reg; + rt_uint8_t bit; + rt_uint32_t data; + struct rt_syscon *regmap; + struct rockchip_pin_data *drvdata = pin_bank->drvdata; + + for (int i = RT_ARRAY_SIZE(rk3588_schmitt_regs) - 1; i >= 0; --i) + { + if (pin >= rk3588_schmitt_regs[i][0]) + { + reg = rk3588_schmitt_regs[i][1]; + bit = ((pin % 32) % RK3588_SMT_PINS_PER_REG) * RK3588_SMT_BITS_PER_PIN; + + goto _find; + } + } + + return -RT_EINVAL; + +_find: + regmap = drvdata->regmap_base; + + /* enable the write to the equivalent lower bits */ + data = RT_BIT(bit + 16) | (enable << bit); + + return rt_syscon_write(regmap, reg, data); +} + +static struct rockchip_pin_bank rk3588_pin_banks[] = +{ + PIN_BANK_FLAGS_IOMUX_PULL(0, 32, "gpio0", IOMUX_WIDTH_4BIT, PULL_TYPE_IO_1V8_ONLY), + PIN_BANK_FLAGS_IOMUX_PULL(1, 32, "gpio1", IOMUX_WIDTH_4BIT, PULL_TYPE_IO_1V8_ONLY), + PIN_BANK_FLAGS_IOMUX_PULL(2, 32, "gpio2", IOMUX_WIDTH_4BIT, PULL_TYPE_IO_1V8_ONLY), + PIN_BANK_FLAGS_IOMUX_PULL(3, 32, "gpio3", IOMUX_WIDTH_4BIT, PULL_TYPE_IO_1V8_ONLY), + PIN_BANK_FLAGS_IOMUX_PULL(4, 32, "gpio4", IOMUX_WIDTH_4BIT, PULL_TYPE_IO_1V8_ONLY), +}; + +static struct rockchip_pin_ctrl rk3588_pin_ctrl = +{ + .pin_banks = rk3588_pin_banks, + .banks_nr = RT_ARRAY_SIZE(rk3588_pin_banks), + .label = "RK3588-GPIO", + .type = RK3588, + .set_mux = rk3588_set_mux, + .set_pull = rk3588_set_pull, + .set_drive = rk3588_set_drive, + .set_schmitt = rk3588_set_schmitt, +}; + +static const struct rt_pin_ctrl_conf_params rockchip_conf_params[] = +{ + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, +}; + +static int rockchip_pinconf_prop_name_to_param(const char *propname, rt_uint32_t *default_value) +{ + const struct rt_pin_ctrl_conf_params *params = rockchip_conf_params; + + for (int i = 0; i < RT_ARRAY_SIZE(rockchip_conf_params); ++i, ++params) + { + if (!rt_strcmp(params->propname, propname)) + { + *default_value = params->default_value; + + return params->param; + } + } + + return -RT_ENOSYS; +} + +static rt_err_t rockchip_pinconf_pull_apply(struct rockchip_pin_ctrl *pinctrl, + struct rockchip_pin_bank *pin_bank, rt_uint32_t pin, rt_uint32_t param, rt_uint32_t arg) +{ + rt_err_t err = RT_EOK; + + switch (param) + { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_BUS_HOLD: + if (pinctrl->set_pull) + { + err = pinctrl->set_pull(pin_bank, pin, param); + } + else + { + err = -RT_ENOSYS; + } + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + if (pinctrl->set_drive) + { + err = pinctrl->set_drive(pin_bank, pin, arg); + } + else + { + err = -RT_ENOSYS; + } + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (pinctrl->set_schmitt) + { + err = pinctrl->set_schmitt(pin_bank, pin, arg); + } + else + { + err = -RT_ENOSYS; + } + break; + + default: + break; + } + + return err; +} + +static rt_err_t rockchip_pinctrl_confs_apply(struct rt_device *device, void *fw_conf_np) +{ + rt_err_t err = RT_EOK; + const fdt32_t *cell; + int pin, function, param; + rt_uint32_t value, default_value, arg; + struct rt_ofw_prop *prop, *pin_prop; + struct rt_ofw_node *pull_np, *conf_np = fw_conf_np; + struct rockchip_pin_ctrl *pinctrl; + struct rockchip_pin_bank *pin_bank; + struct rockchip_pinctrl_device *pinctrl_dev; + + LOG_D("Pinctrl apply '%s'", rt_ofw_node_full_name(conf_np)); + + pinctrl_dev = rt_container_of(device, struct rockchip_pinctrl_device, parent); + pinctrl = pinctrl_dev->pinctrl; + + rt_ofw_foreach_prop_u32(conf_np, "rockchip,pins", prop, cell, value) + { + /* bank -> pin -> function -> pull */ + pin_bank = &pinctrl->pin_banks[value]; + + cell = rt_ofw_prop_next_u32(prop, cell, &value); + pin = value; + + cell = rt_ofw_prop_next_u32(prop, cell, &value); + function = value; + + cell = rt_ofw_prop_next_u32(prop, cell, &value); + pull_np = rt_ofw_find_node_by_phandle(value); + + if (!pull_np) + { + err = -RT_ERROR; + LOG_E("Firmware ref error in '%s'", rt_ofw_node_full_name(conf_np)); + + break; + } + + if (pinctrl->set_mux) + { + LOG_D("IOMUX from GPIO%d-%c%d to function(%d)", + pin_bank->bank_num, 'A' + (pin % 32) / 8, pin % 8, function); + + err = pinctrl->set_mux(pin_bank, pin, function); + + if (err) + { + break; + } + } + + rt_ofw_foreach_prop(pull_np, pin_prop) + { + param = rockchip_pinconf_prop_name_to_param(pin_prop->name, &default_value); + + if (param < 0) + { + err = param; + + break; + } + + if (pin_prop->length < sizeof(*cell)) + { + arg = default_value; + } + else + { + rt_ofw_prop_next_u32(pin_prop, RT_NULL, &arg); + } + + err = rockchip_pinconf_pull_apply(pinctrl, pin_bank, pin, param, arg); + + if (err && err != -RT_ENOSYS) + { + break; + } + } + + rt_ofw_node_put(pull_np); + } + + return err; +} + +static const struct rt_pin_ops rockchip_pinctrl_ops = +{ + .pin_ctrl_confs_apply = rockchip_pinctrl_confs_apply, +}; + +static rt_err_t rockchip_pinctrl_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs; + struct rockchip_pin_data *drvdata = RT_NULL; + struct rt_ofw_node *np = pdev->parent.ofw_node; + struct rockchip_pin_ctrl *pinctrl = (typeof(pinctrl))pdev->id->data; + struct rockchip_pin_bank *pin_bank = pinctrl->pin_banks; + struct rockchip_pinctrl_device *pinctrl_dev = rt_malloc(sizeof(*pinctrl_dev)); + + if (!pinctrl_dev) + { + return -RT_ENOMEM; + } + + drvdata = &pinctrl_dev->drvdata; + + if (!(drvdata->regmap_base = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"))) + { + err = -RT_EIO; + goto _fail; + } + + drvdata->regmap_pmu = rt_syscon_find_by_ofw_phandle(np, "rockchip,pmu"); + drvdata->pinctrl = pinctrl; + + pinctrl_dev->parent.ops = &rockchip_pinctrl_ops; + pinctrl_dev->pinctrl = pinctrl; + pinctrl->pins_nr = 0; + + grf_offs = pinctrl->grf_mux_offset; + pmu_offs = pinctrl->pmu_mux_offset; + drv_pmu_offs = pinctrl->pmu_drv_offset; + drv_grf_offs = pinctrl->grf_drv_offset; + pin_bank = pinctrl->pin_banks; + + for (int i = 0; i < pinctrl->banks_nr; ++i, ++pin_bank) + { + for (int bank_pins = 0, j = 0; j < 4; ++j) + { + int inc; + struct rockchip_drv *drv = &pin_bank->drv[j]; + struct rockchip_iomux *iomux = &pin_bank->iomux[j]; + + if (bank_pins >= pin_bank->nr_pins) + { + break; + } + + /* Preset iomux offset value, set new start value */ + if (iomux->offset >= 0) + { + if ((iomux->type & IOMUX_SOURCE_PMU) || (iomux->type & IOMUX_L_SOURCE_PMU)) + { + pmu_offs = iomux->offset; + } + else + { + grf_offs = iomux->offset; + } + } + else + { + /* Set current iomux offset */ + iomux->offset = ((iomux->type & IOMUX_SOURCE_PMU) || (iomux->type & IOMUX_L_SOURCE_PMU)) ? + pmu_offs : grf_offs; + } + + /* Preset drv offset value, set new start value */ + if (drv->offset >= 0) + { + if (iomux->type & IOMUX_SOURCE_PMU) + { + drv_pmu_offs = drv->offset; + } + else + { + drv_grf_offs = drv->offset; + } + } + else + { + /* Set current drv offset */ + drv->offset = (iomux->type & IOMUX_SOURCE_PMU) ? drv_pmu_offs : drv_grf_offs; + } + + /* + * Increase offset according to iomux width. + * 4bit iomux'es are spread over two registers. + */ + inc = (iomux->type & (IOMUX_WIDTH_4BIT | IOMUX_WIDTH_3BIT | IOMUX_WIDTH_2BIT)) ? 8 : 4; + + /* Preset drv offset value, set new start value */ + if ((iomux->type & IOMUX_SOURCE_PMU) || (iomux->type & IOMUX_L_SOURCE_PMU)) + { + pmu_offs += inc; + } + else + { + grf_offs += inc; + } + + /* + * Increase offset according to drv width. + * 3bit drive-strenth'es are spread over two registers. + */ + inc = ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) || (drv->drv_type == DRV_TYPE_IO_3V3_ONLY)) ? 8 : 4; + + if (iomux->type & IOMUX_SOURCE_PMU) + { + drv_pmu_offs += inc; + } + else + { + drv_grf_offs += inc; + } + + bank_pins += 8; + } + + pin_bank->drvdata = drvdata; + rt_spin_lock_init(&pin_bank->spinlock); + + pinctrl->pins_nr += pin_bank->nr_pins; + } + + rt_ofw_data(np) = &pinctrl_dev->parent; + + return RT_EOK; + +_fail: + rt_free(pinctrl_dev); + + return err; +} + +static const struct rt_ofw_node_id rockchip_pinctrl_ofw_ids[] = +{ + { .compatible = "rockchip,rk3308-pinctrl", .data = &rk3308_pin_ctrl }, + { .compatible = "rockchip,rk3568-pinctrl", .data = &rk3568_pin_ctrl }, + { .compatible = "rockchip,rk3588-pinctrl", .data = &rk3588_pin_ctrl }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pinctrl_driver = +{ + .name = "pinctrl-rockchip", + .ids = rockchip_pinctrl_ofw_ids, + + .probe = rockchip_pinctrl_probe, +}; + +static int rockchip_pinctrl_register(void) +{ + rt_platform_driver_register(&rockchip_pinctrl_driver); + + return 0; +} +INIT_PLATFORM_EXPORT(rockchip_pinctrl_register); diff --git a/components/drivers/pinctrl/pinctrl-rockchip.h b/components/drivers/pinctrl/pinctrl-rockchip.h new file mode 100644 index 000000000000..610fa9bad2b7 --- /dev/null +++ b/components/drivers/pinctrl/pinctrl-rockchip.h @@ -0,0 +1,178 @@ +/* + * 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 + */ + +#ifndef __ROCKCHIP_PINCTRL_H__ +#define __ROCKCHIP_PINCTRL_H__ + +#include +#include + +#include +#include "../soc/rockchip/rockchip.h" + +#define ROCKCHIP_PULL_BITS_PER_PIN 2 +#define ROCKCHIP_PULL_PINS_PER_REG 8 +#define ROCKCHIP_PULL_BANK_STRIDE 16 +#define ROCKCHIP_DRV_BITS_PER_PIN 2 +#define ROCKCHIP_DRV_PINS_PER_REG 8 +#define ROCKCHIP_DRV_BANK_STRIDE 16 +#define ROCKCHIP_DRV_3BITS_PER_PIN 3 + +enum rockchip_pin_drv_type +{ + DRV_TYPE_IO_DEFAULT = 0, + DRV_TYPE_IO_1V8_OR_3V0, + DRV_TYPE_IO_1V8_ONLY, + DRV_TYPE_IO_1V8_3V0_AUTO, + DRV_TYPE_IO_3V3_ONLY, + DRV_TYPE_MAX +}; + +enum rockchip_pin_pull_type +{ + PULL_TYPE_IO_DEFAULT = 0, + PULL_TYPE_IO_1V8_ONLY, + PULL_TYPE_MAX +}; + +enum rockchip_pinctrl_type +{ + RK3308, + RK3568, + RK3588, +}; + +struct rockchip_gpio_regs +{ + rt_uint32_t port_dr; /* Data register */ + rt_uint32_t port_ddr; /* Data direction register */ + rt_uint32_t int_en; /* Interrupt enable */ + rt_uint32_t int_mask; /* Interrupt mask */ + rt_uint32_t int_type; /* Interrupt trigger type, such as high, low, edge trriger type. */ + rt_uint32_t int_polarity; /* Interrupt polarity enable register */ + rt_uint32_t int_bothedge; /* Interrupt bothedge enable register */ + rt_uint32_t int_status; /* Interrupt status register */ + rt_uint32_t int_rawstatus; /* Int_status = int_rawstatus & int_mask */ + rt_uint32_t debounce; /* Enable debounce for interrupt signal */ + rt_uint32_t dbclk_div_en; /* Enable divider for debounce clock */ + rt_uint32_t dbclk_div_con; /* Setting for divider of debounce clock */ + rt_uint32_t port_eoi; /* End of interrupt of the port */ + rt_uint32_t ext_port; /* Port data from external */ + rt_uint32_t version_id; /* Controller version register */ +}; + +struct rockchip_iomux +{ + int type; + int offset; +}; + +struct rockchip_drv +{ + enum rockchip_pin_drv_type drv_type; + int offset; +}; + +struct rockchip_pin_data +{ + struct rt_syscon *regmap_base; + struct rt_syscon *regmap_pmu; + rt_size_t reg_size; + + struct rockchip_pin_ctrl *pinctrl; +}; + +struct rockchip_pin_bank +{ + struct rt_device_pin parent; + + const char *name; + + int irq; + void *reg_base; + struct rt_clk *clk; + struct rt_clk *db_clk; + + rt_uint8_t nr_pins; + rt_uint8_t bank_num; + rt_uint32_t gpio_type; + rt_uint32_t toggle_edge_mode; + struct rockchip_pin_data *drvdata; + const struct rockchip_gpio_regs *gpio_regs; + + struct rockchip_iomux iomux[4]; + struct rockchip_drv drv[4]; + enum rockchip_pin_pull_type pull_type[4]; + struct rt_spinlock spinlock; + + rt_uint32_t recalced_mask; +}; + +struct rockchip_mux_recalced_data +{ + rt_uint8_t num; + rt_uint8_t pin; + rt_uint32_t reg; + rt_uint8_t bit; + rt_uint8_t mask; +}; + +enum rockchip_mux_route_location +{ + ROCKCHIP_ROUTE_SAME = 0, + ROCKCHIP_ROUTE_PMU, + ROCKCHIP_ROUTE_GRF, +}; + +struct rockchip_mux_route_data +{ + rt_uint8_t bank_num; + rt_uint8_t pin; + rt_uint8_t func; + enum rockchip_mux_route_location route_location; + rt_uint32_t route_offset; + rt_uint32_t route_val; +}; + +struct rockchip_pin_ctrl +{ + char *label; + enum rockchip_pinctrl_type type; + + struct rockchip_pin_bank *pin_banks; + rt_uint32_t banks_nr; + rt_uint32_t pins_nr; + + int grf_mux_offset; + int pmu_mux_offset; + int grf_drv_offset; + int pmu_drv_offset; + + struct rockchip_mux_recalced_data *iomux_recalced; + rt_uint32_t niomux_recalced; + + struct rockchip_mux_route_data *iomux_routes; + rt_uint32_t niomux_routes; + + rt_err_t (*set_mux)(struct rockchip_pin_bank *pin_bank, int pin, int mux); + rt_err_t (*set_pull)(struct rockchip_pin_bank *pin_bank, int pin, int pull); + rt_err_t (*set_drive)(struct rockchip_pin_bank *pin_bank, int pin, int strength); + rt_err_t (*set_schmitt)(struct rockchip_pin_bank *pin_bank, int pin, int enable); +}; + +struct rockchip_pinctrl_device +{ + struct rt_device_pin parent; + + struct rockchip_pin_data drvdata; + struct rockchip_pin_ctrl *pinctrl; +}; + +#endif /* __ROCKCHIP_PINCTRL_H__ */ diff --git a/components/drivers/pinctrl/pinctrl.c b/components/drivers/pinctrl/pinctrl.c new file mode 100644 index 000000000000..158db78d19fb --- /dev/null +++ b/components/drivers/pinctrl/pinctrl.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-11-26 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "rtdm.pinctrl" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#ifdef RT_USING_OFW +static rt_err_t ofw_pin_ctrl_confs_apply(struct rt_ofw_node *np, int index) +{ + rt_err_t err = -RT_EEMPTY; + rt_phandle phandle; + const fdt32_t *cell; + struct rt_ofw_prop *prop; + char pinctrl_n_name[sizeof("pinctrl-0")]; + + rt_sprintf(pinctrl_n_name, "pinctrl-%d", index); + index = 0; + + rt_ofw_foreach_prop_u32(np, pinctrl_n_name, prop, cell, phandle) + { + struct rt_device_pin *pinctrl = RT_NULL; + struct rt_ofw_node *conf_np, *pinctrl_np; + + conf_np = pinctrl_np = rt_ofw_find_node_by_phandle(phandle); + + if (!conf_np) + { + err = -RT_EIO; + + break; + } + /* + * We always assume the phandle in pinctrl-N is the pinctrl-device + * node's child node. If not, we need a better way to find it: + * + * / { + * serial@4600 { + * device_type = "serial"; + * reg = <0x4600 0x100>; + * clock-frequency = <0>; + * pinctrl-names = "default"; + * pinctrl-0 = <&uart_pin>; + * }; + * + * i2c@4700 { + * reg = <0x4700 0x100>; + * pinctrl-names = "default"; + * pinctrl-0 = <&i2c_pin_scl, &i2c_pin_sda>; + * }; + * + * pinctrl: pinctrl { + * + * uart_pin { + * multi,pins = + * <0 PD0 1 &uart_rx_pull_up>, + * <0 PD1 1 &uart_tx_pull_up>; + * }; + * + * i2c_pin_scl { + * single,pins = <0 PB1>; + * pull = <&i2c_pull_none_smt>; + * function = <1>; + * }; + * + * i2c_pin_sda { + * single,pins = <0 PB2>; + * pull = <&i2c_pull_none_smt>; + * function = <1>; + * }; + * }; + * } + */ + rt_ofw_foreach_parent_node(pinctrl_np) + { + if (rt_ofw_prop_read_bool(pinctrl_np, "compatible")) + { + break; + } + } + + if (pinctrl_np) + { + pinctrl = rt_ofw_data(pinctrl_np); + + rt_ofw_node_put(pinctrl_np); + } + + if (!pinctrl || !pinctrl->ops || !pinctrl->ops->pin_ctrl_confs_apply) + { + if (index) + { + err = -RT_EEMPTY; + } + else + { + err = -RT_ERROR; + } + + rt_ofw_node_put(conf_np); + + break; + } + + err = pinctrl->ops->pin_ctrl_confs_apply(&pinctrl->parent, conf_np); + rt_ofw_node_put(conf_np); + + if (err) + { + break; + } + + ++index; + } + + return err; +} + +static rt_err_t ofw_pin_ctrl_confs_apply_by_name(struct rt_ofw_node *np, const char *name) +{ + int index = 0; + rt_err_t err = -RT_EEMPTY; + const char *pinctrl_name; + struct rt_ofw_prop *prop; + + rt_ofw_foreach_prop_string(np, "pinctrl-names", prop, pinctrl_name) + { + if (!rt_strcmp(pinctrl_name, name)) + { + err = ofw_pin_ctrl_confs_apply(np, index); + + break; + } + + ++index; + } + + return err; +} +#endif /* RT_USING_OFW */ + +rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index) +{ + rt_err_t err = RT_EOK; + + if (device && index >= 0) + { + err = -RT_ENOSYS; + + #ifdef RT_USING_OFW + if (device->ofw_node) + { + err = ofw_pin_ctrl_confs_apply(device->ofw_node, index); + } + #endif /* RT_USING_OFW */ + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name) +{ + rt_err_t err = RT_EOK; + + if (device) + { + if (!name) + { + name = "default"; + } + + err = -RT_ENOSYS; + + #ifdef RT_USING_OFW + if (device->ofw_node) + { + err = ofw_pin_ctrl_confs_apply_by_name(device->ofw_node, name); + } + #endif /* RT_USING_OFW */ + } + else + { + err = -RT_EINVAL; + } + + return err; +} diff --git a/components/drivers/pm/Kconfig b/components/drivers/pm/Kconfig index fffea8de6056..d638a9d1673d 100644 --- a/components/drivers/pm/Kconfig +++ b/components/drivers/pm/Kconfig @@ -38,14 +38,16 @@ menuconfig RT_USING_PM endif endif -config RT_PM_RESET_SYSCON - bool "Generic SYSCON regmap reset driver" +config RT_PM_BCM2835 + bool "BCM2835 PM driver" depends on RT_USING_PM - depends on RT_USING_OFW - select RT_MFD_SYSCON -config RT_PM_RESET_SYSCON_POWEROFF +config RT_PM_SYSCON_POWEROFF bool "Generic SYSCON regmap poweroff driver" depends on RT_USING_PM - depends on RT_USING_OFW + select RT_MFD_SYSCON + +config RT_PM_SYSCON_REBOOT + bool "Generic SYSCON regmap reboot driver" + depends on RT_USING_PM select RT_MFD_SYSCON diff --git a/components/drivers/pm/SConscript b/components/drivers/pm/SConscript index 09d8d879ca94..d897efea1284 100644 --- a/components/drivers/pm/SConscript +++ b/components/drivers/pm/SConscript @@ -10,10 +10,13 @@ CPPPATH = [cwd + '/../include'] src = ['pm.c', 'lptimer.c'] -if GetDepend(['RT_PM_RESET_SYSCON_POWEROFF']): +if GetDepend(['RT_PM_BCM2835']): + src += ['pm-bcm2835.c'] + +if GetDepend(['RT_PM_SYSCON_POWEROFF']): src += ['pm-syscon-poweroff.c'] -if GetDepend(['RT_PM_RESET_SYSCON']): +if GetDepend(['RT_PM_SYSCON_REBOOT']): src += ['pm-syscon-reboot.c'] group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) diff --git a/components/drivers/pm/pm-bcm2835.c b/components/drivers/pm/pm-bcm2835.c new file mode 100644 index 000000000000..ca5ab11b79c7 --- /dev/null +++ b/components/drivers/pm/pm-bcm2835.c @@ -0,0 +1,91 @@ +/* + * 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 "pm.bcm2835" +#define DBG_LVL DBG_INFO +#include + +#include "pm-bcm2835.h" + +static rt_err_t bcm2835_pm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *pm_name; + struct rt_device *dev = &pdev->parent; + struct bcm2835_pm *pm = rt_malloc(sizeof(*pm)); + + if (!pm) + { + return -RT_ENOMEM; + } + +#ifdef RT_USING_OFW + 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; + + pm_name = "bcm2835-wdt"; + + pdev->name = pm_name; + pdev->priv = pm; + /* Ask bus to check drivers' name */ + pdev->parent.ofw_node = RT_NULL; + + return rt_bus_add_device(pdev->parent.bus, &pdev->parent); + +_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", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver bcm2835_pm_driver = +{ + .name = "pm-bcm2835", + .ids = bcm2835_pm_ofw_ids, + + .probe = bcm2835_pm_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_pm_driver); diff --git a/components/drivers/pm/pm-bcm2835.h b/components/drivers/pm/pm-bcm2835.h new file mode 100644 index 000000000000..00c62343a263 --- /dev/null +++ b/components/drivers/pm/pm-bcm2835.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 __PM_BCM2835_H__ +#define __PM_BCM2835_H__ + +struct bcm2835_pm +{ + void *base; + void *asb; + void *rpivid_asb; + + void *ofw_node; +}; + +#endif /* __PM_BCM2835_H__ */ diff --git a/components/drivers/pm/pm-syscon-poweroff.c b/components/drivers/pm/pm-syscon-poweroff.c index a8510aba39b2..14c511ee36f5 100644 --- a/components/drivers/pm/pm-syscon-poweroff.c +++ b/components/drivers/pm/pm-syscon-poweroff.c @@ -9,13 +9,12 @@ */ #include +#include #define DBG_TAG "pm.syscon.poweroff" #define DBG_LVL DBG_INFO #include -#include - static struct rt_syscon *syscon; static rt_uint32_t offset, value, mask; @@ -34,7 +33,7 @@ static rt_err_t syscon_poweroff_probe(struct rt_platform_device *pdev) rt_err_t mask_err, value_err; struct rt_ofw_node *np = pdev->parent.ofw_node; - syscon = rt_syscon_find_by_phandle(np, "regmap"); + syscon = rt_syscon_find_by_ofw_phandle(np, "regmap"); if (!syscon) { @@ -70,14 +69,14 @@ static rt_err_t syscon_poweroff_probe(struct rt_platform_device *pdev) mask = 0xffffffff; } - if (rt_pm_shutdown) + if (rt_pm_machine_shutdown) { - LOG_E("rt_pm_shutdown have hook %p", rt_pm_shutdown); + LOG_E("rt_pm_machine_shutdown have hook %p", rt_pm_machine_shutdown); return -RT_EBUSY; } - rt_pm_shutdown = syscon_poweroff; + rt_pm_machine_shutdown = syscon_poweroff; return RT_EOK; } diff --git a/components/drivers/pm/pm-syscon-reboot.c b/components/drivers/pm/pm-syscon-reboot.c index 85b3dc09db23..65edbd35d701 100644 --- a/components/drivers/pm/pm-syscon-reboot.c +++ b/components/drivers/pm/pm-syscon-reboot.c @@ -9,13 +9,12 @@ */ #include +#include #define DBG_TAG "pm.syscon.reboot" #define DBG_LVL DBG_INFO #include -#include - static struct rt_syscon *syscon; static rt_uint32_t offset, value, mask; @@ -26,15 +25,15 @@ static void syscon_reboot(void) rt_thread_mdelay(1000); - LOG_E("Unable to restart system\n"); + LOG_E("Unable to restart system"); } -static int syscon_reboot_probe(struct platform_device *pdev) +static rt_err_t syscon_reboot_probe(struct rt_platform_device *pdev) { rt_err_t mask_err, value_err; struct rt_ofw_node *np = pdev->parent.ofw_node; - syscon = rt_syscon_find_by_phandle(np, "regmap"); + syscon = rt_syscon_find_by_ofw_phandle(np, "regmap"); if (!syscon) { @@ -70,14 +69,14 @@ static int syscon_reboot_probe(struct platform_device *pdev) mask = 0xffffffff; } - if (rt_pm_reset) + if (rt_pm_machine_reset) { - LOG_E("rt_pm_reset have hook %p", rt_pm_reset); + LOG_E("rt_pm_machine_reset have hook %p", rt_pm_machine_reset); return -RT_EBUSY; } - rt_pm_reset = syscon_reboot; + rt_pm_machine_reset = syscon_reboot; return RT_EOK; } diff --git a/components/drivers/pm/pm.c b/components/drivers/pm/pm.c index ad6110dd8b8a..263614de1494 100644 --- a/components/drivers/pm/pm.c +++ b/components/drivers/pm/pm.c @@ -53,8 +53,8 @@ #endif #endif -void (*rt_pm_shutdown)(void) = RT_NULL; -void (*rt_pm_reset)(void) = RT_NULL; +void (*rt_pm_machine_shutdown)(void) = RT_NULL; +void (*rt_pm_machine_reset)(void) = RT_NULL; static struct rt_pm _pm; diff --git a/components/drivers/pwm/Kconfig b/components/drivers/pwm/Kconfig new file mode 100755 index 000000000000..4345c6c3d5f9 --- /dev/null +++ b/components/drivers/pwm/Kconfig @@ -0,0 +1,10 @@ +menuconfig RT_USING_PWM + bool "Using PWM device drivers" + default n + +config RT_PWM_ROCKCHIP + bool "Rockchip PWM support" + select RT_USING_PINCTRL + depends on RT_USING_DM + depends on RT_USING_PWM + default n diff --git a/components/drivers/pwm/SConscript b/components/drivers/pwm/SConscript new file mode 100755 index 000000000000..054bec6f6d05 --- /dev/null +++ b/components/drivers/pwm/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_PWM']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['pwm.c'] + +if GetDepend(['RT_PWM_ROCKCHIP']): + src += ['pwm-rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/pwm/pwm-rockchip.c b/components/drivers/pwm/pwm-rockchip.c new file mode 100644 index 000000000000..e85e5f525ec7 --- /dev/null +++ b/components/drivers/pwm/pwm-rockchip.c @@ -0,0 +1,390 @@ +/* + * 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 PWM_CTRL_TIMER_EN (1 << 0) +#define PWM_CTRL_OUTPUT_EN (1 << 3) + +#define PWM_ENABLE (1 << 0) +#define PWM_CONTINUOUS (1 << 1) +#define PWM_DUTY_POSITIVE (1 << 3) +#define PWM_DUTY_NEGATIVE (0 << 3) +#define PWM_INACTIVE_NEGATIVE (0 << 4) +#define PWM_INACTIVE_POSITIVE (1 << 4) +#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE) +#define PWM_OUTPUT_LEFT (0 << 5) +#define PWM_LOCK_EN (1 << 6) +#define PWM_LP_DISABLE (0 << 8) + +#define NSEC_PER_SEC 1000000000L + +enum pwm_polarity +{ + PWM_POLARITY_NORMAL, + PWM_POLARITY_INVERSED, +}; + +struct rockchip_pwm_regs +{ + rt_ubase_t duty; + rt_ubase_t period; + rt_ubase_t cntr; + rt_ubase_t ctrl; +}; + +struct rockchip_pwm_data +{ + struct rockchip_pwm_regs regs; + + rt_uint32_t prescaler; + rt_bool_t supports_polarity; + rt_bool_t supports_lock; + rt_uint32_t enable_conf; +}; + +struct rockchip_pwm +{ + struct rt_device_pwm parent; + void *base; + + struct rt_clk *clk; + struct rt_clk *pclk; + + const struct rockchip_pwm_data *data; +}; + +#define raw_to_rockchip_pwm(raw) rt_container_of(raw, struct rockchip_pwm, parent) + +static rt_err_t rockchip_pwm_enable(struct rockchip_pwm *rk_pwm, rt_bool_t enable) +{ + rt_uint32_t enable_conf = rk_pwm->data->enable_conf, val; + + if (enable) + { + rt_err_t err = rt_clk_enable(rk_pwm->clk); + + if (err) + { + return err; + } + } + + val = HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl); + + if (enable) + { + val |= enable_conf; + } + else + { + val &= ~enable_conf; + } + + HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl) = val; + + if (!enable) + { + rt_clk_disable(rk_pwm->clk); + } + else + { + rt_pin_ctrl_confs_apply_by_name(&rk_pwm->parent.parent, "active"); + } + + return RT_EOK; +} + +static void rockchip_pwm_config(struct rockchip_pwm *rk_pwm, struct rt_pwm_configuration *pwm_cfg, enum pwm_polarity polarity) +{ + rt_ubase_t period, duty; + rt_uint64_t clk_rate, div; + rt_uint32_t ctrl; + + clk_rate = rt_clk_get_rate(rk_pwm->clk); + + /* + * Since period and duty cycle registers have a width of 32 bits, every + * possible input period can be obtained using the default prescaler value + * for all practical clock rate values. + * duty_cycle = pulse / period + */ + div = clk_rate * pwm_cfg->period; + period = RT_DIV_ROUND_CLOSEST_ULL(div, rk_pwm->data->prescaler * NSEC_PER_SEC); + + div = clk_rate * pwm_cfg->pulse; + duty = RT_DIV_ROUND_CLOSEST_ULL(div, rk_pwm->data->prescaler * NSEC_PER_SEC); + + /* + * Lock the period and duty of previous configuration, then change the duty + * and period, that would not be effective. + */ + ctrl = HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl); + + if (rk_pwm->data->supports_lock) + { + ctrl |= PWM_LOCK_EN; + HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl) = ctrl; + } + + HWREG32(rk_pwm->base + rk_pwm->data->regs.period) = period; + HWREG32(rk_pwm->base + rk_pwm->data->regs.duty) = duty; + + if (rk_pwm->data->supports_polarity) + { + ctrl &= ~PWM_POLARITY_MASK; + + if (polarity == PWM_POLARITY_INVERSED) + { + ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; + } + else + { + ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; + } + } + + /* + * Unlock and set polarity at the same time, the configuration of duty, + * period and polarity would be effective together at next period. + */ + if (rk_pwm->data->supports_lock) + { + ctrl &= ~PWM_LOCK_EN; + } + + HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl) = ctrl; +} + +static rt_err_t rockchip_pwm_control(struct rt_device_pwm *pwm, int cmd, void *args) +{ + rt_err_t status = RT_EOK; + struct rockchip_pwm *rk_pwm = raw_to_rockchip_pwm(pwm); + struct rt_pwm_configuration *pwm_cfg = args; + + rt_clk_enable(rk_pwm->pclk); + + /* RT_PWM framework have check args */ + switch (cmd) + { + case PWM_CMD_ENABLE: + rockchip_pwm_enable(rk_pwm, RT_TRUE); + break; + + case PWM_CMD_DISABLE: + rockchip_pwm_enable(rk_pwm, RT_FALSE); + break; + + case PWM_CMD_SET: + case PWM_CMD_SET_PERIOD: + case PWM_CMD_SET_PULSE: + /* Maybe RT_PWM will support polarity */ + rockchip_pwm_config(rk_pwm, pwm_cfg, PWM_POLARITY_NORMAL); + break; + + default: + status = -RT_EINVAL; + break; + } + + rt_clk_disable(rk_pwm->pclk); + + return status; +} + +static struct rt_pwm_ops rockchip_pwm_ops = +{ + .control = rockchip_pwm_control, +}; + +static void rockchip_pwm_free(struct rockchip_pwm *rk_pwm) +{ + if (rk_pwm->base) + { + rt_iounmap(rk_pwm->base); + } + + if (rk_pwm->clk) + { + rt_clk_disable_unprepare(rk_pwm->clk); + rt_clk_put(rk_pwm->clk); + } + + if (rk_pwm->pclk) + { + rt_clk_disable_unprepare(rk_pwm->pclk); + rt_clk_put(rk_pwm->pclk); + } + + rt_free(rk_pwm); +} + +static rt_err_t rockchip_pwm_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + rt_bool_t enabled; + rt_uint32_t enable_conf, ctrl; + struct rt_device *dev = &pdev->parent; + struct rockchip_pwm *rk_pwm = rt_calloc(1, sizeof(*rk_pwm)); + const struct rockchip_pwm_data *pdata = pdev->id->data; + + if (!rk_pwm) + { + return -RT_ENOMEM; + } + + rk_pwm->data = pdata; + rk_pwm->base = rt_dm_dev_iomap(dev, 0); + + if (!rk_pwm->base) + { + err = -RT_EIO; + goto _free_res; + } + + rk_pwm->clk = rt_clk_get_by_name(dev, "pwm"); + + if (!rk_pwm->clk) + { + err = -RT_EIO; + goto _free_res; + } + +#ifdef RT_USING_OFW + if (rt_ofw_count_phandle_cells(dev->ofw_node, "clocks", "#clock-cells") == 2) + { + rk_pwm->pclk = rt_clk_get_by_name(dev, "pclk"); + + if (!rk_pwm->pclk) + { + err = -RT_EIO; + goto _free_res; + } + } + else +#endif /* RT_USING_OFW */ + { + rk_pwm->pclk = rk_pwm->clk; + } + + if ((err = rt_clk_prepare_enable(rk_pwm->clk))) + { + goto _free_res; + } + + if ((err = rt_clk_prepare_enable(rk_pwm->pclk))) + { + goto _free_res; + } + + enable_conf = rk_pwm->data->enable_conf; + ctrl = HWREG32(rk_pwm->base + rk_pwm->data->regs.ctrl); + enabled = (ctrl & enable_conf) == enable_conf; + + /* Keep the PWM clk enabled if the PWM appears to be up and running. */ + if (!enabled) + { + rt_clk_disable(rk_pwm->clk); + } + + rt_clk_disable(rk_pwm->pclk); + + rk_pwm->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name_auto(&rk_pwm->parent.parent, "pwm"); + rt_device_pwm_register(&rk_pwm->parent, rt_dm_dev_get_name(&rk_pwm->parent.parent), &rockchip_pwm_ops, rk_pwm); + + return RT_EOK; + +_free_res: + rockchip_pwm_free(rk_pwm); + + return err; +} + +static const struct rockchip_pwm_data pwm_data_v1 = +{ + .regs = + { + .duty = 0x04, + .period = 0x08, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 2, + .supports_polarity = RT_FALSE, + .supports_lock = RT_FALSE, + .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, +}; + +static const struct rockchip_pwm_data pwm_data_v2 = +{ + .regs = + { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = RT_TRUE, + .supports_lock = RT_FALSE, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | PWM_CONTINUOUS, +}; + +static const struct rockchip_pwm_data pwm_data_vop = +{ + .regs = + { + .duty = 0x08, + .period = 0x04, + .cntr = 0x0c, + .ctrl = 0x00, + }, + .prescaler = 1, + .supports_polarity = RT_TRUE, + .supports_lock = RT_FALSE, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | PWM_CONTINUOUS, +}; + +static const struct rockchip_pwm_data pwm_data_v3 = +{ + .regs = + { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = RT_TRUE, + .supports_lock = RT_TRUE, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | PWM_CONTINUOUS, +}; + +static const struct rt_ofw_node_id rockchip_pwm_ofw_ids[] = +{ + { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1 }, + { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2 }, + { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop }, + { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3 }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_pwm_driver = +{ + .name = "rockchip-pwm", + .ids = rockchip_pwm_ofw_ids, + + .probe = rockchip_pwm_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_pwm_driver); diff --git a/components/drivers/misc/rt_drv_pwm.c b/components/drivers/pwm/pwm.c similarity index 99% rename from components/drivers/misc/rt_drv_pwm.c rename to components/drivers/pwm/pwm.c index af87a5b60e07..438aafbbd616 100644 --- a/components/drivers/misc/rt_drv_pwm.c +++ b/components/drivers/pwm/pwm.c @@ -116,8 +116,6 @@ rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, { rt_err_t result = RT_EOK; - rt_memset(device, 0, sizeof(struct rt_device_pwm)); - #ifdef RT_USING_DEVICE_OPS device->parent.ops = &pwm_device_ops; #else diff --git a/components/drivers/regulator/Kconfig b/components/drivers/regulator/Kconfig new file mode 100644 index 000000000000..1ace25c7b3af --- /dev/null +++ b/components/drivers/regulator/Kconfig @@ -0,0 +1,17 @@ +menuconfig RT_USING_REGULATOR + bool "Using Voltage and Current Regulator" + depends on RT_USING_DM + default n + +config RT_REGULATOR_GPIO + bool "GPIO regulator support" + depends on RT_USING_REGULATOR + depends on RT_USING_PIN + default y + +config RT_REGULATOR_RK8XX + bool "Rockchip RK805/RK808/RK809/RK817/RK818 Power regulators" + depends on RT_USING_REGULATOR + depends on RT_MFD_RK8XX + select RT_USING_PIN + default y diff --git a/components/drivers/regulator/SConscript b/components/drivers/regulator/SConscript new file mode 100755 index 000000000000..1ac9d5812250 --- /dev/null +++ b/components/drivers/regulator/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_REGULATOR']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['regulator.c', 'regulator-fixed.c', 'regulator_dm.c'] + +if GetDepend(['RT_REGULATOR_GPIO']): + src += ['regulator-gpio.c'] + +if GetDepend(['RT_REGULATOR_RK8XX']): + src += ['regulator-rk8xx.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/regulator/regulator-fixed.c b/components/drivers/regulator/regulator-fixed.c new file mode 100644 index 000000000000..5de8506b456a --- /dev/null +++ b/components/drivers/regulator/regulator-fixed.c @@ -0,0 +1,93 @@ +/* + * 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 "regulator_dm.h" + +struct regulator_fixed +{ + struct rt_regulator_node parent; + + const char *input_supply; + rt_uint32_t startup_delay; + rt_uint32_t off_on_delay; + struct rt_regulator_param param; +}; + +#define raw_to_regulator_fixed(raw) rt_container_of(raw, struct regulator_fixed, parent) + +static int regulator_fixed_get_voltage(struct rt_regulator_node *reg_np) +{ + struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np); + + return rf->param.min_uvolt + (rf->param.max_uvolt - rf->param.min_uvolt) / 2; +} + +static const struct rt_regulator_ops regulator_fixed_ops = +{ + .get_voltage = regulator_fixed_get_voltage, +}; + +static rt_err_t regulator_fixed_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct regulator_fixed *rf = rt_malloc(sizeof(*rf)); + struct rt_regulator_node *rnp; + + if (!rf) + { + return -RT_ENOMEM; + } + + regulator_ofw_parse(dev->ofw_node, &rf->param); + + rnp = &rf->parent; + rnp->supply_name = rf->param.name; + rnp->ops = ®ulator_fixed_ops; + rnp->param = &rf->param; + rnp->dev = &pdev->parent; + + rt_dm_dev_prop_read_u32(dev, "startup-delay-us", &rf->startup_delay); + rt_dm_dev_prop_read_u32(dev, "off-on-delay-us", &rf->off_on_delay); + + if (rt_dm_dev_prop_read_bool(dev, "vin-supply")) + { + rf->input_supply = "vin"; + } + + if ((err = rt_regulator_register(rnp))) + { + rt_free(rf); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id regulator_fixed_ofw_ids[] = +{ + { .compatible = "regulator-fixed" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver regulator_fixed_driver = +{ + .name = "reg-fixed-voltage", + .ids = regulator_fixed_ofw_ids, + + .probe = regulator_fixed_probe, +}; + +static int regulator_fixed_register(void) +{ + rt_platform_driver_register(®ulator_fixed_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(regulator_fixed_register); diff --git a/components/drivers/regulator/regulator-gpio.c b/components/drivers/regulator/regulator-gpio.c new file mode 100644 index 000000000000..2b411c58f3a4 --- /dev/null +++ b/components/drivers/regulator/regulator-gpio.c @@ -0,0 +1,333 @@ +/* + * 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 "regulator_dm.h" + +struct regulator_gpio_state +{ + rt_uint32_t value; + rt_uint32_t gpios; +}; + +struct regulator_gpio_desc +{ + rt_base_t pin; + rt_uint32_t flags; +}; + +struct regulator_gpio +{ + struct rt_regulator_node parent; + + rt_size_t enable_cnt; + rt_base_t enable_pin; + + rt_size_t pins_nr; + struct regulator_gpio_desc *pins_desc; + + int state; + rt_size_t states_nr; + struct regulator_gpio_state *states; + + const char *input_supply; + rt_uint32_t startup_delay; + rt_uint32_t off_on_delay; + rt_bool_t enabled_at_boot; + struct rt_regulator_param param; +}; + +#define raw_to_regulator_gpio(raw) rt_container_of(raw, struct regulator_gpio, parent) + +static rt_err_t regulator_gpio_enable(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (rg->enable_pin < 0 || param->always_on) + { + return RT_EOK; + } + + if (rg->enable_cnt == 0) + { + rt_pin_write(rg->enable_pin, param->enable_active_high ? PIN_HIGH : PIN_LOW); + + rt_hw_us_delay(param->enable_delay); + } + ++rg->enable_cnt; + + return RT_EOK; +} + +static rt_err_t regulator_gpio_disable(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (rg->enable_pin < 0 || param->always_on) + { + return RT_EOK; + } + + if (rg->enable_cnt == 1) + { + rt_pin_write(rg->enable_pin, param->enable_active_high ? PIN_LOW: PIN_HIGH); + + rt_hw_us_delay(param->enable_delay); + } + --rg->enable_cnt; + + return RT_EOK; +} + +static rt_bool_t regulator_gpio_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint8_t active; + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (rg->enable_pin < 0 || param->always_on) + { + return RT_TRUE; + } + + active = rt_pin_read(rg->enable_pin); + + if (param->enable_active_high) + { + return active == PIN_HIGH; + } + + return active == PIN_LOW; +} + +static rt_err_t regulator_gpio_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int target = 0, best_val = RT_REGULATOR_UVOLT_INVALID; + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + + for (int i = 0; i < rg->states_nr; ++i) + { + struct regulator_gpio_state *state = &rg->states[i]; + + if (state->value < best_val && + state->value >= min_uvolt && + state->value <= max_uvolt) + { + target = state->gpios; + best_val = state->value; + } + } + + if (best_val == RT_REGULATOR_UVOLT_INVALID) + { + return -RT_EINVAL; + } + + for (int i = 0; i < rg->pins_nr; ++i) + { + int state = (target >> i) & 1; + + if (!rg->param.enable_active_high) + { + state = !state; + } + + rt_pin_write(rg->pins_desc[i].pin, state); + } + + rg->state = target; + + + return RT_EOK; +} + +static int regulator_gpio_get_voltage(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + + for (int i = 0; i < rg->states_nr; ++i) + { + if (rg->states[i].gpios == rg->state) + { + return rg->states[i].value; + } + } + + return -RT_EINVAL; +} + +static const struct rt_regulator_ops regulator_gpio_ops = +{ + .enable = regulator_gpio_enable, + .disable = regulator_gpio_disable, + .is_enabled = regulator_gpio_is_enabled, + .set_voltage = regulator_gpio_set_voltage, + .get_voltage = regulator_gpio_get_voltage, +}; + +static rt_err_t regulator_gpio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct regulator_gpio *rg = rt_calloc(1, sizeof(*rg)); + struct rt_regulator_node *rgp; + + if (!rg) + { + return -RT_ENOMEM; + } + + regulator_ofw_parse(dev->ofw_node, &rg->param); + + rgp = &rg->parent; + rgp->supply_name = rg->param.name; + rgp->ops = ®ulator_gpio_ops; + rgp->param = &rg->param; + rgp->dev = &pdev->parent; + + rt_dm_dev_prop_read_u32(dev, "startup-delay-us", &rg->startup_delay); + rt_dm_dev_prop_read_u32(dev, "off-on-delay-us", &rg->off_on_delay); + + if (rt_dm_dev_prop_read_bool(dev, "vin-supply")) + { + rg->input_supply = "vin"; + } + + rg->enable_pin = rt_pin_get_named_pin(dev, "enable-gpios", 0, RT_NULL, RT_NULL); + + if (rg->enable_pin < 0) + { + rg->enable_pin = -1; + } + + rg->pins_nr = rt_pin_get_named_pin_count(dev, "gpios"); + + if (rg->pins_nr < 0) + { + err = rg->pins_nr; + + goto _fail; + } + + if (rg->pins_nr > 0) + { + rg->pins_desc = rt_malloc(sizeof(*rg->pins_desc) * rg->pins_nr); + + if (!rg->pins_desc) + { + err = -RT_ENOMEM; + + goto _fail; + } + + for (int i = 0; i < rg->pins_nr; ++i) + { + rt_uint32_t val; + struct regulator_gpio_desc *gpiod = &rg->pins_desc[i]; + + gpiod->pin = rt_pin_get_named_pin(dev, "gpios", i, RT_NULL, RT_NULL); + + if (rt_dm_dev_prop_read_u32_index(dev, "gpios-states", i, &val) < 0) + { + gpiod->flags = PIND_OUT_HIGH; + } + else + { + gpiod->flags = val ? PIND_OUT_HIGH : PIND_OUT_LOW; + } + + if (gpiod->flags == PIND_OUT_HIGH) + { + rg->state |= (1 << i); + } + } + } + + rg->states_nr = rt_dm_dev_prop_count_of_u32(dev, "states") / 2; + + if (rg->states_nr < 0) + { + err = -RT_EIO; + + goto _fail; + } + + rg->states = rt_malloc(sizeof(*rg->states) * rg->states_nr); + + if (!rg->states) + { + err = -RT_ENOMEM; + + goto _fail; + } + + for (int i = 0; i < rg->states_nr; ++i) + { + if (rt_dm_dev_prop_read_u32_index(dev, "states", i * 2, &rg->states[i].value) < 0) + { + err = -RT_EIO; + + goto _fail; + } + + if (rt_dm_dev_prop_read_u32_index(dev, "states", i * 2 + 1, &rg->states[i].gpios) < 0) + { + err = -RT_EIO; + + goto _fail; + } + } + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rg->pins_desc) + { + rt_free(rg->pins_desc); + } + if (rg->states) + { + rt_free(rg->states); + } + rt_free(rg); + + return err; +} + +static const struct rt_ofw_node_id regulator_gpio_ofw_ids[] = +{ + { .compatible = "regulator-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver regulator_gpio_driver = +{ + .name = "regulator-gpio", + .ids = regulator_gpio_ofw_ids, + + .probe = regulator_gpio_probe, +}; + +static int regulator_gpio_register(void) +{ + rt_platform_driver_register(®ulator_gpio_driver); + + return 0; +} +INIT_SUBSYS_LATER_EXPORT(regulator_gpio_register); diff --git a/components/drivers/regulator/regulator-rk8xx.c b/components/drivers/regulator/regulator-rk8xx.c new file mode 100644 index 000000000000..e4674ccd3992 --- /dev/null +++ b/components/drivers/regulator/regulator-rk8xx.c @@ -0,0 +1,1160 @@ +/* + * 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 "regulator.rk8xx" +#define DBG_LVL DBG_INFO +#include + +#include "regulator_dm.h" +#include "../mfd/rk8xx.h" + +/* Field Definitions */ +#define RK808_BUCK_VSEL_MASK 0x3f +#define RK808_BUCK4_VSEL_MASK 0xf +#define RK808_LDO_VSEL_MASK 0x1f + +#define RK809_BUCK5_VSEL_MASK 0x7 + +#define RK817_LDO_VSEL_MASK 0x7f +#define RK817_BOOST_VSEL_MASK 0x7 +#define RK817_BUCK_VSEL_MASK 0x7f + +#define RK818_BUCK_VSEL_MASK 0x3f +#define RK818_BUCK4_VSEL_MASK 0x1f +#define RK818_LDO_VSEL_MASK 0x1f +#define RK818_LDO3_ON_VSEL_MASK 0xf +#define RK818_BOOST_ON_VSEL_MASK 0xe0 + +#define RK806_DCDC_SLP_REG_OFFSET 0x0a +#define RK806_NLDO_SLP_REG_OFFSET 0x05 +#define RK806_PLDO_SLP_REG_OFFSET 0x06 + +#define RK806_BUCK_SEL_CNT 0xff +#define RK806_LDO_SEL_CNT 0xff + +/* Ramp rate definitions for buck1 / buck2 only */ +#define RK808_RAMP_RATE_OFFSET 3 +#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) +#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) + +#define RK808_DVS2_POL RT_BIT(2) +#define RK808_DVS1_POL RT_BIT(1) + +/* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */ +#define RK808_SLP_REG_OFFSET 1 +/* Offset from XXX_ON_VSEL to XXX_DVS_VSEL */ +#define RK808_DVS_REG_OFFSET 2 +/* max steps for increase voltage of Buck1/2, equal 100mv*/ +#define MAX_STEPS_ONE_TIME 8 +#define MAX_PIN_NR 2 + +#define ENABLE_MASK(id) (RT_BIT(id) | RT_BIT(4 + (id))) +#define DISABLE_VAL(id) (RT_BIT(4 + (id))) + +struct rk8xx_regulator_range +{ + int min; + int min_sel; + int max_sel; + int step; +}; + +#define RK8XX_REGULATOR_RANGE(UVOLT_MIN, MIN_SEL, MAX_SEL, UVOLT_STEP) \ +{ \ + .min = UVOLT_MIN, \ + .min_sel = MIN_SEL, \ + .max_sel = MAX_SEL, \ + .step = UVOLT_STEP, \ +} + +struct rk8xx_regulator_desc +{ + const char *name; + const char *supply_name; + + const struct rt_regulator_ops *ops; + + int voltages_nr; + int uvolt_min; + int uvolt_step; + + int ranges_nr; + const struct rk8xx_regulator_range *ranges; + + rt_uint32_t vsel_reg; + rt_uint32_t vsel_mask; + rt_uint32_t enable_reg; + rt_uint32_t enable_mask; + rt_uint32_t enable_val; + rt_uint32_t disable_val; +}; + +#define RK8XX_REGULATOR_DESC(NAME, SUPPLY_NAME, \ + OPS, \ + VOLTAGES_NR, UVOLT_MIN, UVOLT_STEP, \ + RANGES_NR, RANGES, \ + VSEL_REG, VSEL_MASK, ENABLE_REG, \ + ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ +{ \ + .name = NAME, \ + .supply_name = SUPPLY_NAME, \ + .ops = &OPS, \ + .voltages_nr = VOLTAGES_NR, \ + .uvolt_min = UVOLT_MIN, \ + .uvolt_step = UVOLT_STEP, \ + .ranges_nr = RANGES_NR, \ + .ranges = RANGES, \ + .vsel_reg = VSEL_REG, \ + .vsel_mask = VSEL_MASK, \ + .enable_reg = ENABLE_REG, \ + .enable_mask = ENABLE_MASK, \ + .enable_val = ENABLE_VAL, \ + .disable_val = DISABLE_VAL, \ +} + +#define RK8XX_REGULATOR_VOLT(NAME, SUPPLY_NAME, OPS, \ + VOLTAGES_NR, UVOLT_MIN, UVOLT_STEP, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ + RK8XX_REGULATOR_DESC(NAME, SUPPLY_NAME, OPS, \ + VOLTAGES_NR, UVOLT_MIN, UVOLT_STEP, \ + 0, RT_NULL, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +#define RK8XX_REGULATOR_VOLT_RANGE(NAME, SUPPLY_NAME, OPS, \ + MIN, MAX, STEP, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ + RK8XX_REGULATOR_DESC(NAME, SUPPLY_NAME, OPS, \ + (((MAX) - (MIN)) / (STEP) + 1), MIN, STEP, \ + 0, RT_NULL, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +#define RK8XX_REGULATOR_VOLT_RANGES(NAME, SUPPLY_NAME, OPS, \ + VOLTAGES_NR, RANGES, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ + RK8XX_REGULATOR_DESC(NAME, SUPPLY_NAME, OPS, \ + VOLTAGES_NR, 0, 0, \ + RT_ARRAY_SIZE(RANGES), RANGES, \ + VSEL_REG, VSEL_MASK, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +#define RK8XX_REGULATOR_SWITCH_DESC(NAME, SUPPLY_NAME, OPS, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) \ + RK8XX_REGULATOR_DESC(NAME, SUPPLY_NAME, OPS, \ + 1, 0, 0, \ + 0, RT_NULL, \ + 0, 0, \ + ENABLE_REG, ENABLE_MASK, ENABLE_VAL, DISABLE_VAL) + +struct rk8xx_regulator +{ + struct rt_regulator_node parent; + struct rt_regulator_param param; + + rt_ubase_t pin; + + struct rt_device device; + struct rk8xx *rk8xx; + struct rt_ofw_node *ofw_node; + + const struct rk8xx_regulator_desc *desc; +}; + +#define raw_to_rk8xx_regulator(raw) rt_container_of(raw, struct rk8xx_regulator, parent) + +static int regulator_voltage_from_selector(struct rk8xx_regulator *rk8xx_reg, + int selector) +{ + int uvolt = -1; + const struct rk8xx_regulator_desc *desc = rk8xx_reg->desc; + + if (desc->ranges_nr) + { + const struct rk8xx_regulator_range *range = &desc->ranges[0]; + + for (int i = desc->ranges_nr - 1; i >= 0; --i, ++range) + { + if (range->min_sel <= selector && range->max_sel >= selector) + { + if (range->min_sel > selector || range->max_sel < selector) + { + return -RT_EINVAL; + } + + uvolt = range->min + (selector - range->min_sel) * range->step; + + break; + } + } + } + else if (desc->voltages_nr) + { + if (selector >= desc->voltages_nr) + { + return -RT_EINVAL; + } + + return desc->uvolt_min + (desc->uvolt_step * selector); + } + else + { + LOG_E("regulator %s-%s voltages info not found", desc->name, desc->supply_name); + } + + return uvolt; +} + +static int regulator_voltage_to_selector(struct rk8xx_regulator *rk8xx_reg, + int min_uvolt, int max_uvolt) +{ + int selector, uvolt; + + /* Allow uvolt_step to be 0 for fixed voltage */ + if (rk8xx_reg->desc->voltages_nr == 1 && rk8xx_reg->desc->uvolt_step == 0) + { + if (min_uvolt <= rk8xx_reg->desc->uvolt_min && rk8xx_reg->desc->uvolt_min <= max_uvolt) + { + return 0; + } + else + { + return -RT_EINVAL; + } + } + + if (!rk8xx_reg->desc->uvolt_step) + { + return -RT_EINVAL; + } + + if (min_uvolt < rk8xx_reg->desc->uvolt_min) + { + min_uvolt = rk8xx_reg->desc->uvolt_min; + } + + selector = RT_DIV_ROUND_UP(min_uvolt - rk8xx_reg->desc->uvolt_min, rk8xx_reg->desc->uvolt_step); + + if (selector < 0) + { + return selector; + } + + /* Map back into a voltage to verify we're still in bounds */ + uvolt = regulator_voltage_from_selector(rk8xx_reg, selector); + + if (uvolt < min_uvolt || uvolt > max_uvolt) + { + return -RT_EINVAL; + } + + return selector; +} + +static rt_err_t rk8xx_regulator_enable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + val = rk8xx_reg->desc->enable_val; + + if (!val) + { + val = rk8xx_reg->desc->enable_mask; + } + + return rk8xx_update_bits(rk8xx_reg->rk8xx, rk8xx_reg->desc->enable_reg, + rk8xx_reg->desc->enable_mask, val); +} + +static rt_err_t rk8xx_regulator_disable(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + val = rk8xx_reg->desc->disable_val; + + return rk8xx_update_bits(rk8xx_reg->rk8xx, rk8xx_reg->desc->enable_reg, + rk8xx_reg->desc->enable_mask, val); +} + +static rt_bool_t rk8xx_regulator_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + val = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->enable_reg); + + if ((rt_err_t)val < 0) + { + return RT_FALSE; + } + + val &= rk8xx_reg->desc->enable_mask; + + if (rk8xx_reg->desc->enable_val) + { + return val == rk8xx_reg->desc->enable_val; + } + + return val != 0; +} + +static rt_err_t rk8xx_regulator_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int selector; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + selector = regulator_voltage_to_selector(rk8xx_reg, min_uvolt, max_uvolt); + + if (selector < 0) + { + return -RT_EINVAL; + } + + selector <<= __rt_ffs(rk8xx_reg->desc->vsel_mask) - 1; + + return rk8xx_update_bits(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg, + rk8xx_reg->desc->vsel_mask, selector); +} + +static int rk8xx_regulator_get_voltage(struct rt_regulator_node *reg_np) +{ + int uvolt; + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + val = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg); + + if ((rt_err_t)val < 0) + { + return val; + } + + val &= rk8xx_reg->desc->vsel_mask; + val >>= __rt_ffs(rk8xx_reg->desc->vsel_mask) - 1; + + uvolt = regulator_voltage_from_selector(rk8xx_reg, val); + + return uvolt < 0 ? -RT_EINVAL : uvolt; +} + +/* wmsk */ +static rt_bool_t rk8xx_regulator_wmsk_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + val = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->enable_reg); + + if ((rt_err_t)val < 0) + { + return RT_FALSE; + } + + val |= rk8xx_reg->desc->enable_mask & 0xf0; + val &= rk8xx_reg->desc->enable_mask; + + if (rk8xx_reg->desc->enable_val) + { + return val == rk8xx_reg->desc->enable_val; + } + + return val != 0; +} + +/* buck */ +static rt_err_t rk8xx_regulator_buck_set_voltage_no_pin(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + rt_err_t err; + int delta_sel, selector; + rt_uint32_t old_sel, tmp, val, mask; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + selector = regulator_voltage_to_selector(rk8xx_reg, min_uvolt, max_uvolt); + + if (selector < 0) + { + return -RT_EINVAL; + } + + val = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg); + + if ((rt_err_t)val < 0) + { + return (rt_err_t)val; + } + + mask = rk8xx_reg->desc->vsel_mask; + tmp = val & ~mask; + old_sel = val & mask; + old_sel >>= __rt_ffs(mask) - 1; + delta_sel = selector - old_sel; + + while (delta_sel > MAX_STEPS_ONE_TIME) + { + old_sel += MAX_STEPS_ONE_TIME; + val = old_sel << (__rt_ffs(mask) - 1); + val |= tmp; + + rk8xx_write(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg, val); + delta_sel = selector - old_sel; + } + + selector <<= __rt_ffs(mask) - 1; + val = tmp | selector; + err = rk8xx_write(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg, val); + + /* wait 1us to make sure the target voltage to be stable */ + rt_hw_us_delay(1); + + return err; +} + +static rt_err_t rk8xx_regulator_buck_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + rt_err_t err; + int selector; + rt_ssize_t gpio_level; + rt_uint32_t reg, old_sel; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + if ((rt_base_t)rk8xx_reg->pin < 0) + { + return rk8xx_regulator_buck_set_voltage_no_pin(reg_np, min_uvolt, max_uvolt); + } + + selector = regulator_voltage_to_selector(rk8xx_reg, min_uvolt, max_uvolt); + + if (selector < 0) + { + return -RT_EINVAL; + } + + reg = rk8xx_reg->desc->vsel_reg; + + gpio_level = rt_pin_read(rk8xx_reg->pin); + + if (gpio_level == 0) + { + reg += RK808_DVS_REG_OFFSET; + old_sel = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg); + } + else + { + old_sel = rk8xx_read(rk8xx_reg->rk8xx, reg + RK808_DVS_REG_OFFSET); + } + + if ((rt_err_t)old_sel < 0) + { + return -RT_EIO; + } + + selector <<= __rt_ffs(rk8xx_reg->desc->vsel_mask) - 1; + selector |= old_sel & ~rk8xx_reg->desc->vsel_mask; + + err = rk8xx_write(rk8xx_reg->rk8xx, reg, selector); + + if (err) + { + return err; + } + + rt_pin_write(rk8xx_reg->pin, !gpio_level); + + return err; +} + +static int rk8xx_regulator_buck_get_voltage(struct rt_regulator_node *reg_np) +{ + int uvolt; + rt_uint32_t val; + struct rk8xx_regulator *rk8xx_reg = raw_to_rk8xx_regulator(reg_np); + + if ((rt_base_t)rk8xx_reg->pin < 0 || rt_pin_read(rk8xx_reg->pin) == 0) + { + return rk8xx_regulator_get_voltage(reg_np); + } + + val = rk8xx_read(rk8xx_reg->rk8xx, rk8xx_reg->desc->vsel_reg + RK808_DVS_REG_OFFSET); + + if ((rt_err_t)val < 0) + { + return (int)val; + } + + val &= rk8xx_reg->desc->vsel_mask; + val >>= __rt_ffs(rk8xx_reg->desc->vsel_mask) - 1; + + uvolt = regulator_voltage_from_selector(rk8xx_reg, val); + + return uvolt < 0 ? -RT_EINVAL : uvolt; +} + +static const struct rt_regulator_ops rk8xx_regulator_ops = +{ + .enable = rk8xx_regulator_enable, + .disable = rk8xx_regulator_disable, + .is_enabled = rk8xx_regulator_is_enabled, + .set_voltage = rk8xx_regulator_set_voltage, + .get_voltage = rk8xx_regulator_get_voltage, +}; + +static const struct rt_regulator_ops rk8xx_regulator_wmsk_ops = +{ + .enable = rk8xx_regulator_enable, + .disable = rk8xx_regulator_disable, + .is_enabled = rk8xx_regulator_wmsk_is_enabled, + .set_voltage = rk8xx_regulator_set_voltage, + .get_voltage = rk8xx_regulator_get_voltage, +}; + +static const struct rt_regulator_ops rk8xx_regulator_buck_ops = +{ + .enable = rk8xx_regulator_enable, + .disable = rk8xx_regulator_disable, + .is_enabled = rk8xx_regulator_is_enabled, + .set_voltage = rk8xx_regulator_buck_set_voltage, + .get_voltage = rk8xx_regulator_buck_get_voltage, +}; + +static const struct rt_regulator_ops rk8xx_regulator_switch_ops = +{ + .enable = rk8xx_regulator_enable, + .disable = rk8xx_regulator_disable, + .is_enabled = rk8xx_regulator_is_enabled, +}; + +static const struct rt_regulator_ops rk8xx_regulator_switch_wmsk_ops = +{ + .enable = rk8xx_regulator_enable, + .disable = rk8xx_regulator_disable, + .is_enabled = rk8xx_regulator_wmsk_is_enabled, +}; + +static const struct rk8xx_regulator_range rk805_buck_1_2_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(712500, 0, 59, 12500), + RK8XX_REGULATOR_RANGE(1800000, 60, 62, 200000), + RK8XX_REGULATOR_RANGE(2300000, 63, 63, 0), +}; + +static const struct rk8xx_regulator_desc rk805_desc[] = +{ + RK8XX_REGULATOR_DESC("DCDC_REG1", "vcc1", rk8xx_regulator_ops, + 64, 0, 0, + RT_ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), rk805_buck_1_2_voltage_ranges, + RK805_BUCK1_ON_VSEL_REG, RK818_BUCK_VSEL_MASK, + RK805_DCDC_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_DESC("DCDC_REG2", "vcc2", rk8xx_regulator_ops, + 64, 0, 0, + RT_ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), rk805_buck_1_2_voltage_ranges, + RK805_BUCK2_ON_VSEL_REG, RK818_BUCK_VSEL_MASK, + RK805_DCDC_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("DCDC_REG3", "vcc3", rk8xx_regulator_switch_ops, + RK805_DCDC_EN_REG, RT_BIT(2), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("DCDC_REG4", "vcc4", rk8xx_regulator_ops, + 800000, 3400000, 100000, + RK805_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK805_DCDC_EN_REG, RT_BIT(3), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG1", "vcc5", rk8xx_regulator_ops, + 800000, 3400000, 100000, + RK805_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK805_LDO_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG2", "vcc5", rk8xx_regulator_ops, + 800000, 3400000, 100000, + RK805_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK805_LDO_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG3", "vcc6", rk8xx_regulator_ops, + 800000, 3400000, 100000, + RK805_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK805_LDO_EN_REG, RT_BIT(2), 0, 0), +}; + +static const struct rk8xx_regulator_range rk806_buck_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(500000, 0, 160, 6250), + RK8XX_REGULATOR_RANGE(1500000, 161, 237, 25000), + RK8XX_REGULATOR_RANGE(3400000, 238, 255, 0), +}; + +static const struct rk8xx_regulator_range rk806_ldo_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(500000, 0, 232, 12500), + RK8XX_REGULATOR_RANGE(3400000, 233, 255, 0), +}; + +static const struct rk8xx_regulator_desc rk806_desc[] = +{ + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg1", "vcc1", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK1_ON_VSEL, 0xff, + RK806_POWER_EN0, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg2", "vcc2", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK2_ON_VSEL, 0xff, + RK806_POWER_EN0, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg3", "vcc3", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK3_ON_VSEL, 0xff, + RK806_POWER_EN0, ENABLE_MASK(2), ENABLE_MASK(2), DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg4", "vcc4", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK4_ON_VSEL, 0xff, + RK806_POWER_EN0, ENABLE_MASK(3), ENABLE_MASK(3), DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg5", "vcc5", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK5_ON_VSEL, 0xff, + RK806_POWER_EN1, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg6", "vcc6", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK6_ON_VSEL, 0xff, + RK806_POWER_EN1, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg7", "vcc7", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK7_ON_VSEL, 0xff, + RK806_POWER_EN1, ENABLE_MASK(2), ENABLE_MASK(2), DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg8", "vcc8", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK8_ON_VSEL, 0xff, + RK806_POWER_EN1, ENABLE_MASK(3), ENABLE_MASK(3), DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg9", "vcc9", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK9_ON_VSEL, 0xff, + RK806_POWER_EN2, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGES("dcdc-reg10", "vcc10", rk8xx_regulator_wmsk_ops, + RK806_BUCK_SEL_CNT, rk806_buck_voltage_ranges, + RK806_BUCK10_ON_VSEL, 0xff, + RK806_POWER_EN2, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + + RK8XX_REGULATOR_VOLT_RANGES("nldo-reg1", "vcc13", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_NLDO1_ON_VSEL, 0xff, + RK806_POWER_EN3, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGES("nldo-reg2", "vcc13", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_NLDO2_ON_VSEL, 0xff, + RK806_POWER_EN3, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGES("nldo-reg3", "vcc13", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_NLDO3_ON_VSEL, 0xff, + RK806_POWER_EN3, ENABLE_MASK(2), ENABLE_MASK(2), DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGES("nldo-reg4", "vcc14", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_NLDO4_ON_VSEL, 0xff, + RK806_POWER_EN3, ENABLE_MASK(3), ENABLE_MASK(3), DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGES("nldo-reg5", "vcc14", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_NLDO5_ON_VSEL, 0xff, + RK806_POWER_EN5, ENABLE_MASK(2), ENABLE_MASK(2), DISABLE_VAL(2)), + + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg1", "vcc11", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO1_ON_VSEL, 0xff, + RK806_POWER_EN4, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg2", "vcc11", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO2_ON_VSEL, 0xff, + RK806_POWER_EN4, ENABLE_MASK(2), ENABLE_MASK(2), DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg3", "vcc11", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO3_ON_VSEL, 0xff, + RK806_POWER_EN4, ENABLE_MASK(3), ENABLE_MASK(3), DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg4", "vcc12", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO4_ON_VSEL, 0xff, + RK806_POWER_EN5, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg5", "vcc12", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO5_ON_VSEL, 0xff, + RK806_POWER_EN5, ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + + RK8XX_REGULATOR_VOLT_RANGES("pldo-reg6", "vcca", rk8xx_regulator_ops, + RK806_LDO_SEL_CNT, rk806_ldo_voltage_ranges, + RK806_PLDO6_ON_VSEL, 0xff, + RK806_POWER_EN4, ENABLE_MASK(0), ENABLE_MASK(0), DISABLE_VAL(0)), +}; + +static const struct rk8xx_regulator_range rk808_ldo3_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(800000, 0, 13, 100000), + RK8XX_REGULATOR_RANGE(2500000, 15, 15, 0), +}; + +static const struct rk8xx_regulator_desc rk808_desc[] = +{ + RK8XX_REGULATOR_VOLT("DCDC_REG1", "vcc1", rk8xx_regulator_buck_ops, + 64, 712500, 12500, + RK808_BUCK1_ON_VSEL_REG, RK808_BUCK_VSEL_MASK, + RK808_DCDC_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_VOLT("DCDC_REG2", "vcc2", rk8xx_regulator_buck_ops, + 64, 712500, 12500, + RK808_BUCK2_ON_VSEL_REG, RK808_BUCK_VSEL_MASK, + RK808_DCDC_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("DCDC_REG3", "vcc3", rk8xx_regulator_switch_ops, + RK808_DCDC_EN_REG, RT_BIT(2), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("DCDC_REG4", "vcc4", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_BUCK4_ON_VSEL_REG, RK808_BUCK4_VSEL_MASK, + RK808_DCDC_EN_REG, RT_BIT(3), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG1", "vcc6", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_LDO1_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG2", "vcc6", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_LDO2_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_DESC("LDO_REG3", "vcc7", rk8xx_regulator_ops, + 16, 0, 0, + RT_ARRAY_SIZE(rk808_ldo3_voltage_ranges), rk808_ldo3_voltage_ranges, + RK808_LDO3_ON_VSEL_REG, RK808_BUCK4_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(2), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG4", "vcc9", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_LDO4_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(3), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG5", "vcc9", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_LDO5_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(4), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG6", "vcc10", rk8xx_regulator_ops, + 800000, 2500000, 100000, + RK808_LDO6_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(5), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG7", "vcc7", rk8xx_regulator_ops, + 800000, 2500000, 100000, + RK808_LDO7_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(6), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG8", "vcc11", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK808_LDO8_ON_VSEL_REG, RK808_LDO_VSEL_MASK, + RK808_LDO_EN_REG, RT_BIT(7), 0, 0), + + RK8XX_REGULATOR_SWITCH_DESC("SWITCH_REG1", "vcc8", rk8xx_regulator_switch_ops, + RK808_DCDC_EN_REG, RT_BIT(5), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("SWITCH_REG2", "vcc12", rk8xx_regulator_switch_ops, + RK808_DCDC_EN_REG, RT_BIT(6), 0, 0), +}; + +#define RK817_BUCK1_MIN0 500000 +#define RK817_BUCK1_MAX0 1500000 + +#define RK817_BUCK1_MIN1 1600000 +#define RK817_BUCK1_MAX1 2400000 + +#define RK817_BUCK3_MAX1 3400000 + +#define RK817_BUCK1_STP0 12500 +#define RK817_BUCK1_STP1 100000 + +#define RK817_BUCK1_SEL0 ((RK817_BUCK1_MAX0 - RK817_BUCK1_MIN0) / RK817_BUCK1_STP0) +#define RK817_BUCK1_SEL1 ((RK817_BUCK1_MAX1 - RK817_BUCK1_MIN1) / RK817_BUCK1_STP1) +#define RK817_BUCK3_SEL1 ((RK817_BUCK3_MAX1 - RK817_BUCK1_MIN1) / RK817_BUCK1_STP1) + +#define RK817_BUCK1_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK1_SEL1 + 1) +#define RK817_BUCK3_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK3_SEL1 + 1) + +static const struct rk8xx_regulator_range rk817_buck1_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(RK817_BUCK1_MIN0, 0, RK817_BUCK1_SEL0, RK817_BUCK1_STP0), + RK8XX_REGULATOR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1, RK817_BUCK1_SEL_CNT, RK817_BUCK1_STP1), +}; + +static const struct rk8xx_regulator_range rk817_buck3_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(RK817_BUCK1_MIN0, 0, RK817_BUCK1_SEL0, RK817_BUCK1_STP0), + RK8XX_REGULATOR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1, RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1), +}; + +#define RK809_BUCK5_SEL_CNT 8 + +static const struct rk8xx_regulator_range rk809_buck5_voltage_ranges[] = +{ + RK8XX_REGULATOR_RANGE(1500000, 0, 0, 0), + RK8XX_REGULATOR_RANGE(1800000, 1, 3, 200000), + RK8XX_REGULATOR_RANGE(2800000, 4, 5, 200000), + RK8XX_REGULATOR_RANGE(3300000, 6, 7, 300000), +}; + +static const struct rk8xx_regulator_desc rk809_desc[] = +{ + RK8XX_REGULATOR_DESC("DCDC_REG1", "vcc1", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK1_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC1), ENABLE_MASK(RK817_ID_DCDC1), DISABLE_VAL(RK817_ID_DCDC1)), + RK8XX_REGULATOR_DESC("DCDC_REG2", "vcc2", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK2_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC2), ENABLE_MASK(RK817_ID_DCDC2), DISABLE_VAL(RK817_ID_DCDC2)), + RK8XX_REGULATOR_DESC("DCDC_REG3", "vcc3", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK3_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC3), ENABLE_MASK(RK817_ID_DCDC3), DISABLE_VAL(RK817_ID_DCDC3)), + RK8XX_REGULATOR_DESC("DCDC_REG4", "vcc4", rk8xx_regulator_wmsk_ops, + RK817_BUCK3_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck3_voltage_ranges), rk817_buck3_voltage_ranges, + RK817_BUCK4_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC4), ENABLE_MASK(RK817_ID_DCDC4), DISABLE_VAL(RK817_ID_DCDC4)), + + RK8XX_REGULATOR_DESC("DCDC_REG5", "vcc9", rk8xx_regulator_wmsk_ops, + RK809_BUCK5_SEL_CNT, 0, 0, + RT_ARRAY_SIZE(rk809_buck5_voltage_ranges), rk809_buck5_voltage_ranges, + RK809_BUCK5_CONFIG(0), RK809_BUCK5_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG1", "vcc5", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG2", "vcc5", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(1), 0, DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG3", "vcc5", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(2), 0, DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG4", "vcc6", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(3), 0, DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG5", "vcc6", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG6", "vcc6", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(1), 0, DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG7", "vcc7", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(2), 0, DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG8", "vcc7", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(3), 0, DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG9", "vcc7", rk8xx_regulator_wmsk_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + + RK8XX_REGULATOR_SWITCH_DESC("SWITCH_REG1", "vcc9", rk8xx_regulator_switch_wmsk_ops, + RK817_POWER_EN_REG(3), ENABLE_MASK(2), 0, DISABLE_VAL(2)), + RK8XX_REGULATOR_SWITCH_DESC("SWITCH_REG2", "vcc8", rk8xx_regulator_switch_wmsk_ops, + RK817_POWER_EN_REG(3), ENABLE_MASK(3), 0, DISABLE_VAL(3)), +}; + +static const struct rk8xx_regulator_desc rk817_desc[] = +{ + RK8XX_REGULATOR_DESC("DCDC_REG1", "vcc1", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK1_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC1), ENABLE_MASK(RK817_ID_DCDC1), DISABLE_VAL(RK817_ID_DCDC1)), + RK8XX_REGULATOR_DESC("DCDC_REG2", "vcc2", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK2_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC2), ENABLE_MASK(RK817_ID_DCDC2), DISABLE_VAL(RK817_ID_DCDC2)), + RK8XX_REGULATOR_DESC("DCDC_REG3", "vcc3", rk8xx_regulator_wmsk_ops, + RK817_BUCK1_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck1_voltage_ranges), rk817_buck1_voltage_ranges, + RK817_BUCK3_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC3), ENABLE_MASK(RK817_ID_DCDC3), DISABLE_VAL(RK817_ID_DCDC3)), + RK8XX_REGULATOR_DESC("DCDC_REG4", "vcc4", rk8xx_regulator_wmsk_ops, + RK817_BUCK3_SEL_CNT + 1, 0, 0, + RT_ARRAY_SIZE(rk817_buck3_voltage_ranges), rk817_buck3_voltage_ranges, + RK817_BUCK4_ON_VSEL_REG, RK817_BUCK_VSEL_MASK, + RK817_POWER_EN_REG(0), ENABLE_MASK(RK817_ID_DCDC4), ENABLE_MASK(RK817_ID_DCDC4), DISABLE_VAL(RK817_ID_DCDC4)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG1", "vcc5", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG2", "vcc5", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(1), 0, DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG3", "vcc5", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(2), 0, DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG4", "vcc6", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(3), 0, DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG5", "vcc6", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG6", "vcc6", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(1), 0, DISABLE_VAL(1)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG7", "vcc7", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(2), 0, DISABLE_VAL(2)), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG8", "vcc7", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(3), 0, DISABLE_VAL(3)), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG9", "vcc7", rk8xx_regulator_ops, + 600000, 3400000, 25000, + RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(0), 0, DISABLE_VAL(0)), + + RK8XX_REGULATOR_VOLT_RANGE("BOOST", "vcc8", rk8xx_regulator_wmsk_ops, + 4700000, 5400000, 100000, + RK817_BOOST_OTG_CFG, RK817_BOOST_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(1), ENABLE_MASK(1), DISABLE_VAL(1)), + RK8XX_REGULATOR_SWITCH_DESC("OTG_SWITCH", "vcc9", rk8xx_regulator_switch_wmsk_ops, + RK817_POWER_EN_REG(3), ENABLE_MASK(2), 0, DISABLE_VAL(2)), +}; + +static const struct rk8xx_regulator_desc rk818_desc[] = +{ + RK8XX_REGULATOR_VOLT("DCDC_REG1", "vcc1", rk8xx_regulator_ops, + 64, 712500, 12500, + RK818_BUCK1_ON_VSEL_REG, RK818_BUCK_VSEL_MASK, + RK818_DCDC_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_VOLT("DCDC_REG2", "vcc2", rk8xx_regulator_ops, + 64, 712500, 12500, + RK818_BUCK2_ON_VSEL_REG, RK818_BUCK_VSEL_MASK, + RK818_DCDC_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("DCDC_REG3", "vcc3", rk8xx_regulator_switch_ops, + RK818_DCDC_EN_REG, RT_BIT(2), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("DCDC_REG4", "vcc4", rk8xx_regulator_ops, + 1800000, 3600000, 100000, + RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK818_DCDC_EN_REG, RT_BIT(3), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("DCDC_BOOST", "boost", rk8xx_regulator_ops, + 4700000, 5400000, 100000, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK, + RK818_DCDC_EN_REG, RT_BIT(4), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG1", "vcc6", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG2", "vcc6", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(1), 0, 0), + RK8XX_REGULATOR_DESC("LDO_REG3", "vcc7", rk8xx_regulator_ops, + 16, 0, 0, + RT_ARRAY_SIZE(rk808_ldo3_voltage_ranges), rk808_ldo3_voltage_ranges, + RK818_LDO3_ON_VSEL_REG, RK818_LDO3_ON_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(2), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG4", "vcc8", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(3), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG5", "vcc7", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(4), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG6", "vcc8", rk8xx_regulator_ops, + 800000, 2500000, 100000, + RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(5), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG7", "vcc7", rk8xx_regulator_ops, + 800000, 2500000, 100000, + RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(6), 0, 0), + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG8", "vcc8", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_LDO_EN_REG, RT_BIT(7), 0, 0), + + RK8XX_REGULATOR_VOLT_RANGE("LDO_REG9", "vcc9", rk8xx_regulator_ops, + 1800000, 3400000, 100000, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_DCDC_EN_REG, RT_BIT(5), 0, 0), + + RK8XX_REGULATOR_SWITCH_DESC("SWITCH_REG", "vcc9", rk8xx_regulator_switch_ops, + RK818_DCDC_EN_REG, RT_BIT(6), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("HDMI_SWITCH", "h_5v", rk8xx_regulator_switch_ops, + RK818_H5V_EN_REG, RT_BIT(0), 0, 0), + RK8XX_REGULATOR_SWITCH_DESC("OTG_SWITCH", "usb", rk8xx_regulator_switch_ops, + RK818_DCDC_EN_REG, RT_BIT(7), 0, 0), +}; + +static rt_err_t append_rk8xx_regulator(struct rk8xx *rk8xx, struct rt_ofw_node *np, + const struct rk8xx_regulator_desc *desc_table, int id) +{ + rt_err_t err = RT_EOK; + struct rt_regulator_node *rgp; + struct rk8xx_regulator *rk8xx_reg; + + rk8xx_reg = rt_calloc(1, sizeof(*rk8xx_reg)); + + if (!rk8xx_reg) + { + return -RT_ENOMEM; + } + + rk8xx_reg->rk8xx = rk8xx; + rk8xx_reg->desc = &desc_table[id]; + + regulator_ofw_parse(np, &rk8xx_reg->param); + + rgp = &rk8xx_reg->parent; + rgp->ops = rk8xx_reg->desc->ops; + rgp->param = &rk8xx_reg->param; + rgp->dev = &rk8xx_reg->device; + + rgp->dev->ofw_node = np; + + if (id < MAX_PIN_NR) + { + rt_uint32_t tmp; + rt_uint8_t mode, value; + + rk8xx_reg->pin = rt_ofw_get_named_pin(rk8xx->dev->ofw_node, + "dvs", id, &mode, &value); + + if ((rt_base_t)rk8xx_reg->pin >= 0) + { + rt_pin_mode(rk8xx_reg->pin, mode); + rt_pin_write(rk8xx_reg->pin, value); + + tmp = id ? RK808_DVS2_POL : RK808_DVS1_POL; + rk8xx_update_bits(rk8xx, RK808_IO_POL_REG, tmp, + rt_pin_read(rk8xx_reg->pin) == PIN_LOW ? 0 : tmp); + } + } + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(rk8xx_reg); + + return err; +} + +static rt_err_t rk8xx_regulator_probe(struct rt_platform_device *pdev) +{ + int desc_nr; + rt_err_t err; + struct rk8xx *rk8xx = pdev->priv; + struct rt_ofw_node *np, *regulators_np = rk8xx->priv; + const struct rk8xx_regulator_desc *desc_table; + + switch (rk8xx->variant) + { + case RK805_ID: + desc_table = rk805_desc; + desc_nr = RT_ARRAY_SIZE(rk805_desc); + break; + + case RK806_ID: + desc_table = rk806_desc; + desc_nr = RT_ARRAY_SIZE(rk806_desc); + break; + + case RK808_ID: + desc_table = rk808_desc; + desc_nr = RT_ARRAY_SIZE(rk808_desc); + break; + + case RK809_ID: + desc_table = rk809_desc; + desc_nr = RT_ARRAY_SIZE(rk809_desc); + break; + + case RK817_ID: + desc_table = rk817_desc; + desc_nr = RT_ARRAY_SIZE(rk817_desc); + break; + + case RK818_ID: + desc_table = rk818_desc; + desc_nr = RT_ARRAY_SIZE(rk818_desc); + break; + + default: + return -RT_ENOSYS; + } + + for (int i = 0; i < desc_nr; ++i) + { + const char *name = desc_table[i].name; + + if (!(np = rt_ofw_get_child_by_tag(regulators_np, name))) + { + continue; + } + + rt_ofw_node_put(np); + + if ((err = append_rk8xx_regulator(rk8xx, np, desc_table, i))) + { + LOG_E("Append RK8XX regulator %s fail error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + + if (err == -RT_ENOMEM) + { + return err; + } + } + } + + return RT_EOK; +} + +static struct rt_platform_driver rk8xx_regulator_driver = +{ + .name = "rk8xx-regulator", + .probe = rk8xx_regulator_probe, +}; + +static int rk8xx_regulator_register(void) +{ + rt_platform_driver_register(&rk8xx_regulator_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(rk8xx_regulator_register); diff --git a/components/drivers/regulator/regulator.c b/components/drivers/regulator/regulator.c new file mode 100644 index 000000000000..50e6acad2d8d --- /dev/null +++ b/components/drivers/regulator/regulator.c @@ -0,0 +1,483 @@ +/* + * 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 + +#define DBG_TAG "rtdm.regulator" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct rt_regulator +{ + struct rt_regulator_node *reg_np; +}; + +static struct rt_spinlock _regulator_lock = { 0 }; + +static void regulator_release(struct ref *r) +{ + struct rt_regulator_node *reg_np = rt_container_of(r, struct rt_regulator_node, ref); + + LOG_E("%s is release", reg_np->supply_name); + + RT_ASSERT(0); +} + +rt_inline struct rt_regulator_node *regulator_get(struct rt_regulator_node *reg_np) +{ + ref_get(®_np->ref); + + return reg_np; +} + +rt_inline void regulator_put(struct rt_regulator_node *reg_np) +{ + ref_put(®_np->ref, ®ulator_release); +} + +rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np) +{ + const struct rt_regulator_param *param; + + if (!reg_np || !reg_np->dev || !reg_np->param || !reg_np->ops) + { + return -RT_EINVAL; + } + + rt_list_init(®_np->list); + rt_list_init(®_np->children_nodes); + rt_list_init(®_np->notifier_nodes); + ref_init(®_np->ref); + + param = reg_np->param; + + reg_np->parent = RT_NULL; + reg_np->is_enabled = param->boot_on || param->always_on; + +#ifdef RT_USING_OFW + if (reg_np->dev->ofw_node) + { + rt_ofw_data(reg_np->dev->ofw_node) = reg_np; + } +#endif /* RT_USING_OFW */ + + return RT_EOK; +} + +rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + + if (!reg_np) + { + return -RT_EINVAL; + } + + rt_spin_lock(&_regulator_lock); + + if (reg_np->is_enabled && + !(reg_np->param->boot_on || reg_np->param->always_on)) + { + err = -RT_EBUSY; + + LOG_E("%s was enabled by consumer", reg_np->supply_name); + + goto _unlock; + } + + if (!rt_list_isempty(®_np->children_nodes) || + ref_read(®_np->ref) > 1) + { + err = -RT_EBUSY; + + goto _unlock; + } + + reg_np->parent = RT_NULL; + rt_list_remove(®_np->list); + +_unlock: + rt_spin_unlock(&_regulator_lock); + + return err; +} + +rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier) +{ + struct rt_regulator_node *reg_np; + + if (!reg || !notifier) + { + return -RT_EINVAL; + } + + rt_spin_lock(&_regulator_lock); + + reg_np = reg->reg_np; + notifier->regulator = reg; + + rt_list_init(¬ifier->list); + rt_list_insert_after(®_np->notifier_nodes, ¬ifier->list); + + rt_spin_unlock(&_regulator_lock); + + return RT_EOK; +} + +rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier) +{ + if (!reg || !notifier) + { + return -RT_EINVAL; + } + + rt_spin_lock(&_regulator_lock); + + rt_list_remove(¬ifier->list); + + rt_spin_unlock(&_regulator_lock); + + return RT_EOK; +} + +static rt_err_t regulator_notifier_call_chain(struct rt_regulator_node *reg_np, + rt_ubase_t msg, void *data) +{ + rt_err_t err = RT_EOK; + struct rt_regulator_notifier *notifier; + rt_list_t *head = ®_np->notifier_nodes; + + if (rt_list_isempty(head)) + { + return err; + } + + rt_list_for_each_entry(notifier, head, list) + { + err = notifier->callback(notifier, msg, data); + + if (err == -RT_EIO) + { + break; + } + } + + return err; +} + +static rt_err_t regulator_enable(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + + if (reg_np->ops->enable) + { + err = reg_np->ops->enable(reg_np); + + if (!err) + { + reg_np->is_enabled = RT_TRUE; + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_ENABLE, RT_NULL); + } + } + + if (!err && reg_np->parent) + { + err = regulator_enable(reg_np->parent); + } + + return err; +} + +rt_err_t rt_regulator_enable(struct rt_regulator *reg) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + if (rt_regulator_is_enabled(reg)) + { + return RT_EOK; + } + + rt_spin_lock(&_regulator_lock); + + err = regulator_enable(reg->reg_np); + + rt_spin_unlock(&_regulator_lock); + + return err; +} + +static rt_err_t regulator_disable(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + + if (reg_np->ops->disable) + { + err = reg_np->ops->disable(reg_np); + + if (!err) + { + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_DISABLE, RT_NULL); + } + } + + if (!err && reg_np->parent) + { + err = regulator_disable(reg_np->parent); + } + + return err; +} + +rt_err_t rt_regulator_disable(struct rt_regulator *reg) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + if (!rt_regulator_is_enabled(reg)) + { + return RT_EOK; + } + + rt_spin_lock(&_regulator_lock); + + err = regulator_disable(reg->reg_np); + + rt_spin_unlock(&_regulator_lock); + + return err; +} + +rt_bool_t rt_regulator_is_enabled(struct rt_regulator *reg) +{ + if (!reg) + { + return -RT_EINVAL; + } + + return reg->reg_np->is_enabled; +} + +static rt_err_t regulator_set_voltage(struct rt_regulator_node *reg_np, int min_uvolt, int max_uvolt) +{ + rt_err_t err = RT_EOK; + + if (reg_np->ops->set_voltage) + { + union rt_regulator_notifier_args args; + + RT_ASSERT(reg_np->ops->get_voltage != RT_NULL); + + args.old_uvolt = reg_np->ops->get_voltage(reg_np); + args.min_uvolt = min_uvolt; + args.max_uvolt = max_uvolt; + + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_VOLTAGE_CHANGE, &args); + + if (!err) + { + err = reg_np->ops->set_voltage(reg_np, min_uvolt, max_uvolt); + } + + if (err) + { + regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR, + (void *)(rt_base_t)args.old_uvolt); + } + } + + if (!err && reg_np->parent) + { + err = regulator_set_voltage(reg_np->parent, min_uvolt, max_uvolt); + } + + return err; +} + +rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt) +{ + const struct rt_regulator_param *param; + + RT_ASSERT(reg != RT_NULL); + + param = reg->reg_np->param; + + if (!param) + { + return RT_FALSE; + } + + return param->min_uvolt <= min_uvolt && param->max_uvolt >= max_uvolt; +} + +rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_spin_lock(&_regulator_lock); + + err = regulator_set_voltage(reg->reg_np, min_uvolt, max_uvolt); + + rt_spin_unlock(&_regulator_lock); + + return err; +} + +int rt_regulator_get_voltage(struct rt_regulator *reg) +{ + int uvolt = RT_REGULATOR_UVOLT_INVALID; + struct rt_regulator_node *reg_np; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_spin_lock(&_regulator_lock); + + reg_np = reg->reg_np; + + if (reg_np->ops->get_voltage) + { + uvolt = reg_np->ops->get_voltage(reg->reg_np); + } + else + { + uvolt = -RT_ENOSYS; + } + + rt_spin_unlock(&_regulator_lock); + + return uvolt; +} + +static void regulator_check_parent(struct rt_regulator_node *reg_np) +{ + if (reg_np->parent) + { + return; + } + else + { + #ifdef RT_USING_OFW + rt_phandle parent_phandle = 0; + struct rt_ofw_node *np = reg_np->dev->ofw_node; + + while (np) + { + if (rt_ofw_prop_read_u32(np, "vin-supply", &parent_phandle)) + { + break; + } + + if (!(np = rt_ofw_find_node_by_phandle(parent_phandle))) + { + break; + } + + if (!(reg_np->parent = rt_ofw_data(np))) + { + LOG_W("%s parent ofw node = %s not init", + reg_np->supply_name, rt_ofw_node_full_name(np)); + + break; + } + + rt_list_insert_after(®_np->parent->children_nodes, ®_np->list); + rt_ofw_node_put(np); + } + #endif + } +} + +struct rt_regulator *rt_regulator_get_optional(struct rt_device *dev, const char *id) +{ + struct rt_regulator *reg = RT_NULL; + struct rt_regulator_node *reg_np = RT_NULL; + + if (!dev || !id) + { + goto _end; + } + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + rt_phandle supply_phandle; + struct rt_ofw_node *np = dev->ofw_node; + char supply_name[64]; + + rt_snprintf(supply_name, sizeof(supply_name), "%s-supply", id); + + if (rt_ofw_prop_read_u32(np, supply_name, &supply_phandle)) + { + goto _end; + } + + if (!(np = rt_ofw_find_node_by_phandle(supply_phandle))) + { + goto _end; + } + + reg_np = rt_ofw_data(np); + } +#endif + + if (!reg_np) + { + goto _end; + } + + rt_spin_lock(&_regulator_lock); + + regulator_check_parent(reg_np); + + rt_spin_unlock(&_regulator_lock); + + reg = rt_calloc(1, sizeof(*reg)); + + if (!reg) + { + goto _end; + } + + reg->reg_np = reg_np; + +_end: + return reg; +} + +void rt_regulator_put(struct rt_regulator *reg) +{ + if (reg) + { + regulator_put(reg->reg_np); + rt_free(reg); + } +} diff --git a/components/drivers/regulator/regulator_dm.c b/components/drivers/regulator/regulator_dm.c new file mode 100644 index 000000000000..d8096c43d301 --- /dev/null +++ b/components/drivers/regulator/regulator_dm.c @@ -0,0 +1,59 @@ +/* + * 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 "regulator_dm.h" + +#ifdef RT_USING_OFW +rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param) +{ + rt_uint32_t pval; + + param->name = rt_ofw_prop_read_raw(np, "regulator-name", RT_NULL); + + if (!rt_ofw_prop_read_u32(np, "regulator-min-microvolt", &pval)) + { + param->min_uvolt = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-max-microvolt", &pval)) + { + param->max_uvolt = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-min-microamp", &pval)) + { + param->min_uamp = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-max-microamp", &pval)) + { + param->max_uamp = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-ramp-delay", &pval)) + { + param->ramp_delay = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-enable-ramp-delay", &pval)) + { + param->enable_delay = pval; + } + + param->enable_active_high = rt_ofw_prop_read_bool(np, "enable-active-high"); + param->boot_on = rt_ofw_prop_read_bool(np, "regulator-boot-on"); + param->always_on = rt_ofw_prop_read_bool(np, "regulator-always-on"); + param->soft_start = rt_ofw_prop_read_bool(np, "regulator-soft-start"); + param->pull_down = rt_ofw_prop_read_bool(np, "regulator-pull-down"); + param->over_current_protection = rt_ofw_prop_read_bool(np, "regulator-over-current-protection"); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/regulator/regulator_dm.h b/components/drivers/regulator/regulator_dm.h new file mode 100644 index 000000000000..207bb1279465 --- /dev/null +++ b/components/drivers/regulator/regulator_dm.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +#ifndef __REGULATOR_DM_H__ +#define __REGULATOR_DM_H__ + +#include +#include + +#ifdef RT_USING_OFW +rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param); +#else +rt_inline rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param); +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +#endif /* __REGULATOR_DM_H__ */ diff --git a/components/drivers/reset/Kconfig b/components/drivers/reset/Kconfig new file mode 100644 index 000000000000..b19646b5cc02 --- /dev/null +++ b/components/drivers/reset/Kconfig @@ -0,0 +1,5 @@ +menuconfig RT_USING_RESET + bool "Using Reset Controller support" + depends on RT_USING_DM + select RT_USING_OFW + default n diff --git a/components/drivers/reset/SConscript b/components/drivers/reset/SConscript new file mode 100755 index 000000000000..23f677874cb4 --- /dev/null +++ b/components/drivers/reset/SConscript @@ -0,0 +1,15 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_RESET']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['reset.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/reset/reset.c b/components/drivers/reset/reset.c new file mode 100644 index 000000000000..b8c1c8c82a7f --- /dev/null +++ b/components/drivers/reset/reset.c @@ -0,0 +1,429 @@ +/* + * 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 "rtdm.reset" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct reset_control_array +{ + struct rt_reset_control captain; + + rt_size_t count; + struct rt_reset_control *rstcs[]; +}; + +#define reset_control_to_array(rstc) rt_container_of(rstc, struct reset_control_array, captain) + +static struct rt_spinlock _rstcer_lock = { 0 }; +static rt_list_t _rstcer_nodes = RT_LIST_OBJECT_INIT(_rstcer_nodes); + +rt_err_t rt_reset_controller_register(struct rt_reset_controller *rstcer) +{ + rt_ubase_t level; + + if (!rstcer) + { + return -RT_EINVAL; + } + + rt_list_init(&rstcer->list); + rt_list_init(&rstcer->rstc_nodes); + rt_spin_lock_init(&rstcer->spinlock); + + level = rt_spin_lock_irqsave(&_rstcer_lock); + + rt_list_insert_after(&_rstcer_nodes, &rstcer->list); + + rt_spin_unlock_irqrestore(&_rstcer_lock, level); + + if (rstcer->ofw_node) + { + if (!rt_ofw_data(rstcer->ofw_node)) + { + rt_ofw_data(rstcer->ofw_node) = rstcer; + } + } + + return RT_EOK; +} + +rt_err_t rt_reset_controller_unregister(struct rt_reset_controller *rstcer) +{ + if (rstcer) + { + rt_spin_lock(&_rstcer_lock); + + rt_list_remove(&rstcer->list); + + rt_spin_unlock(&_rstcer_lock); + + return RT_EOK; + } + + return -RT_EINVAL; +} + +rt_err_t rt_reset_control_reset(struct rt_reset_control *rstc) +{ + rt_err_t err; + + if (!rstc) + { + return -RT_EINVAL; + } + + if (rstc->rstcer->ops->reset) + { + if ((err = rstc->rstcer->ops->reset(rstc))) + { + return err; + } + } + + if (rstc->is_array) + { + struct reset_control_array *rstc_arr = reset_control_to_array(rstc); + + for (int i = 0; i < rstc_arr->count; ++i) + { + if ((err = rt_reset_control_reset(rstc_arr->rstcs[i]))) + { + return err; + } + } + } + + return RT_EOK; +} + +rt_err_t rt_reset_control_assert(struct rt_reset_control *rstc) +{ + rt_err_t err; + + if (!rstc) + { + return -RT_EINVAL; + } + + if (rstc->deassert && rstc->rstcer->ops->assert) + { + if ((err = rstc->rstcer->ops->assert(rstc))) + { + return err; + } + + rstc->deassert = RT_FALSE; + } + + if (rstc->is_array) + { + struct reset_control_array *rstc_arr = reset_control_to_array(rstc); + + for (int i = 0; i < rstc_arr->count; ++i) + { + if ((err = rt_reset_control_assert(rstc_arr->rstcs[i]))) + { + if (rstc->rstcer->ops->deassert) + { + rstc->rstcer->ops->deassert(rstc); + + rstc->deassert = RT_TRUE; + } + + while (i --> 0) + { + rt_reset_control_deassert(rstc_arr->rstcs[i]); + } + + return err; + } + } + } + + return RT_EOK; +} + +rt_err_t rt_reset_control_deassert(struct rt_reset_control *rstc) +{ + rt_err_t err; + + if (!rstc) + { + return -RT_EINVAL; + } + + if (!rstc->deassert && rstc->rstcer->ops->deassert) + { + if ((err = rstc->rstcer->ops->deassert(rstc))) + { + return err; + } + + rstc->deassert = RT_TRUE; + } + + if (rstc->is_array) + { + struct reset_control_array *rstc_arr = reset_control_to_array(rstc); + + for (int i = 0; i < rstc_arr->count; ++i) + { + if ((err = rt_reset_control_deassert(rstc_arr->rstcs[i]))) + { + if (rstc->rstcer->ops->assert) + { + rstc->rstcer->ops->assert(rstc); + + rstc->deassert = RT_FALSE; + } + + while (i --> 0) + { + rt_reset_control_assert(rstc_arr->rstcs[i]); + } + + return err; + } + } + } + + return RT_EOK; +} + +int rt_reset_control_status(struct rt_reset_control *rstc) +{ + if (!rstc) + { + return -RT_EINVAL; + } + + if (rstc->rstcer->ops->status) + { + return rstc->rstcer->ops->status(rstc); + } + + return -RT_ENOSYS; +} + +static void reset_free(struct rt_reset_control *rstc) +{ + if (rstc->is_array) + { + struct reset_control_array *rstc_arr = reset_control_to_array(rstc); + + for (int i = 0; i < rstc_arr->count; ++i) + { + rt_reset_control_put(rstc_arr->rstcs[i]); + } + } + + rt_free(rstc); +} + +struct rt_reset_control *rt_reset_control_get_array(struct rt_device *dev) +{ + return rt_ofw_get_reset_control_array(dev->ofw_node); +} + +struct rt_reset_control *rt_reset_control_get_by_index(struct rt_device *dev, int index) +{ + return rt_ofw_get_reset_control_by_index(dev->ofw_node, index); +} + +struct rt_reset_control *rt_reset_control_get_by_name(struct rt_device *dev, const char *name) +{ + return rt_ofw_get_reset_control_by_name(dev->ofw_node, name); +} + +void rt_reset_control_put(struct rt_reset_control *rstc) +{ + struct rt_reset_controller *rstcer; + + if (!rstc) + { + return; + } + + rstcer = rstc->rstcer; + + rt_spin_lock(&rstcer->spinlock); + + rt_list_remove(&rstc->list); + + rt_spin_unlock(&rstcer->spinlock); + + reset_free(rstc); +} + +static struct rt_reset_control *ofw_get_reset_control(struct rt_ofw_node *np, int index, + const char *name, rt_bool_t is_array) +{ + struct rt_reset_control *rstc; + struct rt_ofw_cell_args reset_args = {}; + struct rt_reset_controller *rstcer = RT_NULL; + + if (is_array) + { + rt_size_t rstc_nr; + struct reset_control_array *rstc_arr; + + rstc_nr = rt_ofw_count_phandle_cells(np, "resets", "#reset-cells"); + + if (!rstc_nr) + { + return RT_NULL; + } + + rstc_arr = rt_calloc(1, sizeof(*rstc_arr) + sizeof(struct rt_reset_control *) * rstc_nr); + + if (!rstc_arr) + { + LOG_E("No memory to create %s[%d] reset control", + rt_ofw_node_full_name(np), index); + + return RT_NULL; + } + + rstc_arr->count = rstc_nr - 1; + + for (int i = 0; i < rstc_arr->count; ++i) + { + rstc_arr->rstcs[i] = ofw_get_reset_control(np, i + 1, RT_NULL, RT_FALSE); + + if (!rstc_arr->rstcs[i]) + { + while (i --> 0) + { + rt_reset_control_put(rstc_arr->rstcs[i]); + } + + rt_free(rstc_arr); + rstc_arr = RT_NULL; + + return RT_NULL; + } + } + + rstc = &rstc_arr->captain; + rstc->is_array = RT_TRUE; + } + else + { + rstc = rt_calloc(1, sizeof(*rstc)); + + if (!rstc) + { + LOG_E("No memory to create %s[%d] reset control", + rt_ofw_node_full_name(np), index); + + return RT_NULL; + } + } + + if (!rt_ofw_parse_phandle_cells(np, "resets", "#reset-cells", index, &reset_args)) + { + void *rt_data = rt_ofw_data(reset_args.data); + + if (rt_data) + { + /* check is clk */ + if (rt_ofw_prop_read_bool(reset_args.data, "#clock-cells")) + { + struct rt_reset_controller_clk_node *rstcer_clk = rt_data; + + rstcer = &rstcer_clk->rstcer; + } + else + { + rstcer = rt_data; + } + } + + rt_ofw_node_put(reset_args.data); + } + + if (!rstcer) + { + goto _fail; + } + + if (!name && rt_ofw_prop_read_bool(np, "reset-names")) + { + rt_ofw_prop_read_string_index(np, "reset-names", index, &name); + } + + rstc->con_id = name; + rstc->rstcer = rstcer; + + if (rstcer->ops->ofw_parse) + { + rt_err_t err = rstcer->ops->ofw_parse(rstc, &reset_args); + + if (err) + { + LOG_E("Parse %s reset control error = %s", + rt_ofw_node_full_name(np), rt_strerror(err)); + + goto _fail; + } + } + + rstc->id = reset_args.args[0]; + + rt_list_init(&rstc->list); + + rt_spin_lock(&rstcer->spinlock); + + rt_list_insert_after(&rstcer->rstc_nodes, &rstc->list); + + rt_spin_unlock(&rstcer->spinlock); + + return rstc; + +_fail: + if (rstc && !rstc->is_array) + { + rt_free(rstc); + } + + return RT_NULL; +} + +struct rt_reset_control *rt_ofw_get_reset_control_array(struct rt_ofw_node *np) +{ + return ofw_get_reset_control(np, 0, RT_NULL, RT_TRUE); +} + +struct rt_reset_control *rt_ofw_get_reset_control_by_index(struct rt_ofw_node *np, int index) +{ + return ofw_get_reset_control(np, index, RT_NULL, RT_FALSE); +} + +struct rt_reset_control *rt_ofw_get_reset_control_by_name(struct rt_ofw_node *np, const char *name) +{ + if (np) + { + int index = rt_ofw_prop_index_of_string(np, "reset-names", name); + + if (index >= 0) + { + return ofw_get_reset_control(np, index, name, RT_FALSE); + } + } + + return RT_NULL; +} diff --git a/components/drivers/rtc/Kconfig b/components/drivers/rtc/Kconfig index 8ebece448656..43e5179d6a67 100755 --- a/components/drivers/rtc/Kconfig +++ b/components/drivers/rtc/Kconfig @@ -12,14 +12,33 @@ menuconfig RT_USING_RTC default n endif +config RT_RTC_GOLDFISH + bool "Goldfish Real Time Clock" + depends on RT_USING_DM + depends on RT_USING_RTC + default n + +config RT_RTC_HYM8563 + bool "Haoyu Microelectronics HYM8563" + depends on RT_USING_DM + depends on RT_USING_RTC + select RT_USING_I2C + default n + config RT_RTC_PL031 bool "ARM PL031" depends on RT_USING_DM depends on RT_USING_RTC default n -config RT_RTC_GOLDFISH - bool "Goldfish Real Time Clock" +config RT_RTC_RK8XX + bool "Rockchip RK805/RK808/RK809/RK817/RK818 RTC" + depends on RT_USING_DM + depends on RT_USING_RTC + depends on RT_MFD_RK8XX + +config RT_RTC_RK_TIMER + bool "Rockchip RTC" depends on RT_USING_DM depends on RT_USING_RTC default n diff --git a/components/drivers/rtc/SConscript b/components/drivers/rtc/SConscript index 572ec85aedf9..b491a4253d63 100644 --- a/components/drivers/rtc/SConscript +++ b/components/drivers/rtc/SConscript @@ -16,12 +16,24 @@ if GetDepend(['RT_USING_ALARM']): if GetDepend(['RT_USING_SOFT_RTC']): src += ['soft_rtc.c'] -if GetDepend(['RT_RTC_PL031']): - src += ['rtc-pl031.c'] +if GetDepend(['RT_USING_DM']): + src += ['rtc_dm.c'] if GetDepend(['RT_RTC_GOLDFISH']): src += ['rtc-goldfish.c'] +if GetDepend(['RT_RTC_HYM8563']): + src += ['rtc-hym8563.c'] + +if GetDepend(['RT_RTC_PL031']): + src += ['rtc-pl031.c'] + +if GetDepend(['RT_RTC_RK8XX']): + src += ['rtc-rk8xx.c'] + +if GetDepend(['RT_RTC_RK_TIMER']): + src += ['rtc-rk_timer.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/rtc/rtc-goldfish.c b/components/drivers/rtc/rtc-goldfish.c index d23594c1b625..d51adb97eebb 100644 --- a/components/drivers/rtc/rtc-goldfish.c +++ b/components/drivers/rtc/rtc-goldfish.c @@ -8,11 +8,7 @@ * 2022-11-26 GuEe-GUI first version */ -#include -#include -#include - -#include +#include "rtc_dm.h" #define GOLDFISH_RTC_TIME_LOW 0x00 /* get low bits of current time and update GOLDFISH_RTC_TIME_HIGH */ #define GOLDFISH_RTC_TIME_HIGH 0x04 /* get high bits of time at last GOLDFISH_RTC_TIME_LOW read */ @@ -67,7 +63,7 @@ static void goldfish_rtc_get_secs(struct goldfish_rtc *grtc, time_t *sec) time |= time_high << 32; } - do_div(time, NSEC_PER_SEC); + rt_do_div(time, NSEC_PER_SEC); rt_memcpy(sec, &time, sizeof(*sec)); } @@ -184,20 +180,27 @@ const static struct rt_device_ops goldfish_rtc_ops = }; #endif -static rt_err_t goldfish_rtc_ofw_init(struct rt_platform_device *pdev, struct goldfish_rtc *grtc) +static rt_err_t goldfish_rtc_probe(struct rt_platform_device *pdev) { rt_err_t err = RT_EOK; - struct rt_ofw_node *np = pdev->parent.ofw_node; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct goldfish_rtc *grtc = rt_calloc(1, sizeof(*grtc)); + + if (!grtc) + { + return -RT_ENOMEM; + } - grtc->base = rt_ofw_iomap(np, 0); + grtc->base = rt_dm_dev_iomap(dev, 0); if (grtc->base) { - grtc->irq = rt_ofw_get_irq(np, 0); + grtc->irq = rt_dm_dev_get_irq(dev, 0); if (grtc->irq >= 0) { - rt_ofw_data(np) = &grtc->parent; + rt_dm_dev_bind_fwdata(dev, RT_NULL, &grtc->parent); } else { @@ -209,23 +212,6 @@ static rt_err_t goldfish_rtc_ofw_init(struct rt_platform_device *pdev, struct go err = -RT_EIO; } - return err; -} - -static rt_err_t goldfish_rtc_probe(struct rt_platform_device *pdev) -{ - rt_err_t err = RT_EOK; - struct goldfish_rtc *grtc = rt_calloc(1, sizeof(*grtc)); - - if (grtc) - { - err = goldfish_rtc_ofw_init(pdev, grtc); - } - else - { - err = -RT_ENOMEM; - } - if (!err) { grtc->parent.type = RT_Device_Class_RTC; @@ -235,13 +221,20 @@ static rt_err_t goldfish_rtc_probe(struct rt_platform_device *pdev) grtc->parent.control = goldfish_rtc_control; #endif - rt_device_register(&grtc->parent, "rtc", RT_DEVICE_FLAG_RDWR); + rtc_dev_set_name(&grtc->parent); + dev_name = rt_dm_dev_get_name(&grtc->parent); + rt_device_register(&grtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); rt_hw_interrupt_install(grtc->irq, goldfish_rtc_isr, grtc, "rtc-goldfish"); rt_hw_interrupt_umask(grtc->irq); } else { + if (grtc->base) + { + rt_iounmap(grtc->base); + } + rt_free(grtc); } diff --git a/components/drivers/rtc/rtc-hym8563.c b/components/drivers/rtc/rtc-hym8563.c new file mode 100644 index 000000000000..f5b6994209f8 --- /dev/null +++ b/components/drivers/rtc/rtc-hym8563.c @@ -0,0 +1,573 @@ +/* + * 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 "rtc_dm.h" + +#define DBG_TAG "rtc.hym8563" +#define DBG_LVL DBG_INFO +#include + +#define HYM8563_CTL1 0x00 +#define HYM8563_CTL1_TEST RT_BIT(7) +#define HYM8563_CTL1_STOP RT_BIT(5) +#define HYM8563_CTL1_TESTC RT_BIT(3) + +#define HYM8563_CTL2 0x01 +#define HYM8563_CTL2_TI_TP RT_BIT(4) +#define HYM8563_CTL2_AF RT_BIT(3) +#define HYM8563_CTL2_TF RT_BIT(2) +#define HYM8563_CTL2_AIE RT_BIT(1) +#define HYM8563_CTL2_TIE RT_BIT(0) + +#define HYM8563_SEC 0x02 +#define HYM8563_SEC_VL RT_BIT(7) +#define HYM8563_SEC_MASK 0x7f + +#define HYM8563_MIN 0x03 +#define HYM8563_MIN_MASK 0x7f + +#define HYM8563_HOUR 0x04 +#define HYM8563_HOUR_MASK 0x3f + +#define HYM8563_DAY 0x05 +#define HYM8563_DAY_MASK 0x3f + +#define HYM8563_WEEKDAY 0x06 +#define HYM8563_WEEKDAY_MASK 0x07 + +#define HYM8563_MONTH 0x07 +#define HYM8563_MONTH_CENTURY RT_BIT(7) +#define HYM8563_MONTH_MASK 0x1f + +#define HYM8563_YEAR 0x08 + +#define HYM8563_ALM_MIN 0x09 +#define HYM8563_ALM_HOUR 0x0a +#define HYM8563_ALM_DAY 0x0b +#define HYM8563_ALM_WEEK 0x0c + +/* Each alarm check can be disabled by setting this bit in the register */ +#define HYM8563_ALM_BIT_DISABLE RT_BIT(7) + +#define HYM8563_CLKOUT 0x0d +#define HYM8563_CLKOUT_ENABLE RT_BIT(7) +#define HYM8563_CLKOUT_32768 0 +#define HYM8563_CLKOUT_1024 1 +#define HYM8563_CLKOUT_32 2 +#define HYM8563_CLKOUT_1 3 +#define HYM8563_CLKOUT_MASK 3 + +#define HYM8563_TMR_CTL 0x0e +#define HYM8563_TMR_CTL_ENABLE RT_BIT(7) +#define HYM8563_TMR_CTL_4096 0 +#define HYM8563_TMR_CTL_64 1 +#define HYM8563_TMR_CTL_1 2 +#define HYM8563_TMR_CTL_1_60 3 +#define HYM8563_TMR_CTL_MASK 3 + +#define HYM8563_TMR_CNT 0x0f + +struct hym8563_rtc +{ + struct rt_device parent; + + int irq; + struct rt_i2c_client *client; + struct rt_thread *irq_thread; + + struct rt_rtc_wkalarm wkalarm; +}; + +#define raw_to_hym8563_rtc(raw) rt_container_of(raw, struct hym8563_rtc, parent) + +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; +} + +static rt_int32_t i2c_smbus_write_byte_data(struct rt_i2c_client *client, + rt_uint8_t command, rt_uint8_t value) +{ + rt_int32_t res; + struct rt_i2c_msg msg[1]; + rt_uint8_t data[2] = { command, value }; + + msg[0].buf = data; + msg[0].addr = client->client_addr; + msg[0].len = 2; + msg[0].flags = RT_I2C_WR; + + res = rt_i2c_transfer(client->bus, msg, 1); + + return res == 1 ? 0 : res; +} + +/* Returns the number of read bytes */ +static rt_int32_t i2c_smbus_read_i2c_block_data(struct rt_i2c_client *client, + rt_uint8_t command, rt_uint8_t length, rt_uint8_t *values) +{ + 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 = values; + msg[1].addr = client->client_addr; + msg[1].len = length; + msg[1].flags = RT_I2C_RD; + + return rt_i2c_transfer(client->bus, msg, 2); +} + +static rt_int32_t i2c_smbus_write_i2c_block_data(struct rt_i2c_client *client, + rt_uint8_t command, rt_uint8_t length, const rt_uint8_t *values) +{ + rt_uint8_t data[32]; + struct rt_i2c_msg msg[1]; + + length = rt_min_t(rt_uint8_t, length, RT_ARRAY_SIZE(data) - 1); + + data[0] = command; + rt_memcpy(&data[1], values, length); + + msg[0].buf = data; + msg[0].addr = client->client_addr; + msg[0].len = length + 1; + msg[0].flags = RT_I2C_WR; + + return rt_i2c_transfer(client->bus, msg, 1); +} + +static void hym8563_rtc_read_time(struct hym8563_rtc *hym8563, time_t *sec) +{ + struct tm tm; + rt_uint8_t buf[7]; + + if (i2c_smbus_read_i2c_block_data(hym8563->client, HYM8563_SEC, 7, buf) < 0) + { + return; + } + + if (buf[0] & HYM8563_SEC_VL) + { + LOG_D("no valid clock/calendar values available"); + } + + tm.tm_sec = rt_bcd2bin(buf[0] & HYM8563_SEC_MASK); + tm.tm_min = rt_bcd2bin(buf[1] & HYM8563_MIN_MASK); + tm.tm_hour = rt_bcd2bin(buf[2] & HYM8563_HOUR_MASK); + tm.tm_mday = rt_bcd2bin(buf[3] & HYM8563_DAY_MASK); + tm.tm_wday = rt_bcd2bin(buf[4] & HYM8563_WEEKDAY_MASK); /* 0 = Sun */ + tm.tm_mon = rt_bcd2bin(buf[5] & HYM8563_MONTH_MASK) - 1; /* 0 = Jan */ + tm.tm_year = rt_bcd2bin(buf[6]) + 100; + + *sec = timegm(&tm); +} + +static void hym8563_rtc_set_time(struct hym8563_rtc *hym8563, time_t *sec) +{ + struct tm *tm; + rt_uint8_t buf[7]; + struct rt_i2c_client *client = hym8563->client; + + tm = localtime(sec); + + /* Years >= 2100 are to far in the future, 19XX is to early */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + { + return; + } + + buf[0] = rt_bin2bcd(tm->tm_sec); + buf[1] = rt_bin2bcd(tm->tm_min); + buf[2] = rt_bin2bcd(tm->tm_hour); + buf[3] = rt_bin2bcd(tm->tm_mday); + buf[4] = rt_bin2bcd(tm->tm_wday); + buf[5] = rt_bin2bcd(tm->tm_mon + 1); + + /* + * While the HYM8563 has a century flag in the month register, + * it does not seem to carry it over a subsequent write/read. + * So we'll limit ourself to 100 years, starting at 2000 for now. + */ + buf[6] = rt_bin2bcd(tm->tm_year - 100); + + /* CTL1 only contains TEST-mode bits apart from stop, so no need to read the value first */ + if (i2c_smbus_write_byte_data(client, HYM8563_CTL1, HYM8563_CTL1_STOP) < 0) + { + return; + } + + if (i2c_smbus_write_i2c_block_data(client, HYM8563_SEC, 7, buf) < 0) + { + return; + } + + if (i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0) < 0) + { + return; + } +} + +static int hym8563_rtc_alarm_irq_enable(struct hym8563_rtc *hym8563, rt_bool_t enabled) +{ + int data; + struct rt_i2c_client *client = hym8563->client; + + data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + + if (data < 0) + { + return data; + } + + if (enabled) + { + data |= HYM8563_CTL2_AIE; + } + else + { + data &= ~HYM8563_CTL2_AIE; + } + + return i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); +}; + +static int hym8563_rtc_read_alarm(struct hym8563_rtc *hym8563, + struct rt_rtc_wkalarm *alarm) +{ + int res; + rt_uint8_t buf[4]; + struct rt_i2c_client *client = hym8563->client; + + *alarm = hym8563->wkalarm; + + res = i2c_smbus_read_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); + + if (res < 0) + { + return res; + } + + /* The alarm only has a minute accuracy */ + alarm->tm_sec = 0; + alarm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ? + -1 : rt_bcd2bin(buf[0] & HYM8563_MIN_MASK); + alarm->tm_hour = (buf[1] & HYM8563_ALM_BIT_DISABLE) ? + -1 : rt_bcd2bin(buf[1] & HYM8563_HOUR_MASK); + + res = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + + if (res < 0) + { + return res; + } + + alarm->enable = res & HYM8563_CTL2_AIE ? RT_TRUE : RT_FALSE; + + return 0; +} + +static int hym8563_rtc_set_alarm(struct hym8563_rtc *hym8563, + struct rt_rtc_wkalarm *alarm) +{ + int res; + rt_uint8_t buf[4]; + struct rt_i2c_client *client = hym8563->client; + struct rt_rtc_wkalarm *wkalarm = &hym8563->wkalarm; + + res = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + + if (res < 0) + { + return res; + } + + res &= ~HYM8563_CTL2_AIE; + + res = i2c_smbus_write_byte_data(client, HYM8563_CTL2, res); + + if (res < 0) + { + return res; + } + + buf[0] = (alarm->tm_min < 60 && alarm->tm_min >= 0) ? + rt_bin2bcd(alarm->tm_min) : HYM8563_ALM_BIT_DISABLE; + buf[1] = (alarm->tm_hour < 24 && alarm->tm_hour >= 0) ? + rt_bin2bcd(alarm->tm_hour) : HYM8563_ALM_BIT_DISABLE; + buf[2] = HYM8563_ALM_BIT_DISABLE; + buf[3] = HYM8563_ALM_BIT_DISABLE; + + res = i2c_smbus_write_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); + + if (res < 0) + { + return res; + } + + res = hym8563_rtc_alarm_irq_enable(hym8563, alarm->enable); + + if (!(res < 0)) + { + wkalarm->enable = alarm->enable; + wkalarm->tm_hour = alarm->tm_hour; + wkalarm->tm_min = alarm->tm_min; + wkalarm->tm_sec = alarm->tm_sec; + } + + return res; +} + +static rt_err_t hym8563_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct hym8563_rtc *hym8563 = raw_to_hym8563_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + hym8563_rtc_read_time(hym8563, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + hym8563_rtc_set_time(hym8563, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + hym8563_rtc_read_time(hym8563, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + hym8563_rtc_set_time(hym8563, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + err = hym8563_rtc_read_alarm(hym8563, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + err = hym8563_rtc_set_alarm(hym8563, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops hym8563_rtc_ops = +{ + .control = hym8563_rtc_control, +}; +#endif + +static void hym8563_rtc_thread_isr(void *param) +{ + int data, res; + struct hym8563_rtc *hym8563 = param; + struct rt_i2c_client *client = hym8563->client; + + while (RT_TRUE) + { + rt_thread_suspend(hym8563->irq_thread); + rt_schedule(); + + data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + + if (data < 0) + { + LOG_E("IRQ: error %sing i2c data %d", "read", data); + + return; + } + + data &= ~HYM8563_CTL2_AF; + + res = i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); + + if (res < 0) + { + LOG_E("IRQ: error %sing i2c data %d", "writ", res); + + return; + } + + rt_alarm_update(&hym8563->parent, 1); + } +} + +static void hym8563_rtc_isr(int irqno, void *param) +{ + struct hym8563_rtc *hym8563 = param; + + rt_thread_resume(hym8563->irq_thread); +} + +static rt_err_t hym8563_init_device(struct rt_i2c_client *client) +{ + int res; + + /* Clear stop flag if present */ + res = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); + if (res < 0) + { + return res; + } + + res = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (res < 0) + { + return res; + } + + /* Disable alarm and timer interrupts */ + res &= ~HYM8563_CTL2_AIE; + res &= ~HYM8563_CTL2_TIE; + + /* Clear any pending alarm and timer flags */ + if (res & HYM8563_CTL2_AF) + { + res &= ~HYM8563_CTL2_AF; + } + + if (res & HYM8563_CTL2_TF) + { + res &= ~HYM8563_CTL2_TF; + } + + res &= ~HYM8563_CTL2_TI_TP; + + return i2c_smbus_write_byte_data(client, HYM8563_CTL2, res); +} + +static rt_err_t hym8563_rtc_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_int32_t res; + const char *dev_name; + struct rt_device *dev = &client->parent; + struct hym8563_rtc *hym8563 = rt_calloc(1, sizeof(*hym8563)); + + if (!hym8563) + { + return -RT_ENOMEM; + } + + if ((res = hym8563_init_device(client)) < 0) + { + err = res; + + goto _fail; + } + + hym8563->irq = rt_dm_dev_get_irq(dev, 0); + hym8563->client = client; + + /* check state of calendar information */ + if ((res = i2c_smbus_read_byte_data(client, HYM8563_SEC)) < 0) + { + err = res; + + goto _fail; + } + + LOG_D("rtc information is %s", (res & HYM8563_SEC_VL) ? "invalid" : "valid"); + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + hym8563->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + hym8563->parent.ops = &hym8563_rtc_ops; +#else + hym8563->parent.control = hym8563_rtc_control; +#endif + + rtc_dev_set_name(&hym8563->parent); + dev_name = rt_dm_dev_get_name(&hym8563->parent); + rt_device_register(&hym8563->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + if (hym8563->irq >= 0) + { + hym8563->irq_thread = rt_thread_create("rtc-hym8563", &hym8563_rtc_thread_isr, + hym8563, SYSTEM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!hym8563->irq_thread) + { + err = -RT_ERROR; + LOG_E("Create RTC IRQ thread fail"); + goto _fail; + } + + rt_thread_startup(hym8563->irq_thread); + + rt_hw_interrupt_install(hym8563->irq, hym8563_rtc_isr, hym8563, "rtc-hym8563"); + rt_hw_interrupt_umask(hym8563->irq); + } + + return RT_EOK; + +_fail: + if (hym8563->irq_thread) + { + rt_thread_delete(hym8563->irq_thread); + } + rt_free(hym8563); + + return err; +} + +static const struct rt_i2c_device_id hym8563_rtc_ids[] = +{ + { .name = "hym8563" }, + { /* sentinel */ }, +}; + +static const struct rt_ofw_node_id hym8563_rtc_ofw_ids[] = +{ + { .compatible = "haoyu,hym8563" }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver hym8563_rtc_driver = +{ + .ids = hym8563_rtc_ids, + .ofw_ids = hym8563_rtc_ofw_ids, + + .probe = hym8563_rtc_probe, +}; +RT_I2C_DRIVER_EXPORT(hym8563_rtc_driver); diff --git a/components/drivers/rtc/rtc-pl031.c b/components/drivers/rtc/rtc-pl031.c index 25cc9a4bf87b..3ccb4767b4c4 100755 --- a/components/drivers/rtc/rtc-pl031.c +++ b/components/drivers/rtc/rtc-pl031.c @@ -8,11 +8,7 @@ * 2022-11-26 GuEe-GUI first version */ -#include -#include -#include - -#include +#include "rtc_dm.h" #define PL031_DR 0x00 /* data read register */ #define PL031_MR 0x04 /* match register */ @@ -34,6 +30,7 @@ struct pl031 int irq; void *base; + struct rt_clk *pclk; struct rt_rtc_wkalarm wkalarm; }; @@ -186,68 +183,83 @@ const static struct rt_device_ops pl031_rtc_ops = }; #endif -static rt_err_t pl031_ofw_init(struct rt_platform_device *pdev, struct pl031 *pl031) +static rt_err_t pl031_probe(struct rt_platform_device *pdev) { rt_err_t err = RT_EOK; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - pl031->base = rt_ofw_iomap(np, 0); + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct pl031 *pl031 = rt_calloc(1, sizeof(*pl031)); - if (pl031->base) + if (!pl031) { - pl031->irq = rt_ofw_get_irq(np, 0); - - if (pl031->irq >= 0) - { - rt_ofw_data(np) = &pl031->parent; - } - else - { - err = -RT_ERROR; - } + return -RT_ENOMEM; } - else + + pl031->base = rt_dm_dev_iomap(dev, 0); + + if (!pl031->base) { err = -RT_EIO; + + goto _fail; } - return err; -} + pl031->irq = rt_dm_dev_get_irq(dev, 0); -static rt_err_t pl031_probe(struct rt_platform_device *pdev) -{ - rt_err_t err = RT_EOK; - struct pl031 *pl031 = rt_calloc(1, sizeof(*pl031)); + if (pl031->irq < 0) + { + err = pl031->irq; + + goto _fail; + } - if (pl031) + pl031->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!pl031->pclk) { - err = pl031_ofw_init(pdev, pl031); + err = -RT_EIO; + + goto _fail; } - else + + if ((err = rt_clk_prepare_enable(pl031->pclk))) { - err = -RT_ENOMEM; + goto _fail; } - if (!err) + rt_dm_dev_bind_fwdata(dev, RT_NULL, &pl031->parent); + + pl031->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + pl031->parent.ops = &pl031_rtc_ops; +#else + pl031->parent.init = pl031_init; + pl031->parent.control = pl031_control; +#endif + + rtc_dev_set_name(&pl031->parent); + dev_name = rt_dm_dev_get_name(&pl031->parent); + rt_device_register(&pl031->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + rt_hw_interrupt_install(pl031->irq, pl031_isr, pl031, "rtc-pl031"); + rt_hw_interrupt_umask(pl031->irq); + + return RT_EOK; + +_fail: + if (pl031->base) { - pl031->parent.type = RT_Device_Class_RTC; - #ifdef RT_USING_DEVICE_OPS - pl031->parent.ops = &pl031_rtc_ops; - #else - pl031->parent.init = pl031_init; - pl031->parent.control = pl031_control; - #endif - - rt_device_register(&pl031->parent, "rtc", RT_DEVICE_FLAG_RDWR); - - rt_hw_interrupt_install(pl031->irq, pl031_isr, pl031, "rtc-pl031"); - rt_hw_interrupt_umask(pl031->irq); + rt_iounmap(pl031->base); } - else + + if (pl031->pclk) { - rt_free(pl031); + rt_clk_disable_unprepare(pl031->pclk); + rt_clk_put(pl031->pclk); } + rt_free(pl031); + return err; } diff --git a/components/drivers/rtc/rtc-rk8xx.c b/components/drivers/rtc/rtc-rk8xx.c new file mode 100644 index 000000000000..e232b6ab52f0 --- /dev/null +++ b/components/drivers/rtc/rtc-rk8xx.c @@ -0,0 +1,436 @@ +/* + * 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 "rtc.rk8xx" +#define DBG_LVL DBG_INFO +#include + +#include "rtc_dm.h" +#include "../mfd/rk8xx.h" + +#define BIT_RTC_CTRL_REG_STOP_RTC_M RT_BIT(0) +#define BIT_RTC_CTRL_REG_RTC_GET_TIME RT_BIT(6) +#define BIT_RTC_CTRL_REG_RTC_READSEL_M RT_BIT(7) +#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M RT_BIT(3) + +#define RTC_STATUS_MASK 0xfe +#define SECONDS_REG_MSK 0x7f +#define MINUTES_REG_MAK 0x7f +#define HOURS_REG_MSK 0x3f +#define DAYS_REG_MSK 0x3f +#define MONTHS_REG_MSK 0x1f +#define YEARS_REG_MSK 0xff +#define WEEKS_REG_MSK 0x7 + +#define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1) +#define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1) + +struct rk_rtc_compat_reg +{ + rt_uint32_t ctrl_reg; + rt_uint32_t status_reg; + rt_uint32_t alarm_seconds_reg; + rt_uint32_t int_reg; + rt_uint32_t seconds_reg; +}; + +struct rk8xx_rtc +{ + struct rt_device parent; + + int irq; + struct rk8xx *rk8xx; + struct rk_rtc_compat_reg *creg; + struct rt_thread *irq_thread; +}; + +#define raw_to_rk8xx_rtc(raw) rt_container_of(raw, struct rk8xx_rtc, parent) + +static rt_err_t rk8xx_rtc_read_time(struct rk8xx_rtc *rk8xx_rtc, time_t *sec) +{ + rt_err_t err; + struct tm tm; + struct rk8xx *rk8xx; + rt_uint32_t ctrl_reg, seconds_reg; + rt_uint8_t rtc_data[NUM_TIME_REGS]; + + rk8xx = rk8xx_rtc->rk8xx; + ctrl_reg = rk8xx_rtc->creg->ctrl_reg; + seconds_reg = rk8xx_rtc->creg->seconds_reg; + + err = rk8xx_update_bits(rk8xx, ctrl_reg, BIT_RTC_CTRL_REG_RTC_GET_TIME, + BIT_RTC_CTRL_REG_RTC_GET_TIME); + + if (err) + { + LOG_E("Update RTC control error = %s", rt_strerror(err)); + + return err; + } + + err = rk8xx_update_bits(rk8xx, ctrl_reg, BIT_RTC_CTRL_REG_RTC_GET_TIME, 0); + + if (err) + { + LOG_E("Update RTC control error = %s", rt_strerror(err)); + + return err; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rtc_data); ++i) + { + rtc_data[i] = rk8xx_read(rk8xx, seconds_reg + i * sizeof(rt_uint8_t)); + } + + tm.tm_sec = rt_bcd2bin(rtc_data[0] & SECONDS_REG_MSK); + tm.tm_min = rt_bcd2bin(rtc_data[1] & MINUTES_REG_MAK); + tm.tm_hour = rt_bcd2bin(rtc_data[2] & HOURS_REG_MSK); + tm.tm_mday = rt_bcd2bin(rtc_data[3] & DAYS_REG_MSK); + tm.tm_mon = (rt_bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; + tm.tm_year = (rt_bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; + tm.tm_wday = rt_bcd2bin(rtc_data[6] & WEEKS_REG_MSK); + + *sec = mktime(&tm); + + return RT_EOK; +} + +static rt_err_t rk8xx_rtc_set_time(struct rk8xx_rtc *rk8xx_rtc, time_t *sec) +{ + rt_err_t err; + struct tm *tm; + struct rk8xx *rk8xx; + rt_uint32_t ctrl_reg, seconds_reg; + rt_uint8_t rtc_data[NUM_TIME_REGS]; + + rk8xx = rk8xx_rtc->rk8xx; + ctrl_reg = rk8xx_rtc->creg->ctrl_reg; + seconds_reg = rk8xx_rtc->creg->seconds_reg; + + tm = localtime(sec); + rtc_data[0] = rt_bin2bcd(tm->tm_sec); + rtc_data[1] = rt_bin2bcd(tm->tm_min); + rtc_data[2] = rt_bin2bcd(tm->tm_hour); + rtc_data[3] = rt_bin2bcd(tm->tm_mday); + rtc_data[4] = rt_bin2bcd(tm->tm_mon + 1); + rtc_data[5] = rt_bin2bcd(tm->tm_year - 100); + rtc_data[6] = rt_bin2bcd(tm->tm_wday); + + err = rk8xx_update_bits(rk8xx, ctrl_reg, BIT_RTC_CTRL_REG_STOP_RTC_M, + BIT_RTC_CTRL_REG_STOP_RTC_M); + + if (err) + { + LOG_E("Update RTC control error = %s", rt_strerror(err)); + + return err; + } + + for (int i = 0; i < RT_ARRAY_SIZE(rtc_data); ++i) + { + err = rk8xx_write(rk8xx, seconds_reg + i * sizeof(rt_uint8_t), rtc_data[i]); + + if (err) + { + LOG_E("Update RTC time[%d] error = %s", i, rt_strerror(err)); + + return err; + } + } + + err = rk8xx_update_bits(rk8xx, ctrl_reg, BIT_RTC_CTRL_REG_STOP_RTC_M, 0); + + if (err) + { + LOG_E("Update RTC control error = %s", rt_strerror(err)); + + return err; + } + + return RT_EOK; +} + +static void rk8xx_rtc_read_alarm(struct rk8xx_rtc *rk8xx_rtc, + struct rt_rtc_wkalarm *alarm) +{ + struct rk8xx *rk8xx; + rt_uint8_t alrm_data[NUM_ALARM_REGS]; + rt_uint32_t int_reg, alarm_seconds_reg; + + rk8xx = rk8xx_rtc->rk8xx; + int_reg = rk8xx_rtc->creg->int_reg; + alarm_seconds_reg = rk8xx_rtc->creg->alarm_seconds_reg; + + for (int i = 0; i < 3; ++i) + { + alrm_data[i] = rk8xx_read(rk8xx, alarm_seconds_reg + i * sizeof(rt_uint8_t)); + } + + alarm->tm_sec = rt_bcd2bin(alrm_data[0] & SECONDS_REG_MSK); + alarm->tm_min = rt_bcd2bin(alrm_data[1] & MINUTES_REG_MAK); + alarm->tm_hour = rt_bcd2bin(alrm_data[2] & HOURS_REG_MSK); + + alarm->enable = !!(rk8xx_read(rk8xx, int_reg) & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); +} + +static rt_err_t rk8xx_rtc_set_alarm(struct rk8xx_rtc *rk8xx_rtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_err_t err; + struct rk8xx *rk8xx; + rt_uint32_t int_reg, alarm_seconds_reg; + rt_uint8_t alrm_data[NUM_ALARM_REGS]; + + rk8xx = rk8xx_rtc->rk8xx; + int_reg = rk8xx_rtc->creg->int_reg; + alarm_seconds_reg = rk8xx_rtc->creg->alarm_seconds_reg; + + err = rk8xx_update_bits(rk8xx, int_reg, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0); + + if (err) + { + LOG_E("%s RTC alarm error = %s", "Stop", rt_strerror(err)); + + return err; + } + + alrm_data[0] = rt_bin2bcd(alarm->tm_sec); + alrm_data[1] = rt_bin2bcd(alarm->tm_min); + alrm_data[2] = rt_bin2bcd(alarm->tm_hour); + + for (int i = 0; i < RT_ARRAY_SIZE(alrm_data); ++i) + { + err = rk8xx_write(rk8xx, alarm_seconds_reg + i * sizeof(rt_uint8_t), + alrm_data[i]); + + if (err) + { + LOG_E("Update RTC alarm time[%d] error = %s", i, rt_strerror(err)); + + return err; + } + } + + if (alarm->enable) + { + err = rk8xx_update_bits(rk8xx, int_reg, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + + if (err) + { + LOG_E("%s RTC alarm error = %s", "Start", rt_strerror(err)); + + return err; + } + } + + return RT_EOK; +} + +static rt_err_t rk8xx_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rk8xx_rtc *rk8xx_rtc = raw_to_rk8xx_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + err = rk8xx_rtc_read_time(rk8xx_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + err = rk8xx_rtc_set_time(rk8xx_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + err = rk8xx_rtc_read_time(rk8xx_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + err = rk8xx_rtc_set_time(rk8xx_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + rk8xx_rtc_read_alarm(rk8xx_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + rk8xx_rtc_set_alarm(rk8xx_rtc, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops rk8xx_rtc_ops = +{ + .control = rk8xx_rtc_control, +}; +#endif + +static void rk8xx_rtc_thread_isr(void *param) +{ + rt_err_t err; + struct rk8xx_rtc *rk8xx_rtc = param; + + while (RT_TRUE) + { + rt_thread_suspend(rk8xx_rtc->irq_thread); + rt_schedule(); + + err = rk8xx_write(rk8xx_rtc->rk8xx, rk8xx_rtc->creg->status_reg, + RTC_STATUS_MASK); + + if (err) + { + LOG_E("Update RTC status error = %s", rt_strerror(err)); + + continue; + } + + rt_alarm_update(&rk8xx_rtc->parent, 1); + } +} + +static void rk8xx_rtc_isr(int irqno, void *param) +{ + struct rk8xx_rtc *rk8xx_rtc = param; + + rt_thread_resume(rk8xx_rtc->irq_thread); +} + +static struct rk_rtc_compat_reg rk808_creg = +{ + .ctrl_reg = RK808_RTC_CTRL_REG, + .status_reg = RK808_RTC_STATUS_REG, + .alarm_seconds_reg = RK808_ALARM_SECONDS_REG, + .int_reg = RK808_RTC_INT_REG, + .seconds_reg = RK808_SECONDS_REG, +}; + +static struct rk_rtc_compat_reg rk817_creg = +{ + .ctrl_reg = RK817_RTC_CTRL_REG, + .status_reg = RK817_RTC_STATUS_REG, + .alarm_seconds_reg = RK817_ALARM_SECONDS_REG, + .int_reg = RK817_RTC_INT_REG, + .seconds_reg = RK817_SECONDS_REG, +}; + +static rt_err_t rk8xx_rtc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rk8xx *rk8xx = pdev->priv; + struct rk8xx_rtc *rk8xx_rtc = rt_calloc(1, sizeof(*rk8xx_rtc)); + + if (!rk8xx_rtc) + { + return -RT_ENOMEM; + } + + rk8xx_rtc->rk8xx = rk8xx; + + switch (rk8xx->variant) + { + case RK809_ID: + case RK817_ID: + rk8xx_rtc->creg = &rk817_creg; + break; + + default: + rk8xx_rtc->creg = &rk808_creg; + break; + } + + err = rk8xx_update_bits(rk8xx, rk8xx_rtc->creg->ctrl_reg, + BIT_RTC_CTRL_REG_STOP_RTC_M | + BIT_RTC_CTRL_REG_RTC_READSEL_M, + BIT_RTC_CTRL_REG_RTC_READSEL_M); + + if (err) + { + LOG_E("Update RTC control error = %s", rt_strerror(err)); + goto _fail; + } + + err = rk8xx_write(rk8xx, rk8xx_rtc->creg->status_reg, RTC_STATUS_MASK); + + if (err) + { + LOG_E("Write RTC status error = %s", rt_strerror(err)); + goto _fail; + } + + rk8xx_rtc->irq_thread = rt_thread_create("rtc-rk8xx", &rk8xx_rtc_thread_isr, + rk8xx_rtc, SYSTEM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10); + + if (!rk8xx_rtc->irq_thread) + { + err = -RT_ERROR; + LOG_E("Create RTC IRQ thread fail"); + goto _fail; + } + + rt_thread_startup(rk8xx_rtc->irq_thread); + + rk8xx_rtc->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + rk8xx_rtc->parent.ops = &rk8xx_rtc_ops; +#else + rk8xx_rtc->parent.control = rk8xx_rtc_control; +#endif + + rtc_dev_set_name(&rk8xx_rtc->parent); + dev_name = rt_dm_dev_get_name(&rk8xx_rtc->parent); + rt_device_register(&rk8xx_rtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + rt_hw_interrupt_install(rk8xx->irq, rk8xx_rtc_isr, rk8xx_rtc, "rtc-rk8xx"); + rt_hw_interrupt_umask(rk8xx->irq); + + return RT_EOK; + +_fail: + if (rk8xx_rtc->irq_thread) + { + rt_thread_delete(rk8xx_rtc->irq_thread); + } + rt_free(rk8xx_rtc); + + return err; +} + +static struct rt_platform_driver rk8xx_rtc_driver = +{ + .name = "rk8xx-rtc", + .probe = rk8xx_rtc_probe, +}; + +static int rk8xx_rtc_drv_register(void) +{ + rt_platform_driver_register(&rk8xx_rtc_driver); + + return 0; +} +INIT_DRIVER_LATE_EXPORT(rk8xx_rtc_drv_register); diff --git a/components/drivers/rtc/rtc-rk_timer.c b/components/drivers/rtc/rtc-rk_timer.c new file mode 100644 index 000000000000..0d4dd4a66b25 --- /dev/null +++ b/components/drivers/rtc/rtc-rk_timer.c @@ -0,0 +1,372 @@ +/* + * 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 "rtc_dm.h" + +#define TIMER_LOAD_COUNT0 0x00 +#define TIMER_LOAD_COUNT1 0x04 +#define TIMER_CURRENT_VALUE0 0x08 +#define TIMER_CURRENT_VALUE1 0x0c +#define TIMER_CONTROL_REG3288 0x10 +#define TIMER_INT_STATUS 0x18 + +#define TIMER_ENABLE RT_BIT(0) +#define TIMER_MODE_USER_DEFINED_COUNT RT_BIT(1) +#define TIMER_INT_UNMASK RT_BIT(2) + +/* Forbid any alarms which would trigger inside the threshold */ +#define TIMER_ALARM_THRESHOLD_MS 10 +#define TIMER_COUNT_MAX ((rt_uint64_t)-1) + +struct rk_timer_rtc_data +{ + int ctrl_reg_offset; +}; + +struct rk_timer_rtc +{ + struct rt_device parent; + + int irq; + void *base; + + struct rt_clk *clk; + struct rt_clk *pclk; + + rt_uint32_t freq; + rt_uint64_t timebase; + rt_bool_t alarm_irq_enabled; + struct rt_rtc_wkalarm wkalarm; + + const struct rk_timer_rtc_data *soc_data; +}; + +#define raw_to_rk_timer_rtc(raw) rt_container_of(raw, struct rk_timer_rtc, parent) + +rt_inline rt_uint64_t tick_to_sec(struct rk_timer_rtc *rk_rtc, rt_uint64_t tick) +{ + rt_do_div(tick, rk_rtc->freq); + + return tick; +} + +rt_inline rt_uint64_t ms_to_tick(struct rk_timer_rtc *rk_rtc, int ms) +{ + return ms * rk_rtc->freq / 1000; +} + +rt_inline rt_uint64_t tick_to_time64(struct rk_timer_rtc *rk_rtc, rt_uint64_t tick) +{ + return tick_to_sec(rk_rtc, tick) + rk_rtc->timebase; +} + +rt_inline rt_uint64_t time64_to_tick(struct rk_timer_rtc *rk_rtc, rt_uint64_t time) +{ + return (time - rk_rtc->timebase) * rk_rtc->freq; +} + +rt_inline void rk_timer_rtc_writel(struct rk_timer_rtc *rk_rtc, int offset, rt_uint32_t value) +{ + HWREG32(rk_rtc->base + offset) = value; +} + +rt_inline rt_uint32_t rk_timer_rtc_readl(struct rk_timer_rtc *rk_rtc, int offset) +{ + return HWREG32(rk_rtc->base + offset); +} + +rt_inline void rk_timer_rtc_writeq(struct rk_timer_rtc *rk_rtc, int offset, rt_uint64_t value) +{ + HWREG32(rk_rtc->base + offset) = value; + HWREG32(rk_rtc->base + offset + 4) = value >> 32; +} + +rt_inline rt_uint64_t rk_timer_rtc_readq(struct rk_timer_rtc *rk_rtc, int offset) +{ + rt_uint32_t val_lo, val_hi, tmp_hi; + + do { + val_hi = HWREG32(rk_rtc->base + offset + 4); + val_lo = HWREG32(rk_rtc->base + offset); + tmp_hi = HWREG32(rk_rtc->base + offset + 4); + } while (val_hi != tmp_hi); + + return ((rt_uint64_t) val_hi << 32) | val_lo; +} + +rt_inline void rk_timer_rtc_irq_clear(struct rk_timer_rtc *rk_rtc) +{ + return rk_timer_rtc_writel(rk_rtc->base, TIMER_INT_STATUS, 1); +} + +rt_inline void rk_timer_rtc_irq_enable(struct rk_timer_rtc *rk_rtc, rt_bool_t enabled) +{ + rt_uint32_t old_val; + + /* Clear any pending irq before enable it */ + if (enabled) + { + rk_timer_rtc_irq_clear(rk_rtc); + } + + old_val = rk_timer_rtc_readl(rk_rtc, rk_rtc->soc_data->ctrl_reg_offset); + old_val &= ~TIMER_INT_UNMASK; + rk_timer_rtc_writel(rk_rtc, rk_rtc->soc_data->ctrl_reg_offset, + old_val | (enabled ? TIMER_INT_UNMASK : 0)); +} + +static void rk_timer_rtc_reset(struct rk_timer_rtc *rk_rtc) +{ + rk_timer_rtc_writel(rk_rtc, rk_rtc->soc_data->ctrl_reg_offset, 0); + + /* Init load count to UINT64_MAX to keep timer running */ + rk_timer_rtc_writeq(rk_rtc, TIMER_LOAD_COUNT0, TIMER_COUNT_MAX); + + /* Clear any pending irq before enable it */ + rk_timer_rtc_irq_clear(rk_rtc); + + /* Enable timer in user-defined count mode with irq unmasked */ + rk_timer_rtc_writel(rk_rtc, rk_rtc->soc_data->ctrl_reg_offset, + TIMER_ENABLE | TIMER_MODE_USER_DEFINED_COUNT | TIMER_INT_UNMASK); +} + +static void rk_timer_rtc_read_time(struct rk_timer_rtc *rk_rtc, time_t *sec) +{ + rt_uint64_t tick; + + tick = rk_timer_rtc_readq(rk_rtc, TIMER_CURRENT_VALUE0); + + *sec = (time_t)tick_to_time64(rk_rtc, tick); +} + +static void rk_timer_rtc_set_time(struct rk_timer_rtc *rk_rtc, time_t *sec) +{ + rk_rtc->timebase = (rt_uint64_t)*sec; + + rk_timer_rtc_reset(rk_rtc); +} + +static void rk_timer_rtc_read_alarm(struct rk_timer_rtc *rk_rtc, + struct rt_rtc_wkalarm *alarm) +{ + *alarm = rk_rtc->wkalarm; + + alarm->enable = rk_rtc->alarm_irq_enabled; +} + +static rt_err_t rk_timer_rtc_set_alarm(struct rk_timer_rtc *rk_rtc, + struct rt_rtc_wkalarm *alarm) +{ + rt_uint64_t alarm_tick, alarm_threshold_tick, cur_tick, time; + + rk_rtc->alarm_irq_enabled = alarm->enable; + + time = alarm->tm_hour * 3600 + alarm->tm_min * 60 + alarm->tm_sec; + alarm_tick = time64_to_tick(rk_rtc, time); + cur_tick = rk_timer_rtc_readq(rk_rtc, TIMER_CURRENT_VALUE0); + + /* Don't set an alarm in the past or about to pass */ + alarm_threshold_tick = ms_to_tick(rk_rtc, TIMER_ALARM_THRESHOLD_MS); + + if (alarm_tick <= (cur_tick + alarm_threshold_tick)) + { + return -RT_ERROR; + } + + /* + * When the current value counts up to the load count, the timer will + * stop and generate an irq. + */ + rk_timer_rtc_writeq(rk_rtc, TIMER_LOAD_COUNT0, alarm_tick); + + return RT_EOK; +} + +static rt_err_t rk_timer_rtc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t err = RT_EOK; + struct rk_timer_rtc *rk_rtc = raw_to_rk_timer_rtc(dev); + + if (!args) + { + return -RT_EINVAL; + } + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + rk_timer_rtc_read_time(rk_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + rk_timer_rtc_set_time(rk_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_GET_TIMEVAL: + rk_timer_rtc_read_time(rk_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIMEVAL: + rk_timer_rtc_set_time(rk_rtc, (time_t *)&((struct timeval *)args)->tv_sec); + break; + + case RT_DEVICE_CTRL_RTC_GET_ALARM: + rk_timer_rtc_read_alarm(rk_rtc, args); + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + err = rk_timer_rtc_set_alarm(rk_rtc, args); + break; + + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops rk_timer_rtc_ops = +{ + .control = rk_timer_rtc_control, +}; +#endif + +static void rk_timer_rtc_isr(int irqno, void *param) +{ + struct rk_timer_rtc *rk_rtc = param; + + rk_timer_rtc_writeq(rk_rtc, TIMER_LOAD_COUNT0, TIMER_COUNT_MAX); + rk_timer_rtc_writel(rk_rtc, TIMER_INT_STATUS, 1); + + if (rk_rtc->alarm_irq_enabled) + { + rt_alarm_update(&rk_rtc->parent, 1); + } +} + +static rt_err_t rk_timer_rtc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct rk_timer_rtc *rk_rtc = rt_calloc(1, sizeof(*rk_rtc)); + + if (!rk_rtc) + { + return -RT_ENOMEM; + } + + rk_rtc->soc_data = pdev->id->data; + + rk_rtc->base = rt_dm_dev_iomap(dev, 0); + + if (!rk_rtc->base) + { + err = -RT_EIO; + + goto _fail; + } + + rk_rtc->irq = rt_dm_dev_get_irq(dev, 0); + + if (rk_rtc->irq < 0) + { + err = rk_rtc->irq; + + goto _fail; + } + + rk_rtc->pclk = rt_clk_get_by_name(dev, "pclk"); + + if (!rk_rtc->pclk) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rk_rtc->pclk))) + { + goto _fail; + } + + rk_rtc->clk = rt_clk_get_by_name(dev, "timer"); + + if (!rk_rtc->clk) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rk_rtc->clk))) + { + goto _fail; + } + + rk_rtc->freq = rt_clk_get_rate(rk_rtc->clk); + + rk_rtc->parent.type = RT_Device_Class_RTC; +#ifdef RT_USING_DEVICE_OPS + rk_rtc->parent.ops = &rk_timer_rtc_ops; +#else + rk_rtc->parent.control = rk_timer_rtc_control; +#endif + + rtc_dev_set_name(&rk_rtc->parent); + dev_name = rt_dm_dev_get_name(&rk_rtc->parent); + rt_device_register(&rk_rtc->parent, dev_name, RT_DEVICE_FLAG_RDWR); + + rt_hw_interrupt_install(rk_rtc->irq, rk_timer_rtc_isr, rk_rtc, "rtc-rockchip"); + rt_hw_interrupt_umask(rk_rtc->irq); + + return RT_EOK; + +_fail: + if (rk_rtc->base) + { + rt_iounmap(rk_rtc->base); + } + if (rk_rtc->pclk) + { + rt_clk_disable_unprepare(rk_rtc->pclk); + rt_clk_put(rk_rtc->pclk); + } + if (rk_rtc->clk) + { + rt_clk_disable_unprepare(rk_rtc->clk); + rt_clk_put(rk_rtc->clk); + } + rt_free(rk_rtc); + + return err; +} + +static const struct rk_timer_rtc_data rk3288_timer_rtc_data = +{ + .ctrl_reg_offset = TIMER_CONTROL_REG3288, +}; + +static const struct rt_ofw_node_id rk_timer_rtc_ofw_ids[] = +{ + { .compatible = "rockchip,rk3308-timer-rtc", .data = &rk3288_timer_rtc_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rk_timer_rtc_driver = +{ + .name = "rk-timer-rtc", + .ids = rk_timer_rtc_ofw_ids, + + .probe = rk_timer_rtc_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rk_timer_rtc_driver); diff --git a/components/drivers/rtc/rtc_dm.c b/components/drivers/rtc/rtc_dm.c new file mode 100644 index 000000000000..e173689568bf --- /dev/null +++ b/components/drivers/rtc/rtc_dm.c @@ -0,0 +1,35 @@ +/* + * 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 "rtc_dm.h" + +#define DBG_TAG "rtc.dm" +#define DBG_LVL DBG_INFO +#include + +int rtc_dev_set_name(struct rt_device *rtc_dev) +{ + int id; + static volatile rt_atomic_t uid = 1; + + RT_ASSERT(rtc_dev != RT_NULL) + + if (rt_device_find("rtc")) + { + id = (int)rt_hw_atomic_add(&uid, 1); + + return rt_dm_dev_set_name(rtc_dev, "rtc%u", id); + } + else + { + return rt_dm_dev_set_name(rtc_dev, "rtc"); + } +} diff --git a/components/drivers/rtc/rtc_dm.h b/components/drivers/rtc/rtc_dm.h new file mode 100644 index 000000000000..9cf719a5ae16 --- /dev/null +++ b/components/drivers/rtc/rtc_dm.h @@ -0,0 +1,22 @@ +/* + * 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 + */ + +#ifndef __RTC_DM_H__ +#define __RTC_DM_H__ + +#include +#include +#include + +#include + +int rtc_dev_set_name(struct rt_device *rtc_dev); + +#endif /* __RTC_DM_H__ */ diff --git a/components/drivers/sdio/Kconfig b/components/drivers/sdio/Kconfig new file mode 100644 index 000000000000..086b65de5279 --- /dev/null +++ b/components/drivers/sdio/Kconfig @@ -0,0 +1,32 @@ +menuconfig RT_USING_SDIO + bool "Using SD/MMC device drivers" + default n + + if RT_USING_SDIO + config RT_SDIO_STACK_SIZE + int "The stack size for sdio irq thread" + default 512 + + config RT_SDIO_THREAD_PRIORITY + int "The priority level value of sdio irq thread" + default 15 + + config RT_MMCSD_STACK_SIZE + int "The stack size for mmcsd thread" + default 1024 + + config RT_MMCSD_THREAD_PREORITY + int "The priority level value of mmcsd thread" + default 22 + + config RT_MMCSD_MAX_PARTITION + int "mmcsd max partition" + default 16 + config RT_SDIO_DEBUG + bool "Enable SDIO debug log output" + default n + endif + +if RT_USING_DM && RT_USING_SDIO +source "$RTT_DIR/components/drivers/sdio/host/Kconfig" +endif diff --git a/components/drivers/sdio/SConscript b/components/drivers/sdio/SConscript index d5b6eb1cb9b9..662a9db40565 100644 --- a/components/drivers/sdio/SConscript +++ b/components/drivers/sdio/SConscript @@ -14,6 +14,19 @@ mmc.c # The set of source files associated with this SConscript file. path = [cwd + '/../include'] +if GetDepend(['RT_USING_DM']): + src += ['sdio_dm.c'] + + if GetDepend(['RT_USING_REGULATOR']): + src += ['regulator.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SDIO'], CPPPATH = path) +objs = [] + +for d in os.listdir(cwd): + 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 + group -Return('group') +Return('objs') diff --git a/components/drivers/sdio/block_dev.c b/components/drivers/sdio/block_dev.c index 1cdcec22b084..d88e54406569 100644 --- a/components/drivers/sdio/block_dev.c +++ b/components/drivers/sdio/block_dev.c @@ -479,7 +479,13 @@ rt_int32_t gpt_device_probe(struct rt_mmcsd_card *card) status = gpt_get_partition_param(card, &blk_dev->part, i); if (status == RT_EOK) { - rt_snprintf(dname, sizeof(dname) - 1, "%s%d", card->host->name, i); + rt_snprintf(dname, sizeof(dname) - 1, + #ifdef RT_USING_DM + "%sp%d", + #else + "%s%d", + #endif + card->host->name, i); rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, i + 1); blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); diff --git a/components/drivers/sdio/host/Kconfig b/components/drivers/sdio/host/Kconfig new file mode 100644 index 000000000000..70da7143255d --- /dev/null +++ b/components/drivers/sdio/host/Kconfig @@ -0,0 +1,25 @@ +config RT_SDIO_SDHCI_DWCMSHC + bool "Synopsys DWC MSHC SDHCI" + select RT_USING_OFW + default n + +config RT_SDIO_DW_MMC + bool "Synopsys DesignWare MMC Family" + select RT_USING_PINCTRL + select RT_USING_RESET + select RT_USING_REGULATOR + select RT_USING_DEVICE_IPC + select RT_USING_SYSTEM_WORKQUEUE + default n + +config RT_SDIO_DW_MMC_PCI + bool "Synopsys Designware MCI support on PCI bus" + depends on RT_SDIO_DW_MMC + select RT_USING_PCI + default n + +config RT_SDIO_DW_MMC_ROCKCHIP + bool "Rockchip" + depends on RT_SDIO_DW_MMC + select RT_USING_OFW + default n diff --git a/components/drivers/sdio/host/SConscript b/components/drivers/sdio/host/SConscript new file mode 100644 index 000000000000..019f8f7306b1 --- /dev/null +++ b/components/drivers/sdio/host/SConscript @@ -0,0 +1,27 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_SDIO']) and not GetDepend(['RT_USING_DM']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_SDIO_SDHCI_DWCMSHC']): + src += ['sdhci-dwcmshc.c'] + +if GetDepend(['RT_SDIO_DW_MMC']): + src += ['sdio-dw.c', 'sdio-dw-platfrom.c'] + + if GetDepend(['RT_SDIO_DW_MMC_PCI']): + src += ['sdio-dw-pci.c'] + + if GetDepend(['RT_SDIO_DW_MMC_ROCKCHIP']): + src += ['sdio-dw_rockchip.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/sdio/host/sdhci-dwcmshc.c b/components/drivers/sdio/host/sdhci-dwcmshc.c new file mode 100644 index 000000000000..7695a2e455d2 --- /dev/null +++ b/components/drivers/sdio/host/sdhci-dwcmshc.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include + +#include "../sdio_dm.h" + +#define SDHCI_DWCMSHC_ARG2_STUFF RT_GENMASK(31, 16) + +/* DWCMSHC specific Mode Select value */ +#define DWCMSHC_CTRL_HS400 0x7 + +/* DWC IP vendor area 1 pointer */ +#define DWCMSHC_P_VENDOR_AREA1 0xe8 +#define DWCMSHC_AREA1_MASK RT_GENMASK(11, 0) +/* Offset inside the vendor area 1 */ +#define DWCMSHC_HOST_CTRL3 0x8 +#define DWCMSHC_EMMC_CONTROL 0x2c +#define DWCMSHC_CARD_IS_EMMC RT_BIT(0) +#define DWCMSHC_ENHANCED_STROBE RT_BIT(8) +#define DWCMSHC_EMMC_ATCTRL 0x40 + +/* Rockchip specific Registers */ +#define DWCMSHC_EMMC_DLL_CTRL 0x800 +#define DWCMSHC_EMMC_DLL_RXCLK 0x804 +#define DWCMSHC_EMMC_DLL_TXCLK 0x808 +#define DWCMSHC_EMMC_DLL_STRBIN 0x80c +#define DECMSHC_EMMC_DLL_CMDOUT 0x810 +#define DWCMSHC_EMMC_DLL_STATUS0 0x840 +#define DWCMSHC_EMMC_DLL_START RT_BIT(0) +#define DWCMSHC_EMMC_DLL_LOCKED RT_BIT(8) +#define DWCMSHC_EMMC_DLL_TIMEOUT RT_BIT(9) +#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 +#define DWCMSHC_EMMC_DLL_START_POINT 16 +#define DWCMSHC_EMMC_DLL_INC 8 +#define DWCMSHC_EMMC_DLL_BYPASS RT_BIT(24) +#define DWCMSHC_EMMC_DLL_DLYENA RT_BIT(27) +#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 +#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA +#define DLL_TXCLK_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 +#define DLL_STRBIN_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_STRBIN_DELAY_NUM_SEL RT_BIT(26) +#define DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 +#define DLL_RXCLK_NO_INVERTER 1 +#define DLL_RXCLK_INVERTER 0 +#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 +#define DLL_RXCLK_ORI_GATE RT_BIT(31) +#define DLL_CMDOUT_TAPNUM_FROM_SW RT_BIT(24) +#define DLL_CMDOUT_SRC_CLK_NEG RT_BIT(28) +#define DLL_CMDOUT_EN_SRC_CLK_NEG RT_BIT(29) + +#define DLL_LOCK_WO_TMOUT(x) \ + ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ + (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) + +#define BOUNDARY_OK(addr, len) \ + ((addr | ((128 * SIZE_MB) - 1)) == ((addr + len - 1) | ((128 * SIZE_MB) - 1))) + +struct sdwcmshc_soc_data +{ + const struct rt_mmcsd_host_ops *ops; +}; + +struct dwcmshc_sdhci +{ + struct rt_clk *bus_clk; + /* P_VENDOR_SPECIFIC_AREA reg */ + int vendor_specific_area1; + + void *priv; +}; + +enum dwcmshc_rk_type +{ + DWCMSHC_RK3568, + DWCMSHC_RK3588, +}; + +struct rk35xx_priv +{ + /* Rockchip specified optional clocks */ + struct rt_clk_array *clk_arr; + struct reset_control *rstc; + + enum dwcmshc_rk_type devtype; + rt_uint8_t txclk_tapnum; +}; + +static rt_err_t sdhci_dwcmshc_probe(struct rt_platform_device *pdev) +{ + return RT_EOK; +} + +static const struct sdwcmshc_soc_data sdhci_dwcmshc_data = +{ +}; + +static const struct sdwcmshc_soc_data sdhci_dwcmshc_rk35xx_data = +{ +}; + +static const struct rt_ofw_node_id sdhci_dwcmshc_ofw_ids[] = +{ + { .compatible = "rockchip,rk3588-dwcmshc", .data = &sdhci_dwcmshc_rk35xx_data, }, + { .compatible = "rockchip,rk3568-dwcmshc", .data = &sdhci_dwcmshc_rk35xx_data, }, + { .compatible = "rockchip,dwcmshc-sdhci", .data = &sdhci_dwcmshc_rk35xx_data, }, + { .compatible = "snps,dwcmshc-sdhci", .data = &sdhci_dwcmshc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdhci_dwcmshc_driver = +{ + .name = "sdhci-dwcmshc", + .ids = sdhci_dwcmshc_ofw_ids, + + .probe = sdhci_dwcmshc_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(sdhci_dwcmshc_driver); diff --git a/components/drivers/sdio/host/sdio-dw-pci.c b/components/drivers/sdio/host/sdio-dw-pci.c new file mode 100644 index 000000000000..8a07bda12ce8 --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw-pci.c @@ -0,0 +1,83 @@ +/* + * 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 "sdio-dw.h" + +#include + +#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700 +#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107 + +#define MCI_REG_NO 2 + +static const struct sdio_dw_drv_data sdio_dw_pci_drv_data = +{ +}; + +static rt_err_t sdio_dw_pci_probe(struct rt_pci_device *pdev) +{ + rt_err_t err; + struct sdio_dw *sd = rt_calloc(1, sizeof(*sd)); + + if (!sd) + { + return -RT_ENOMEM; + } + + sd->base = rt_pci_iomap(pdev, MCI_REG_NO); + + if (!sd->base) + { + goto _fail; + } + + sd->irq = pdev->irq; + rt_pci_intx(pdev, RT_TRUE); + + sd->base_phy = (rt_ubase_t)rt_kmem_v2p(sd->base); + sd->drv_data = &sdio_dw_pci_drv_data; + + /* board data */ + sd->bus_hz = 33 * 1000 * 1000; + sd->detect_delay_ms = 200; + sd->fifo_depth = 32; + + if ((err = sdio_dw_probe(sd))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (sd->base) + { + rt_iounmap(sd->base); + } + + rt_free(sd); + + return err; +} + +static struct rt_pci_device_id sdio_dw_pci_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) }, + { /* sentinel */ } +}; + +static struct rt_pci_driver sdio_dw_pci_driver = +{ + .name = "dw-mmc-pci", + + .ids = sdio_dw_pci_pci_ids, + .probe = sdio_dw_pci_probe, +}; +RT_PCI_DRIVER_EXPORT(sdio_dw_pci_driver); \ No newline at end of file diff --git a/components/drivers/sdio/host/sdio-dw-platfrom.c b/components/drivers/sdio/host/sdio-dw-platfrom.c new file mode 100644 index 000000000000..02b46f8ca9a1 --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw-platfrom.c @@ -0,0 +1,93 @@ +/* + * 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 "sdio-dw-platfrom.h" + +#include + +rt_err_t sdio_dw_platfrom_register(struct rt_platform_device *pdev, + const struct sdio_dw_drv_data *drv_data) +{ + rt_err_t err = RT_EOK; + struct rt_device *dev = &pdev->parent; + struct sdio_dw *sd = rt_calloc(1, sizeof(*sd)); + + if (!sd) + { + return -RT_ENOMEM; + } + + sd->base = rt_dm_dev_iomap(dev, 0); + + if (!sd->base) + { + err = -RT_EIO; + goto _fail; + } + + sd->irq = rt_dm_dev_get_irq(dev, 0); + + if (sd->irq < 0) + { + err = sd->irq; + + goto _fail; + } + + sd->parent.ofw_node = dev->ofw_node; + + sd->base_phy = (rt_ubase_t)rt_kmem_v2p(sd->base); + sd->drv_data = drv_data; + + if ((err = sdio_dw_probe(sd))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (sd->base) + { + rt_iounmap(sd->base); + } + + rt_free(sd); + + return err; +} + +static rt_err_t sdio_dw_platfrom_probe(struct rt_platform_device *pdev) +{ + const struct sdio_dw_drv_data *drv_data = RT_NULL; + + if (pdev->parent.ofw_node) + { + drv_data = pdev->id->data; + } + + return sdio_dw_platfrom_register(pdev, drv_data); +} + +static const struct rt_ofw_node_id sdio_dw_platfrom_ofw_ids[] = +{ + { .compatible = "snps,dw-mshc", }, + { .compatible = "img,pistachio-dw-mshc", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdio_dw_platfrom_driver = +{ + .name = "dw-mmc", + .ids = sdio_dw_platfrom_ofw_ids, + + .probe = sdio_dw_platfrom_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(sdio_dw_platfrom_driver); diff --git a/components/drivers/sdio/host/sdio-dw-platfrom.h b/components/drivers/sdio/host/sdio-dw-platfrom.h new file mode 100644 index 000000000000..314d4ea4e00e --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw-platfrom.h @@ -0,0 +1,19 @@ +/* + * 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 + */ + +#ifndef __SDIO_DW_PLATFROM_H__ +#define __SDIO_DW_PLATFROM_H__ + +#include "sdio-dw.h" + +rt_err_t sdio_dw_platfrom_register(struct rt_platform_device *pdev, + const struct sdio_dw_drv_data *drv_data); + +#endif /* __SDIO_DW_PLATFROM_H__ */ diff --git a/components/drivers/sdio/host/sdio-dw.c b/components/drivers/sdio/host/sdio-dw.c new file mode 100644 index 000000000000..5ee3f555cf08 --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw.c @@ -0,0 +1,3133 @@ +/* + * 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 + +#define DBG_TAG "sdio.dw" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +#include "sdio-dw.h" + +/* Common flag combinations */ +#define PINT(x) SDIO_DW_INT_##x +#define SDIO_DW_DATA_ERROR_FLAGS (PINT(DRTO) | PINT(DCRC) | PINT(HTO) | PINT(SBE) | PINT(EBE) | PINT(HLE)) +#define SDIO_DW_CMD_ERROR_FLAGS (PINT(RTO) | PINT(RCRC) | PINT(RESP_ERR) | PINT(HLE)) +#define SDIO_DW_ERROR_FLAGS (SDIO_DW_DATA_ERROR_FLAGS | SDIO_DW_CMD_ERROR_FLAGS) +#define SDIO_DW_SEND_STATUS 1 +#define SDIO_DW_RECV_STATUS 2 +#define SDIO_DW_DMA_THRESHOLD 16 + +#define SDIO_DW_FREQ_HZ_MAX 200000000 +#define SDIO_DW_FREQ_HZ_MIN 100000 + +#define PINTC(x) SDIO_DW_IDMAC_INT_##x +#define SDIO_DW_IDMAC_INT_CLR (PINTC(AI) | PINTC(NI) | PINTC(CES) | PINTC(DU) | PINTC(FBE) | PINTC(RI) | PINTC(TI)) + +#define DESC_RING_BUF_SZ ARCH_PAGE_SIZE +#define NSEC_PER_SEC 1000000000L +#define USEC_PER_MSEC 1000L +#define MSEC_PER_SEC 1000L + +struct idmac_desc64 +{ + rt_uint32_t des0; /* Control descriptor */ +#define IDMAC_OWN_CLR64(x) !((x) & rt_cpu_to_le32(IDMAC_DES0_OWN)) + + rt_uint32_t des1; /* Reserved */ + + rt_uint32_t des2; /* Buffer sizes */ +#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ + ((d)->des2 = ((d)->des2 & rt_cpu_to_le32(0x03ffe000)) | ((rt_cpu_to_le32(s)) & rt_cpu_to_le32(0x1fff))) + + rt_uint32_t des3; /* Reserved */ + + rt_uint32_t des4; /* Lower 32-bits of buffer address pointer 1 */ + rt_uint32_t des5; /* Upper 32-bits of buffer address pointer 1 */ + + rt_uint32_t des6; /* Lower 32-bits of next descriptor address */ + rt_uint32_t des7; /* Upper 32-bits of next descriptor address */ +}; + +struct idmac_desc32 +{ + rt_le32_t des0; /* Control Descriptor */ +#define IDMAC_DES0_DIC RT_BIT(1) +#define IDMAC_DES0_LD RT_BIT(2) +#define IDMAC_DES0_FD RT_BIT(3) +#define IDMAC_DES0_CH RT_BIT(4) +#define IDMAC_DES0_ER RT_BIT(5) +#define IDMAC_DES0_CES RT_BIT(30) +#define IDMAC_DES0_OWN RT_BIT(31) + rt_le32_t des1; /* Buffer sizes */ + +#define IDMAC_32ADDR_SET_BUFFER1_SIZE(d, s) \ + ((d)->des1 = ((d)->des1 & rt_cpu_to_le32(0x03ffe000)) | (rt_cpu_to_le32((s) & 0x1fff))) + + rt_le32_t des2; /* Buffer 1 physical address */ + rt_le32_t des3; /* Buffer 2 physical address */ +}; + +/* Each descriptor can transfer up to 4KB of data in chained mode */ +#define DW_MCI_DESC_DATA_LENGTH 0x1000 + +static rt_bool_t sdio_dw_ctrl_reset(struct sdio_dw *sd, rt_uint32_t reset) +{ + rt_uint32_t ctrl; + rt_tick_t start; + int timeout = rt_tick_from_millisecond(500); + + ctrl = sdio_dw_readl(sd, CTRL); + ctrl |= reset; + sdio_dw_writel(sd, CTRL, ctrl); + + start = rt_tick_get(); + + while ((sdio_dw_readl(sd, CTRL) & reset)) + { + if ((rt_tick_get() - start) > timeout) + { + LOG_E("Timeout resetting block (ctrl reset 0x%x)", ctrl & reset); + + return RT_FALSE; + } + + rt_hw_cpu_relax(); + } + + return RT_TRUE; +} + +static void sdio_dw_wait_while_busy(struct sdio_dw *sd, rt_uint32_t cmd_flags) +{ + if ((cmd_flags & SDIO_DW_CMD_PRV_DAT_WAIT) && !(cmd_flags & SDIO_DW_CMD_VOLT_SWITCH)) + { + rt_tick_t start = rt_tick_get(); + int timeout = rt_tick_from_millisecond(500); + + while ((sdio_dw_readl(sd, STATUS) & SDIO_DW_STATUS_BUSY)) + { + if ((rt_tick_get() - start) > timeout) + { + LOG_E("Wait busy fail"); + + break; + } + + rt_hw_cpu_relax(); + } + } +} + +static void sdio_dw_send_cmd(struct sdio_dw_slot *slot, rt_uint32_t cmd, rt_uint32_t arg) +{ + rt_tick_t start; + struct sdio_dw *sd = slot->sd; + int timeout = rt_tick_from_millisecond(500); + + sdio_dw_writel(sd, CMDARG, arg); + rt_hw_wmb(); + sdio_dw_wait_while_busy(sd, cmd); + sdio_dw_writel(sd, CMD, SDIO_DW_CMD_START | cmd); + + start = rt_tick_get(); + + while ((sdio_dw_readl(sd, CMD) & SDIO_DW_CMD_START)) + { + if ((rt_tick_get() - start) > timeout) + { + LOG_E("Wait command start fail"); + + break; + } + + rt_hw_cpu_relax(); + } +} + +rt_inline void sdio_dw_set_cto(struct sdio_dw *sd) +{ + rt_ubase_t level; + rt_uint32_t cto_clks, cto_div, cto_ms; + + cto_clks = sdio_dw_readl(sd, TMOUT) & 0xff; + cto_div = (sdio_dw_readl(sd, CLKDIV) & 0xff) * 2; + + if (cto_div == 0) + { + cto_div = 1; + } + + cto_ms = RT_DIV_ROUND_UP_ULL((rt_uint64_t)MSEC_PER_SEC * cto_clks * cto_div, + sd->bus_hz); + + /* Add a bit spare time */ + cto_ms += 10; + + /* + * The durations we're working with are fairly short so we have to be extra + * careful about synchronization here. Specifically in hardware a command + * timeout is _at most_ 5.1 ms, so that means we expect an interrupt + * (either command done or timeout) to come rather quickly after the + * sdio_dw_writel. ...but just in case we have a long interrupt latency + * let's add a bit of paranoia. + * + * In general we'll assume that at least an interrupt will be asserted in + * hardware by the time the cto_timer runs. ...and if it hasn't been + * asserted in hardware by that time then we'll assume it'll never come. + */ + level = rt_spin_lock_irqsave(&sd->irq_lock); + + if (!bitmap_test_bit(&sd->pending_events, EVENT_CMD_COMPLETE)) + { + rt_tick_t tick = rt_tick_from_millisecond(cto_ms) + 1; + + rt_timer_control(&sd->cto_timer, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&sd->cto_timer); + } + + rt_spin_unlock_irqrestore(&sd->irq_lock, level); +} + +static void sdio_dw_start_cmd(struct sdio_dw_slot *slot, rt_uint32_t cmd, + rt_uint32_t arg) +{ + struct sdio_dw *sd = slot->sd; + + sdio_dw_writel(sd, CMDARG, arg); + rt_hw_wmb(); + sdio_dw_wait_while_busy(sd, cmd); + sdio_dw_writel(sd, CMD, SDIO_DW_CMD_START | cmd); + + /* Response expected command only */ + if ((cmd & SDIO_DW_CMD_RESP_EXP)) + { + sdio_dw_set_cto(sd); + } +} + +rt_inline void send_stop_abort(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + struct rt_mmcsd_cmd *stop = &sd->stop_abort; + + sdio_dw_start_cmd(sd->slot, sd->stop_cmdr, stop->arg); +} + +/* DMA interface functions */ +static void sdio_dw_stop_dma(struct sdio_dw *sd) +{ + if (sd->using_dma) + { + sd->dma_ops->stop(sd); + sd->dma_ops->cleanup(sd); + } + + /* Data transfer was stopped by the interrupt handler */ + bitmap_set_bit(&sd->pending_events, EVENT_XFER_COMPLETE); +} + +static rt_uint32_t sdio_dw_prep_stop_abort(struct sdio_dw *sd, struct rt_mmcsd_cmd *cmd) +{ + rt_uint32_t cmdr; + struct rt_mmcsd_cmd *stop; + + if (!cmd->data) + { + return 0; + } + + stop = &sd->stop_abort; + cmdr = cmd->cmd_code; + rt_memset(stop, 0, sizeof(*stop)); + + if (cmdr == READ_SINGLE_BLOCK || + cmdr == READ_MULTIPLE_BLOCK || + cmdr == WRITE_BLOCK || + cmdr == WRITE_MULTIPLE_BLOCK || + cmdr == SEND_TUNING_BLOCK || + cmdr == SEND_TUNING_BLOCK_HS200 || + cmdr == GEN_CMD) + { + stop->cmd_code = STOP_TRANSMISSION; + stop->arg = 0; + stop->flags = CMD_AC; + } + else if (cmdr == SD_IO_RW_EXTENDED) + { + stop->cmd_code = SD_IO_RW_DIRECT; + stop->arg |= (1 << 31) | (0 << 28) | ((cmd->arg >> 28) & 0x7); + stop->flags = RESP_SPI_R5 | CMD_AC; + } + else + { + return 0; + } + + cmdr = stop->cmd_code | SDIO_DW_CMD_STOP | SDIO_DW_CMD_RESP_CRC | SDIO_DW_CMD_RESP_EXP; + + if (!bitmap_test_bit(&sd->slot->flags, DW_MMC_CARD_NO_USE_HOLD)) + { + cmdr |= SDIO_DW_CMD_USE_HOLD_REG; + } + + return cmdr; +} + +static void sdio_dw_idmac_reset(struct sdio_dw *sd) +{ + /* Software reset of DMA */ + sdio_dw_writel(sd, BMOD, sdio_dw_readl(sd, BMOD) | SDIO_DW_IDMAC_SWRESET); +} + +static rt_err_t sdio_dw_idmac_init(struct sdio_dw *sd) +{ + int i; + rt_err_t err = RT_EOK; + + if (sd->dma_64bit_address) + { + struct idmac_desc64 *p; + /* Number of descriptors in the ring buffer */ + sd->ring_size = DESC_RING_BUF_SZ / sizeof(struct idmac_desc64); + + /* Forward link the descriptor list */ + for (i = 0, p = sd->dma_buf; i < sd->ring_size - 1; ++i, ++p) + { + p->des6 = (sd->dma_buf_phy + (sizeof(struct idmac_desc64) * (i + 1))) & 0xffffffff; + p->des7 = (rt_uint64_t)(sd->dma_buf_phy + (sizeof(struct idmac_desc64) * (i + 1))) >> 32; + /* Initialize reserved and buffer size fields to "0" */ + p->des0 = 0; + p->des1 = 0; + p->des2 = 0; + p->des3 = 0; + } + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des6 = sd->dma_buf_phy & 0xffffffff; + p->des7 = (rt_uint64_t)sd->dma_buf_phy >> 32; + p->des0 = IDMAC_DES0_ER; + } + else + { + struct idmac_desc32 *p; + /* Number of descriptors in the ring buffer */ + sd->ring_size = DESC_RING_BUF_SZ / sizeof(struct idmac_desc32); + + /* Forward link the descriptor list */ + for (i = 0, p = sd->dma_buf; i < sd->ring_size - 1; ++i, ++p) + { + p->des3 = rt_cpu_to_le32(sd->dma_buf_phy + (sizeof(struct idmac_desc32) * (i + 1))); + p->des0 = 0; + p->des1 = 0; + } + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des3 = rt_cpu_to_le32(sd->dma_buf_phy); + p->des0 = rt_cpu_to_le32(IDMAC_DES0_ER); + } + + sdio_dw_idmac_reset(sd); + + if (sd->dma_64bit_address) + { + /* Mask out interrupts - get Tx & Rx complete only */ + sdio_dw_writel(sd, IDSTS64, SDIO_DW_IDMAC_INT_CLR); + sdio_dw_writel(sd, IDINTEN64, PINTC(NI) | PINTC(RI) | PINTC(TI)); + + /* Set the descriptor base address */ + sdio_dw_writel(sd, DBADDRL, sd->dma_buf_phy & 0xffffffff); + sdio_dw_writel(sd, DBADDRU, (rt_uint64_t)sd->dma_buf_phy >> 32); + } + else + { + /* Mask out interrupts - get Tx & Rx complete only */ + sdio_dw_writel(sd, IDSTS, SDIO_DW_IDMAC_INT_CLR); + sdio_dw_writel(sd, IDINTEN, PINTC(NI) | PINTC(RI) | PINTC(TI)); + + /* Set the descriptor base address */ + sdio_dw_writel(sd, DBADDR, sd->dma_buf_phy); + } + + return err; +} + +rt_inline rt_err_t sdio_dw_prepare_desc64(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_uint32_t desc_len; + rt_uint64_t mem_addr; + int timeout = rt_tick_from_millisecond(100); + struct idmac_desc64 *desc_first, *desc_last, *desc; + + desc_first = desc_last = desc = sd->dma_buf; + mem_addr = (rt_uint64_t)rt_kmem_v2p(sd->last_buf); + + for (rt_uint32_t length = sd->last_remain; length; ++desc) + { + rt_tick_t start = rt_tick_get(); + + desc_len = rt_min_t(rt_uint32_t, length, DW_MCI_DESC_DATA_LENGTH); + length -= desc_len; + + /* + * Wait for the former clear OWN bit operation of IDMAC to make sure + * that this descriptor isn't still owned by IDMAC as IDMAC's write ops + * and CPU's read ops are asynchronous. + */ + while ((HWREG32(&desc->des0) & IDMAC_DES0_OWN)) + { + if ((rt_tick_get() - start) > timeout) + { + goto _err_own_bit; + } + + rt_hw_cpu_relax(); + } + + /* Set the OWN bit and disable interrupts for this descriptor */ + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; + + /* Buffer length */ + IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len); + + /* Physical address to DMA to/from */ + desc->des4 = mem_addr & 0xffffffff; + desc->des5 = mem_addr >> 32; + + /* Update physical address for the next desc */ + mem_addr += desc_len; + + /* Save pointer to the last descriptor */ + desc_last = desc; + } + + /* Set first descriptor */ + desc_first->des0 |= IDMAC_DES0_FD; + + /* Set last descriptor */ + desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); + desc_last->des0 |= IDMAC_DES0_LD; + + return RT_EOK; + +_err_own_bit: + /* restore the descriptor chain as it's polluted */ + LOG_D("Descriptor is still owned by IDMAC"); + + rt_memset(sd->dma_buf, 0, DESC_RING_BUF_SZ); + sdio_dw_idmac_init(sd); + + return -RT_EINVAL; +} + +rt_inline rt_err_t sdio_dw_prepare_desc32(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_uint32_t desc_len, mem_addr; + int timeout = rt_tick_from_millisecond(100); + struct idmac_desc32 *desc_first, *desc_last, *desc; + + desc_first = desc_last = desc = sd->dma_buf; + mem_addr = (rt_ubase_t)rt_kmem_v2p(sd->last_buf); + + for (rt_uint32_t length = sd->last_remain; length; ++desc) + { + rt_tick_t start = rt_tick_get(); + + desc_len = rt_min_t(rt_uint32_t, length, DW_MCI_DESC_DATA_LENGTH); + length -= desc_len; + + /* + * Wait for the former clear OWN bit operation of IDMAC to make sure + * that this descriptor isn't still owned by IDMAC as IDMAC's write ops + * and CPU's read ops are asynchronous. + */ + while (!IDMAC_OWN_CLR64(HWREG32(&desc->des0))) + { + if ((rt_tick_get() - start) > timeout) + { + goto _err_own_bit; + } + + rt_hw_cpu_relax(); + } + + /* Set the OWN bit and disable interrupts for this descriptor */ + desc->des0 = rt_cpu_to_le32(IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH); + + /* Buffer length */ + IDMAC_32ADDR_SET_BUFFER1_SIZE(desc, desc_len); + + /* Physical address to DMA to/from */ + desc->des2 = rt_cpu_to_le32(mem_addr); + + /* Update physical address for the next desc */ + mem_addr += desc_len; + + /* Save pointer to the last descriptor */ + desc_last = desc; + } + + /* Set first descriptor */ + desc_first->des0 |= rt_cpu_to_le32(IDMAC_DES0_FD); + + /* Set last descriptor */ + desc_last->des0 &= rt_cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC)); + desc_last->des0 |= rt_cpu_to_le32(IDMAC_DES0_LD); + + return RT_EOK; + +_err_own_bit: + /* restore the descriptor chain as it's polluted */ + LOG_D("Descriptor is still owned by IDMAC"); + + rt_memset(sd->dma_buf, 0, DESC_RING_BUF_SZ); + sdio_dw_idmac_init(sd); + + return -RT_EINVAL; +} + +static rt_err_t sdio_dw_idmac_start(struct sdio_dw *sd) +{ + rt_err_t err = RT_EOK; + + if (sd->dma_64bit_address) + { + err = sdio_dw_prepare_desc64(sd, sd->data); + } + else + { + err = sdio_dw_prepare_desc32(sd, sd->data); + } + + if (err) + { + goto _out; + } + + /* Drain writebuffer */ + rt_hw_wmb(); + + /* Make sure to reset DMA in case we did PIO before this */ + sdio_dw_ctrl_reset(sd, SDIO_DW_CTRL_DMA_RESET); + sdio_dw_idmac_reset(sd); + + /* Select IDMAC interface */ + sdio_dw_writel(sd, CTRL, sdio_dw_readl(sd, CTRL) | SDIO_DW_CTRL_USE_IDMAC); + + /* Drain writebuffer */ + rt_hw_wmb(); + + /* Enable the IDMAC */ + sdio_dw_writel(sd, BMOD, sdio_dw_readl(sd, BMOD) | SDIO_DW_IDMAC_ENABLE | SDIO_DW_IDMAC_FB); + + /* Start it running */ + sdio_dw_writel(sd, PLDMND, 1); + +_out: + return err; +} + +static rt_err_t sdio_dw_idmac_complete(struct sdio_dw *sd) +{ + rt_err_t err = RT_EOK; + struct rt_mmcsd_data *data = sd->data; + + sd->dma_ops->cleanup(sd); + + if (data) + { + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, data->buf, data->blks * data->blksize); + bitmap_set_bit(&sd->pending_events, EVENT_XFER_COMPLETE); + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); + } + + return err; +} + +static rt_err_t sdio_dw_idmac_stop(struct sdio_dw *sd) +{ + rt_uint32_t reg; + + /* Disable and reset the IDMAC interface */ + reg = sdio_dw_readl(sd, CTRL); + reg &= ~SDIO_DW_CTRL_USE_IDMAC; + reg |= SDIO_DW_CTRL_DMA_RESET; + sdio_dw_writel(sd, CTRL, reg); + + /* Stop the IDMAC running */ + reg = sdio_dw_readl(sd, BMOD); + reg &= ~(SDIO_DW_IDMAC_ENABLE | SDIO_DW_IDMAC_FB); + reg |= SDIO_DW_IDMAC_SWRESET; + sdio_dw_writel(sd, BMOD, reg); + + return RT_EOK; +} + +static rt_err_t sdio_dw_idmac_cleanup(struct sdio_dw *sd) +{ + return RT_EOK; +} + +static const struct sdio_dw_dma_ops sdio_dw_idmac_ops = +{ + .init = sdio_dw_idmac_init, + .start = sdio_dw_idmac_start, + .complete = sdio_dw_idmac_complete, + .stop = sdio_dw_idmac_stop, + .cleanup = sdio_dw_idmac_cleanup, +}; + +static const struct sdio_dw_dma_ops sdio_dw_edmac_ops = +{ +}; + +static rt_bool_t sdio_dw_get_cd(struct sdio_dw_slot *slot) +{ + rt_bool_t present; + struct sdio_dw *sd = slot->sd; + + present = (sdio_dw_readl(sd, CDETECT) & (1 << slot->id)) == 0; + + return present; +} + +static void sdio_dw_adjust_fifoth(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + static const rt_uint32_t mszs[] = { 1, 4, 8, 16, 32, 64, 128, 256 }; + rt_uint32_t blksz = data->blksize; + rt_uint32_t fifo_width = 1 << sd->data_shift; + rt_uint32_t blksz_depth = blksz / fifo_width, fifoth_val; + rt_uint32_t msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; + int idx = RT_ARRAY_SIZE(mszs) - 1; + + /* PIO should ship this scenario */ + if (!sd->use_dma) + { + return; + } + + tx_wmark = (sd->fifo_depth) / 2; + tx_wmark_invers = sd->fifo_depth - tx_wmark; + + /* MSIZE is '1', if blksz is not a multiple of the FIFO width */ + if (blksz % fifo_width) + { + goto _done; + } + + do { + if (!((blksz_depth % mszs[idx]) || (tx_wmark_invers % mszs[idx]))) + { + msize = idx; + rx_wmark = mszs[idx] - 1; + + break; + } + } while (--idx > 0); + /* If idx is '0', it won't be tried Thus, initial values are uesed */ + +_done: + fifoth_val = SDIO_DW_SET_FIFOTH(msize, rx_wmark, tx_wmark); + sdio_dw_writel(sd, FIFOTH, fifoth_val); +} + +static void sdio_dw_ctrl_thld(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_uint8_t enable; + rt_uint16_t thld_size; + rt_uint32_t blksz_depth, fifo_depth; + rt_uint32_t blksz = data->blksize; + + /* + * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is + * in the FIFO region, so we really shouldn't access it). + */ + if (sd->verid < SDIO_DW_240A || + (sd->verid < SDIO_DW_280A && (data->flags & DATA_DIR_WRITE))) + { + return; + } + + /* + * Card write Threshold is introduced since 2.80a + * It's used when HS400 mode is enabled. + */ + if ((data->flags & DATA_DIR_WRITE) && sd->timing != MMCSD_TIMING_MMC_HS400) + { + goto _disable; + } + + if ((data->flags & DATA_DIR_WRITE)) + { + enable = SDIO_DW_CARD_WR_THR_EN; + } + else + { + enable = SDIO_DW_CARD_RD_THR_EN; + } + + if (sd->timing != MMCSD_TIMING_MMC_HS200 && + sd->timing != MMCSD_TIMING_UHS_SDR104 && + sd->timing != MMCSD_TIMING_MMC_HS400) + { + goto _disable; + } + + blksz_depth = blksz / (1 << sd->data_shift); + fifo_depth = sd->fifo_depth; + + if (blksz_depth > fifo_depth) + { + goto _disable; + } + + /* + * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' + * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz + * Currently just choose blksz. + */ + thld_size = blksz; + sdio_dw_writel(sd, CDTHRCTL, SDIO_DW_SET_THLD(thld_size, enable)); + + return; + +_disable: + sdio_dw_writel(sd, CDTHRCTL, 0); +} + +static rt_err_t sdio_dw_submit_data_dma(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_uint32_t temp; + rt_ubase_t level; + + sd->using_dma = RT_FALSE; + + /* If we don't have a channel, we can't do DMA */ + if (!sd->use_dma) + { + return -RT_ENOSYS; + } + + sd->using_dma = RT_TRUE; + + /* + * Decide the MSIZE and RX/TX Watermark. If current block size is same with + * previous size, no need to update fifoth. + */ + if (sd->prev_blksz != data->blksize) + { + sdio_dw_adjust_fifoth(sd, data); + } + + /* Enable the DMA interface */ + temp = sdio_dw_readl(sd, CTRL); + temp |= SDIO_DW_CTRL_DMA_ENABLE; + sdio_dw_writel(sd, CTRL, temp); + + /* Disable RX/TX IRQs, let DMA handle it */ + level = rt_spin_lock_irqsave(&sd->irq_lock); + temp = sdio_dw_readl(sd, INTMASK); + temp &= ~(PINT(RXDR) | PINT(TXDR)); + sdio_dw_writel(sd, INTMASK, temp); + rt_spin_unlock_irqrestore(&sd->irq_lock, level); + + /* Flush data to memory */ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, sd->last_buf, sd->last_remain); + + if (sd->dma_ops->start(sd)) + { + /* We can't do DMA, try PIO for this one */ + sd->dma_ops->stop(sd); + + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static void sdio_dw_submit_data(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_ubase_t level; + rt_uint32_t temp; + + data->err = -RT_ERROR; + sd->data = data; + sd->last_buf = data->buf; + sd->last_remain = data->blks * data->blksize; + + if ((data->flags & DATA_DIR_READ)) + { + sd->dir_status = SDIO_DW_RECV_STATUS; + } + else + { + sd->dir_status = SDIO_DW_SEND_STATUS; + } + + sdio_dw_ctrl_thld(sd, data); + + if (sdio_dw_submit_data_dma(sd, data)) + { + sd->part_buf_start = 0; + sd->part_buf_count = 0; + + sdio_dw_writel(sd, RINTSTS, PINT(TXDR) | PINT(RXDR)); + + level = rt_spin_lock_irqsave(&sd->irq_lock); + temp = sdio_dw_readl(sd, INTMASK); + temp |= PINT(TXDR) | PINT(RXDR); + sdio_dw_writel(sd, INTMASK, temp); + rt_spin_unlock_irqrestore(&sd->irq_lock, level); + + temp = sdio_dw_readl(sd, CTRL); + temp &= ~SDIO_DW_CTRL_DMA_ENABLE; + sdio_dw_writel(sd, CTRL, temp); + + /* + * Use the initial fifoth_val for PIO mode. If wm_algined is set, we set + * watermark same as data size. If next issued data may be transfered by + * DMA mode, prev_blksz should be invalidated. + */ + if (sd->wm_aligned) + { + sdio_dw_adjust_fifoth(sd, data); + } + else + { + sdio_dw_writel(sd, FIFOTH, sd->fifoth_val); + } + sd->prev_blksz = 0; + } + else + { + /* + * Keep the current block size. + * It will be used to decide whether to update fifoth register next time. + */ + sd->prev_blksz = data->blksize; + } +} + +static void sdio_dw_setup_bus(struct sdio_dw_slot *slot, rt_bool_t force_clkinit) +{ + struct sdio_dw *sd = slot->sd; + rt_uint32_t clock = slot->clock; + rt_uint32_t cmd_bits = SDIO_DW_CMD_UPD_CLK | SDIO_DW_CMD_PRV_DAT_WAIT; + + /* We must continue to set bit 28 in CMD until the change is complete */ + if (sd->state == STATE_WAITING_CMD11_DONE) + { + cmd_bits |= SDIO_DW_CMD_VOLT_SWITCH; + } + + if (!clock) + { + sdio_dw_writel(sd, CLKENA, 0); + sdio_dw_send_cmd(slot, cmd_bits, 0); + } + else if (clock != sd->current_speed || force_clkinit) + { + rt_uint32_t clk_en_a, div = sd->bus_hz / clock; + + if (sd->bus_hz % clock && sd->bus_hz > clock) + { + /* Move the + 1 after the divide to prevent over-clocking the card */ + div += 1; + } + + div = (sd->bus_hz != clock) ? RT_DIV_ROUND_UP(div, 2) : 0; + + /* Disable clock */ + sdio_dw_writel(sd, CLKENA, 0); + sdio_dw_writel(sd, CLKSRC, 0); + + /* Inform CIU */ + sdio_dw_send_cmd(slot, cmd_bits, 0); + + /* Set clock to desired speed */ + sdio_dw_writel(sd, CLKDIV, div); + + /* Inform CIU */ + sdio_dw_send_cmd(slot, cmd_bits, 0); + + /* Enable clock; only low power if no SDIO */ + clk_en_a = SDIO_DW_CLKEN_ENABLE << slot->id; + if (!bitmap_test_bit(&slot->flags, DW_MMC_CARD_NO_LOW_PWR)) + { + clk_en_a |= SDIO_DW_CLKEN_LOW_PWR << slot->id; + } + sdio_dw_writel(sd, CLKENA, clk_en_a); + + /* Inform CIU */ + sdio_dw_send_cmd(slot, cmd_bits, 0); + + /* Keep the last clock value that was requested from core */ + slot->clk_old = clock; + } + + sd->current_speed = clock; + + /* Set the current slot bus width */ + sdio_dw_writel(sd, CTYPE, (slot->ctype << slot->id)); +} + +static void sdio_dw_set_data_timeout(struct sdio_dw *sd, rt_uint32_t timeout_ns) +{ + rt_uint64_t tmp; + rt_uint32_t clk_div, tmout; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + if (drv_data && drv_data->set_data_timeout) + { + drv_data->set_data_timeout(sd, timeout_ns); + + return; + } + + clk_div = (sdio_dw_readl(sd, CLKDIV) & 0xff) * 2; + + if (clk_div == 0) + { + clk_div = 1; + } + + tmp = RT_DIV_ROUND_UP_ULL((rt_uint64_t)timeout_ns * sd->bus_hz, NSEC_PER_SEC); + tmp = RT_DIV_ROUND_UP_ULL(tmp, clk_div); + + /* TMOUT[7:0] (RESPONSE_TIMEOUT): Set maximum */ + tmout = 0xff; + + /* TMOUT[31:8] (DATA_TIMEOUT) */ + if (!tmp || tmp > 0xffffff) + { + tmout |= (0xffffff << 8); + } + else + { + tmout |= (tmp & 0xffffff) << 8; + } + + sdio_dw_writel(sd, TMOUT, tmout); +} + +/* Push final bytes to part_buf, only use during push */ +static void sdio_dw_set_part_bytes(struct sdio_dw *sd, void *buf, int cnt) +{ + rt_memcpy((void *)&sd->part_buf, buf, cnt); + sd->part_buf_count = cnt; +} + +/* Append bytes to part_buf, only use during push */ +static int sdio_dw_push_part_bytes(struct sdio_dw *sd, void *buf, int cnt) +{ + cnt = rt_min(cnt, (1 << sd->data_shift) - sd->part_buf_count); + rt_memcpy((void *)&sd->part_buf + sd->part_buf_count, buf, cnt); + sd->part_buf_count += cnt; + + return cnt; +} + +/* Pull first bytes from part_buf, only use during pull */ +static int sdio_dw_pull_part_bytes(struct sdio_dw *sd, void *buf, int cnt) +{ + cnt = rt_min_t(int, cnt, sd->part_buf_count); + + if (cnt) + { + rt_memcpy(buf, (void *)&sd->part_buf + sd->part_buf_start, cnt); + sd->part_buf_count -= cnt; + sd->part_buf_start += cnt; + } + + return cnt; +} + +/* Pull final bytes from the part_buf, assuming it's just been filled */ +static void sdio_dw_pull_final_bytes(struct sdio_dw *sd, void *buf, int cnt) +{ + rt_memcpy(buf, &sd->part_buf, cnt); + sd->part_buf_start = cnt; + sd->part_buf_count = (1 << sd->data_shift) - cnt; +} + +static void sdio_dw_push_data16(struct sdio_dw *sd, void *buf, int cnt) +{ + struct rt_mmcsd_data *data = sd->data; + int init_cnt = cnt; + + /* Try and push anything in the part_buf */ + if ((sd->part_buf_count)) + { + int len = sdio_dw_push_part_bytes(sd, buf, cnt); + + buf += len; + cnt -= len; + + if (sd->part_buf_count == 2) + { + sdio_dw_fifo_writew(sd, sd->part_buf16); + sd->part_buf_count = 0; + } + } +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x1)) + { + while (cnt >= 2) + { + rt_uint16_t aligned_buf[64]; + int len = rt_min(cnt & -2, (int)sizeof(aligned_buf)); + int items = len >> 1; + + /* rt_memcpy from input buffer into aligned buffer */ + rt_memcpy(aligned_buf, buf, len); + buf += len; + cnt -= len; + + /* Push data from aligned buffer into fifo */ + for (int i = 0; i < items; ++i) + { + sdio_dw_fifo_writew(sd, aligned_buf[i]); + } + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint16_t *pdata = buf; + + for (; cnt >= 2; cnt -= 2) + { + sdio_dw_fifo_writew(sd, *pdata++); + } + buf = pdata; + } + /* Put anything remaining in the part_buf */ + if (cnt) + { + sdio_dw_set_part_bytes(sd, buf, cnt); + + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == (data->blksize * data->blks)) + { + sdio_dw_fifo_writew(sd, sd->part_buf16); + } + } +} + +static void sdio_dw_pull_data16(struct sdio_dw *sd, void *buf, int cnt) +{ +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x1)) + { + while (cnt >= 2) + { + /* Pull data from fifo into aligned buffer */ + rt_uint16_t aligned_buf[64]; + int len = rt_min(cnt & -2, (int)sizeof(aligned_buf)); + int items = len >> 1; + + for (int i = 0; i < items; ++i) + { + aligned_buf[i] = sdio_dw_fifo_readw(sd); + } + + /* rt_memcpy from aligned buffer into output buffer */ + rt_memcpy(buf, aligned_buf, len); + buf += len; + cnt -= len; + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint16_t *pdata = buf; + + for (; cnt >= 2; cnt -= 2) + { + *pdata++ = sdio_dw_fifo_readw(sd); + } + buf = pdata; + } + if (cnt) + { + sd->part_buf16 = sdio_dw_fifo_readw(sd); + sdio_dw_pull_final_bytes(sd, buf, cnt); + } +} + +static void sdio_dw_push_data32(struct sdio_dw *sd, void *buf, int cnt) +{ + struct rt_mmcsd_data *data = sd->data; + int init_cnt = cnt; + + /* Try and push anything in the part_buf */ + if ((sd->part_buf_count)) + { + int len = sdio_dw_push_part_bytes(sd, buf, cnt); + + buf += len; + cnt -= len; + + if (sd->part_buf_count == 4) + { + sdio_dw_fifo_writel(sd, sd->part_buf32); + sd->part_buf_count = 0; + } + } +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x3)) + { + while (cnt >= 4) + { + rt_uint32_t aligned_buf[32]; + int len = rt_min(cnt & -4, (int)sizeof(aligned_buf)); + int items = len >> 2; + + /* rt_memcpy from input buffer into aligned buffer */ + rt_memcpy(aligned_buf, buf, len); + buf += len; + cnt -= len; + + /* Push data from aligned buffer into fifo */ + for (int i = 0; i < items; ++i) + { + sdio_dw_fifo_writel(sd, aligned_buf[i]); + } + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint32_t *pdata = buf; + + for (; cnt >= 4; cnt -= 4) + { + sdio_dw_fifo_writel(sd, *pdata++); + } + buf = pdata; + } + /* Put anything remaining in the part_buf */ + if (cnt) + { + sdio_dw_set_part_bytes(sd, buf, cnt); + + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == (data->blksize * data->blks)) + { + sdio_dw_fifo_writel(sd, sd->part_buf32); + } + } +} + +static void sdio_dw_pull_data32(struct sdio_dw *sd, void *buf, int cnt) +{ +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x3)) + { + while (cnt >= 4) + { + /* Pull data from fifo into aligned buffer */ + rt_uint32_t aligned_buf[32]; + int len = rt_min(cnt & -4, (int)sizeof(aligned_buf)); + int items = len >> 2; + + for (int i = 0; i < items; ++i) + { + aligned_buf[i] = sdio_dw_fifo_readl(sd); + } + + /* rt_memcpy from aligned buffer into output buffer */ + rt_memcpy(buf, aligned_buf, len); + buf += len; + cnt -= len; + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint32_t *pdata = buf; + + for (; cnt >= 4; cnt -= 4) + { + *pdata++ = sdio_dw_fifo_readl(sd); + } + buf = pdata; + } + if (cnt) + { + sd->part_buf32 = sdio_dw_fifo_readl(sd); + sdio_dw_pull_final_bytes(sd, buf, cnt); + } +} + +static void sdio_dw_push_data64(struct sdio_dw *sd, void *buf, int cnt) +{ + struct rt_mmcsd_data *data = sd->data; + int init_cnt = cnt; + + /* Try and push anything in the part_buf */ + if ((sd->part_buf_count)) + { + int len = sdio_dw_push_part_bytes(sd, buf, cnt); + + buf += len; + cnt -= len; + + if (sd->part_buf_count == 8) + { + sdio_dw_fifo_writeq(sd, sd->part_buf64); + sd->part_buf_count = 0; + } + } +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x7)) + { + while (cnt >= 8) + { + rt_uint64_t aligned_buf[16]; + int len = rt_min(cnt & -8, (int)sizeof(aligned_buf)); + int items = len >> 3; + + /* rt_memcpy from input buffer into aligned buffer */ + rt_memcpy(aligned_buf, buf, len); + buf += len; + cnt -= len; + + /* Push data from aligned buffer into fifo */ + for (int i = 0; i < items; ++i) + { + sdio_dw_fifo_writeq(sd, aligned_buf[i]); + } + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint64_t *pdata = buf; + + for (; cnt >= 8; cnt -= 8) + { + sdio_dw_fifo_writeq(sd, *pdata++); + } + buf = pdata; + } + /* Put anything remaining in the part_buf */ + if (cnt) + { + sdio_dw_set_part_bytes(sd, buf, cnt); + + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == (data->blksize * data->blks)) + { + sdio_dw_fifo_writeq(sd, sd->part_buf64); + } + } +} + +static void sdio_dw_pull_data64(struct sdio_dw *sd, void *buf, int cnt) +{ +#ifndef ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS + if (((rt_ubase_t)buf & 0x7)) + { + while (cnt >= 8) + { + /* Pull data from fifo into aligned buffer */ + rt_uint64_t aligned_buf[16]; + int len = rt_min(cnt & -8, (int)sizeof(aligned_buf)); + int items = len >> 3; + + for (int i = 0; i < items; ++i) + { + aligned_buf[i] = sdio_dw_fifo_readq(sd); + } + + /* rt_memcpy from aligned buffer into output buffer */ + rt_memcpy(buf, aligned_buf, len); + buf += len; + cnt -= len; + } + } + else +#endif /* !ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + { + rt_uint64_t *pdata = buf; + + for (; cnt >= 8; cnt -= 8) + { + *pdata++ = sdio_dw_fifo_readq(sd); + } + buf = pdata; + } + if (cnt) + { + sd->part_buf64 = sdio_dw_fifo_readq(sd); + sdio_dw_pull_final_bytes(sd, buf, cnt); + } +} + +static void sdio_dw_pull_data(struct sdio_dw *sd, void *buf, int cnt) +{ + /* Get remaining partial bytes */ + int len = sdio_dw_pull_part_bytes(sd, buf, cnt); + + if (len != cnt) + { + buf += len; + cnt -= len; + + /* Get the rest of the data */ + sd->pull_data(sd, buf, cnt); + } +} + +static void sdio_dw_read_data_pio(struct sdio_dw *sd, rt_bool_t dto) +{ + void *buf; + int shift = sd->data_shift; + struct rt_mmcsd_data *data = sd->data; + rt_uint32_t status, remain, fcnt, len; + + buf = sd->last_buf; + remain = sd->last_remain; + + do { + if (!remain) + { + break; + } + + do { + fcnt = (SDIO_DW_GET_FCNT(sdio_dw_readl(sd, STATUS)) << shift) + sd->part_buf_count; + len = rt_min(remain, fcnt); + + if (!len) + { + break; + } + + sdio_dw_pull_data(sd, buf, len); + data->bytes_xfered += len; + buf += len; + remain -= len; + } while (remain); + + status = sdio_dw_readl(sd, MINTSTS); + sdio_dw_writel(sd, RINTSTS, PINT(RXDR)); + /* If the RXDR is ready read again */ + } while ((status & PINT(RXDR)) || (dto && SDIO_DW_GET_FCNT(sdio_dw_readl(sd, STATUS)))); + + sd->last_buf = remain ? buf : RT_NULL; + sd->last_remain = remain; + + rt_hw_wmb(); + bitmap_set_bit(&sd->pending_events, EVENT_XFER_COMPLETE); +} + +static void sdio_dw_write_data_pio(struct sdio_dw *sd) +{ + void *buf; + int shift = sd->data_shift; + struct rt_mmcsd_data *data = sd->data; + rt_uint32_t status, remain, fcnt, len, fifo_depth; + + buf = sd->last_buf; + remain = sd->last_remain; + fifo_depth = sd->fifo_depth; + + do { + if (!remain) + { + break; + } + + do { + fcnt = ((fifo_depth - SDIO_DW_GET_FCNT(sdio_dw_readl(sd, STATUS))) << shift) - sd->part_buf_count; + len = rt_min(remain, fcnt); + + if (!len) + { + break; + } + + sd->push_data(sd, buf, len); + data->bytes_xfered += len; + buf += len; + remain -= len; + } while (remain); + + status = sdio_dw_readl(sd, MINTSTS); + sdio_dw_writel(sd, RINTSTS, PINT(TXDR)); + /* If TXDR write again */ + } while ((status & PINT(TXDR))); + + sd->last_buf = remain ? buf : RT_NULL; + sd->last_remain = remain; + + rt_hw_wmb(); + bitmap_set_bit(&sd->pending_events, EVENT_XFER_COMPLETE); +} + +static void sdio_dw_init_dma(struct sdio_dw *sd) +{ + int addr_config; + + /* + * Check tansfer mode from HCON[17:16] + * Clear the ambiguous description of dw_mmc databook: + * 2b'00: No DMA Interface -> Actually means using Internal DMA block + * 2b'01: DesignWare DMA Interface -> Synopsys DW-DMA block + * 2b'10: Generic DMA Interface -> non-Synopsys generic DMA block + * 2b'11: Non DW DMA Interface -> pio only + * Compared to DesignWare DMA Interface, Generic DMA Interface has a simpler + * request/acknowledge handshake mechanism and both of them are regarded as + * external dma master for dw_mmc. + */ + sd->use_dma = SDIO_DW_GET_TRANS_MODE(sdio_dw_readl(sd, HCON)); + + if (sd->use_dma == DMA_INTERFACE_IDMA) + { + sd->use_dma = TRANS_MODE_IDMAC; + } + else if (sd->use_dma == DMA_INTERFACE_DWDMA || sd->use_dma == DMA_INTERFACE_GDMA) + { + sd->use_dma = TRANS_MODE_EDMAC; + } + else + { + goto _no_dma; + } + + /* Determine which DMA interface to use */ + if (sd->use_dma == TRANS_MODE_IDMAC) + { + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ + addr_config = SDIO_DW_GET_ADDR_CONFIG(sdio_dw_readl(sd, HCON)); + + /* Supports IDMAC in 64/32-bit address mode */ + sd->dma_64bit_address = (addr_config == 1); + LOG_D("IDMAC supports %s-bit address mode", sd->dma_64bit_address ? "64" : "32"); + + /* Alloc memory for translation */ + sd->dma_buf_cache = rt_pages_alloc(rt_page_bits(DESC_RING_BUF_SZ)); + + if (!sd->dma_buf_cache) + { + LOG_E("Could not alloc DMA memory witch cache"); + + goto _no_dma; + } + + sd->dma_buf_phy = (rt_ubase_t)rt_kmem_v2p(sd->dma_buf_cache); + sd->dma_buf = rt_ioremap_nocache((void *)sd->dma_buf_phy, DESC_RING_BUF_SZ); + + if (!sd->dma_buf) + { + rt_pages_free(sd->dma_buf_cache, rt_page_bits(DESC_RING_BUF_SZ)); + + LOG_E("Could not alloc DMA memory"); + + goto _no_dma; + } + + sd->dma_ops = &sdio_dw_idmac_ops; + LOG_D("Using internal DMA controller"); + } + else + { + if (!rt_dm_dev_prop_read_bool(&sd->parent, "dma-names") || + !rt_dm_dev_prop_read_bool(&sd->parent, "dmas")) + { + goto _no_dma; + } + + sd->dma_ops = &sdio_dw_edmac_ops; + LOG_D("Using external DMA controller"); + } + + if (sd->dma_ops->init && sd->dma_ops->start && sd->dma_ops->stop && sd->dma_ops->cleanup) + { + if (sd->dma_ops->init(sd)) + { + LOG_E("Unable to initialize DMA Controller"); + goto _no_dma; + } + } + else + { + LOG_E("DMA initialization not found"); + goto _no_dma; + } + + return; + +_no_dma: + LOG_D("Using PIO mode"); + sd->use_dma = TRANS_MODE_PIO; +} + +static rt_bool_t sdio_dw_reset(struct sdio_dw *sd) +{ + rt_err_t res = RT_FALSE; + rt_uint32_t flags = SDIO_DW_CTRL_RESET | SDIO_DW_CTRL_FIFO_RESET; + + if (sd->use_dma) + { + flags |= SDIO_DW_CTRL_DMA_RESET; + } + + if (sdio_dw_ctrl_reset(sd, flags)) + { + int timeout = 500 * USEC_PER_MSEC; + /* In all cases we clear the RAWINTS register to clear any interrupts */ + sdio_dw_writel(sd, RINTSTS, 0xffffffff); + + if (!sd->use_dma) + { + res = RT_TRUE; + goto _ciu_out; + } + + /* Wait for dma_req to be cleared */ + while ((sdio_dw_readl(sd, STATUS) & SDIO_DW_STATUS_DMA_REQ) && timeout--) + { + rt_hw_cpu_relax(); + } + + if (time <= 0) + { + LOG_E("Timeout waiting for dma_req to be cleared in reset"); + goto _ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!sdio_dw_ctrl_reset(sd, SDIO_DW_CTRL_FIFO_RESET)) + { + goto _ciu_out; + } + } + else + { + /* If the controller reset bit did clear, then set clock regs */ + if (!(sdio_dw_readl(sd, CTRL) & SDIO_DW_CTRL_RESET)) + { + LOG_E("FIFO/DMA reset bits didn't clear but ciu was reset, doing clock update"); + + goto _ciu_out; + } + } + + if (sd->use_dma == TRANS_MODE_IDMAC) + { + /* It is also required that we reinit idmac */ + sdio_dw_idmac_init(sd); + } + + res = RT_TRUE; + +_ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + sdio_dw_send_cmd(sd->slot, SDIO_DW_CMD_UPD_CLK, 0); + + return res; +} + +static void sdio_dw_start_request(struct sdio_dw *sd, struct rt_mmcsd_cmd *cmd) +{ + rt_uint32_t cmd_flags; + struct sdio_dw_slot *slot = sd->slot; + struct rt_mmcsd_data *data = cmd->data; + + if (sd->state == STATE_WAITING_CMD11_DONE) + { + sd->state = STATE_IDLE; + } + + if (sd->state == STATE_IDLE) + { + sd->state = STATE_SENDING_CMD; + } + + sd->req = sd->slot->req; + sd->cmd = cmd; + + sd->pending_events = 0; + sd->cmd_status = 0; + sd->data_status = 0; + sd->dir_status = 0; + + if (data) + { + sdio_dw_set_data_timeout(sd, data->timeout_ns); + sdio_dw_writel(sd, BYTCNT, data->blksize * data->blks); + sdio_dw_writel(sd, BLKSIZ, data->blksize); + } + + cmd_flags = cmd->cmd_code; + + if (cmd->cmd_code == STOP_TRANSMISSION || + cmd->cmd_code == GO_IDLE_STATE || + cmd->cmd_code == GO_INACTIVE_STATE || + (cmd->cmd_code == SD_IO_RW_DIRECT && ((cmd->arg >> 9) & 0x1ffff) == SDIO_REG_CCCR_IO_ABORT)) + { + cmd_flags |= SDIO_DW_CMD_STOP; + } + else if (cmd->cmd_code != SEND_STATUS && data) + { + cmd_flags |= SDIO_DW_CMD_PRV_DAT_WAIT; + } + + if (cmd->cmd_code == SD_SWITCH_VOLTAGE) + { + rt_uint32_t clk_en_a; + + /* Special bit makes CMD11 not die */ + cmd_flags |= SDIO_DW_CMD_VOLT_SWITCH; + + /* Change state to continue to handle CMD11 weirdness */ + sd->state = STATE_SENDING_CMD11; + + /* + * We need to disable low power mode (automatic clock stop) while + * doing voltage switch so we don't confuse the card, since stopping + * the clock is a specific part of the UHS voltage change dance. + * + * Note that low power mode (SDIO_DW_CLKEN_LOW_PWR) will be + * unconditionally turned back on in dw_mci_setup_bus() if it's ever + * called with a non-zero clock. That shouldn't happen until the + * voltage change is all done. + */ + clk_en_a = sdio_dw_readl(sd, CLKENA); + clk_en_a &= ~(SDIO_DW_CLKEN_LOW_PWR << slot->id); + sdio_dw_writel(sd, CLKENA, clk_en_a); + sdio_dw_send_cmd(sd->slot, SDIO_DW_CMD_UPD_CLK | SDIO_DW_CMD_PRV_DAT_WAIT, 0); + } + + switch (resp_type(cmd)) + { + case RESP_NONE: + break; + + case RESP_R1: + case RESP_R5: + case RESP_R6: + case RESP_R7: + case RESP_R1B: + cmd_flags |= SDIO_DW_CMD_RESP_EXP; + cmd_flags |= SDIO_DW_CMD_RESP_CRC; + break; + + case RESP_R2: + cmd_flags |= SDIO_DW_CMD_RESP_EXP; + cmd_flags |= SDIO_DW_CMD_RESP_CRC; + cmd_flags |= SDIO_DW_CMD_RESP_LONG; + break; + + case RESP_R3: + case RESP_R4: + cmd_flags |= SDIO_DW_CMD_RESP_EXP; + break; + + default: + LOG_D("Unsupported cmd type = %x", resp_type(cmd)); + break; + } + + if (data) + { + cmd_flags |= SDIO_DW_CMD_DAT_EXP; + + if ((data->flags & DATA_DIR_WRITE)) + { + cmd_flags |= SDIO_DW_CMD_DAT_WR; + } + } + + if (!bitmap_test_bit(&slot->flags, DW_MMC_CARD_NO_USE_HOLD)) + { + cmd_flags |= SDIO_DW_CMD_USE_HOLD_REG; + } + + if (bitmap_test_bit(&slot->flags, DW_MMC_CARD_NEED_INIT)) + { + cmd_flags |= SDIO_DW_CMD_INIT; + bitmap_clear_bit(&slot->flags, DW_MMC_CARD_NEED_INIT); + } + + if (data) + { + sdio_dw_submit_data(sd, data); + /* Drain writebuffer */ + rt_hw_wmb(); + } + + sdio_dw_start_cmd(slot, cmd_flags, cmd->arg); + + if (cmd->cmd_code == SD_SWITCH_VOLTAGE) + { + rt_ubase_t level = rt_spin_lock_irqsave(&sd->irq_lock); + + if (!bitmap_test_bit(&sd->pending_events, EVENT_CMD_COMPLETE)) + { + rt_tick_t tick = rt_tick_from_millisecond(500) + 1; + + rt_timer_control(&sd->cmd11_timer, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&sd->cmd11_timer); + } + + rt_spin_unlock_irqrestore(&sd->irq_lock, level); + } + + sd->stop_cmdr = sdio_dw_prep_stop_abort(sd, cmd); +} + +static void sdio_dw_end_request(struct sdio_dw *sd) +{ + sd->slot->req = RT_NULL; + sd->req = RT_NULL; + + if (sd->state == STATE_SENDING_CMD11) + { + sd->state = STATE_WAITING_CMD11_DONE; + } + else + { + sd->state = STATE_IDLE; + } + + rt_hw_spin_unlock(&sd->lock.lock); + + mmcsd_req_complete(sd->slot->host); + + rt_hw_spin_lock(&sd->lock.lock); +} + +static rt_err_t sdio_dw_cmd_complete(struct sdio_dw *sd, struct rt_mmcsd_cmd *cmd) +{ + rt_uint32_t status = sd->cmd_status; + + sd->cmd_status = 0; + + /* Read the response from the card (up to 16 bytes) */ + if (resp_type(cmd) == RESP_R2) + { + cmd->resp[0] = sdio_dw_readl(sd, RESP3); + cmd->resp[1] = sdio_dw_readl(sd, RESP2); + cmd->resp[2] = sdio_dw_readl(sd, RESP1); + cmd->resp[3] = sdio_dw_readl(sd, RESP0); + } + else + { + cmd->resp[0] = sdio_dw_readl(sd, RESP0); + } + + if ((status & PINT(RTO))) + { + cmd->err = -RT_ETIMEOUT; + } + else if ((resp_type(cmd) & (RESP_R1 | RESP_R5 | RESP_R6 | RESP_R7 | RESP_R1B)) && + (status & PINT(RCRC))) + { + cmd->err = -RT_EIO; + } + else if ((status & PINT(RESP_ERR))) + { + cmd->err = -RT_EIO; + } + else + { + cmd->err = RT_EOK; + } + + return cmd->err; +} + +static int sdio_dw_data_complete(struct sdio_dw *sd, struct rt_mmcsd_data *data) +{ + rt_uint32_t status = sd->data_status; + + if (status & SDIO_DW_DATA_ERROR_FLAGS) + { + if (status & PINT(DRTO)) + { + data->err = -RT_ETIMEOUT; + } + else if (status & PINT(DCRC)) + { + data->err = -RT_EIO; + } + else if (status & PINT(EBE)) + { + if (sd->dir_status == SDIO_DW_SEND_STATUS) + { + /* + * No data CRC status was returned. The number of bytes + * transferred will be exaggerated in PIO mode. + */ + data->bytes_xfered = 0; + data->err = -RT_ETIMEOUT; + } + else if (sd->dir_status == SDIO_DW_RECV_STATUS) + { + data->err = -RT_EIO; + } + } + else + { + /* PINT(SBE) is included */ + data->err = -RT_EIO; + } + + LOG_D("Data error, status 0x%x", status); + + /* After an error, there may be data lingering in the FIFO */ + sdio_dw_reset(sd); + } + else + { + data->bytes_xfered = data->blks * data->blksize; + data->err = RT_EOK; + } + + return data->err; +} + +static void sdio_dw_mmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req) +{ + struct sdio_dw_slot *slot = host->private_data; + struct sdio_dw *sd = slot->sd; + + /* + * The check for card presence and queueing of the request must be atomic, + * otherwise the card could be removed in between and the request wouldn't + * fail until another card was inserted. + */ + if (!sdio_dw_get_cd(slot)) + { + req->cmd->err = -RT_EIO; + mmcsd_req_complete(host); + + return; + } + + rt_hw_spin_lock(&sd->lock.lock); + + sd->slot->req = req; + sdio_dw_start_request(sd, req->sbc ? : req->cmd); + + rt_hw_spin_unlock(&sd->lock.lock); +} + +static void sdio_dw_mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *ios) +{ + rt_err_t err; + rt_uint32_t regs; + struct sdio_dw_slot *slot = host->private_data; + struct sdio_dw *sd = slot->sd; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + /* Bus */ + switch (ios->bus_width) + { + case MMCSD_BUS_WIDTH_4: + slot->ctype = SDIO_DW_CTYPE_4BIT; + break; + + case MMCSD_BUS_WIDTH_8: + slot->ctype = SDIO_DW_CTYPE_8BIT; + break; + + default: + slot->ctype = SDIO_DW_CTYPE_1BIT; + break; + } + + regs = sdio_dw_readl(sd, UHS_REG); + + /* DDR mode set */ + if (ios->timing == MMCSD_TIMING_MMC_DDR52 || + ios->timing == MMCSD_TIMING_UHS_DDR50 || + ios->timing == MMCSD_TIMING_MMC_HS400) + { + regs |= ((0x1 << slot->id) << 16); + } + else + { + regs &= ~((0x1 << slot->id) << 16); + } + + sdio_dw_writel(sd, UHS_REG, regs); + sd->timing = ios->timing; + + /* + * Use mirror of ios->clock to prevent race with mmc core ios update when + * finding the minimum. + */ + slot->clock = ios->clock; + + if (drv_data && drv_data->set_iocfg) + { + drv_data->set_iocfg(sd, ios); + } + + /* Power */ + switch (ios->power_mode) + { + case MMCSD_POWER_UP: + if (host->supply.vmmc) + { + err = sdio_regulator_set_ocr(host, host->supply.vmmc, ios->vdd); + + if (err) + { + LOG_E("Failed to enable vmmc regulator error = %s", rt_strerror(err)); + + return; + } + } + bitmap_set_bit(&slot->flags, DW_MMC_CARD_NEED_INIT); + regs = sdio_dw_readl(sd, PWREN); + regs |= (1 << slot->id); + sdio_dw_writel(sd, PWREN, regs); + break; + + case MMCSD_POWER_ON: + if (!sd->vqmmc_enabled) + { + if (host->supply.vqmmc) + { + err = rt_regulator_enable(host->supply.vqmmc); + + if (err) + { + LOG_E("Failed to enable vqmmc error = %s", rt_strerror(err)); + } + else + { + sd->vqmmc_enabled = RT_TRUE; + } + } + else + { + sd->vqmmc_enabled = RT_TRUE; + } + + sdio_dw_ctrl_reset(sd, SDIO_DW_CTRL_ALL_RESET_FLAGS); + } + + /* Adjust clock / bus width after power is up */ + sdio_dw_setup_bus(slot, RT_FALSE); + break; + + case MMCSD_POWER_OFF: + /* Turn clock off before power goes down */ + sdio_dw_setup_bus(slot, RT_FALSE); + + if (host->supply.vmmc) + { + sdio_regulator_set_ocr(host, host->supply.vmmc, 0); + } + + if (host->supply.vqmmc && sd->vqmmc_enabled) + { + rt_regulator_disable(host->supply.vqmmc); + } + + sd->vqmmc_enabled = RT_FALSE; + + regs = sdio_dw_readl(sd, PWREN); + regs &= ~(1 << slot->id); + sdio_dw_writel(sd, PWREN, regs); + break; + + default: + LOG_E("Invalid power_mode value %x", ios->power_mode); + break; + } + + if (sd->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) + { + sd->state = STATE_IDLE; + } +} + +static rt_int32_t sdio_dw_mmc_get_card_status(struct rt_mmcsd_host *host) +{ + return 0; +} + +static void sdio_dw_mmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable) +{ + rt_ubase_t level; + rt_uint32_t int_mask, clk_en_a_old, clk_en_a; + struct sdio_dw_slot *slot = host->private_data; + struct sdio_dw *sd = slot->sd; + const rt_uint32_t clken_low_pwr = SDIO_DW_CLKEN_LOW_PWR << slot->id; + + /* + * Low power mode will stop the card clock when idle. According to the + * description of the CLKENA register we should disable low power mode for + * SDIO cards if we need SDIO interrupts to work. + */ + clk_en_a_old = sdio_dw_readl(sd, CLKENA); + + if (enable) + { + bitmap_set_bit(&slot->flags, DW_MMC_CARD_NO_LOW_PWR); + clk_en_a = clk_en_a_old & ~clken_low_pwr; + } + else + { + bitmap_clear_bit(&slot->flags, DW_MMC_CARD_NO_LOW_PWR); + clk_en_a = clk_en_a_old | clken_low_pwr; + } + + if (clk_en_a != clk_en_a_old) + { + sdio_dw_writel(sd, CLKENA, clk_en_a); + sdio_dw_send_cmd(slot, SDIO_DW_CMD_UPD_CLK | SDIO_DW_CMD_PRV_DAT_WAIT, 0); + } + + level = rt_spin_lock_irqsave(&sd->irq_lock); + + /* Enable/disable Slot Specific SDIO interrupt */ + int_mask = sdio_dw_readl(sd, INTMASK); + if (enable) + { + int_mask |= SDIO_DW_INT_SDIO(slot->sdio_id); + } + else + { + int_mask &= ~SDIO_DW_INT_SDIO(slot->sdio_id); + } + sdio_dw_writel(sd, INTMASK, int_mask); + + rt_spin_unlock_irqrestore(&sd->irq_lock, level); +} + +static rt_int32_t sdio_dw_mmc_execute_tuning(struct rt_mmcsd_host *host, rt_int32_t opcode) +{ + struct sdio_dw_slot *slot = host->private_data; + struct sdio_dw *sd = slot->sd; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + if (drv_data && drv_data->execute_tuning) + { + return drv_data->execute_tuning(slot, opcode); + } + + return -RT_EINVAL; +} + +static rt_bool_t sdio_dw_mmc_card_busy(struct rt_mmcsd_host *host) +{ + rt_uint32_t status; + struct sdio_dw_slot *slot = host->private_data; + + /* Check the busy bit which is low when DAT[3:0] (the data lines) are 0000 */ + status = sdio_dw_readl(slot->sd, STATUS); + + return !!(status & SDIO_DW_STATUS_BUSY); +} + +static rt_err_t sdio_dw_mmc_signal_voltage_switch(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *ios) +{ + rt_uint32_t uhs, v18; + struct sdio_dw_slot *slot = host->private_data; + struct sdio_dw *sd = slot->sd; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + v18 = SDIO_DW_UHS_18V << slot->id; + + if (drv_data && drv_data->switch_voltage) + { + return drv_data->switch_voltage(host, ios); + } + + /* + * Program the voltage. Note that some instances of dw_mmc may use + * the UHS_REG for this. For other instances (like exynos) the UHS_REG + * does no harm but you need to set the regulator directly. Try both. + */ + uhs = sdio_dw_readl(sd, UHS_REG); + if (ios->signal_voltage == MMCSD_SIGNAL_VOLTAGE_330) + { + uhs &= ~v18; + } + else + { + uhs |= v18; + } + + if (host->supply.vqmmc) + { + rt_err_t err = sdio_regulator_set_vqmmc(host, ios); + + if (err < 0) + { + LOG_D("Regulator set error %s to %s V", rt_strerror(err), + uhs & v18 ? "1.8" : "3.3"); + + return err; + } + } + sdio_dw_writel(sd, UHS_REG, uhs); + + return RT_EOK; +} + +static const struct rt_mmcsd_host_ops sdio_dw_mmc_ops = +{ + .request = sdio_dw_mmc_request, + .set_iocfg = sdio_dw_mmc_set_iocfg, + .get_card_status = sdio_dw_mmc_get_card_status, + .enable_sdio_irq = sdio_dw_mmc_enable_sdio_irq, + .execute_tuning = sdio_dw_mmc_execute_tuning, + .card_busy = sdio_dw_mmc_card_busy, + .signal_voltage_switch = sdio_dw_mmc_signal_voltage_switch, +}; + +static void sdio_dw_set_drto(struct sdio_dw *sd) +{ + rt_ubase_t level; + rt_uint32_t drto_clks, drto_div, drto_ms; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + if (drv_data && drv_data->get_drto_clks) + { + drto_clks = drv_data->get_drto_clks(sd); + } + else + { + drto_clks = sdio_dw_readl(sd, TMOUT) >> 8; + } + + drto_div = (sdio_dw_readl(sd, CLKDIV) & 0xff) * 2; + + if (drto_div == 0) + { + drto_div = 1; + } + + drto_ms = RT_DIV_ROUND_UP_ULL((rt_uint64_t)MSEC_PER_SEC * drto_clks * drto_div, + sd->bus_hz); + + /* Add a bit spare time */ + drto_ms += 10; + + level = rt_spin_lock_irqsave(&sd->irq_lock); + + if (!bitmap_test_bit(&sd->pending_events, EVENT_DATA_COMPLETE)) + { + rt_tick_t tick = rt_tick_from_millisecond(drto_ms); + + rt_timer_control(&sd->dto_timer, RT_TIMER_CTRL_SET_TIME, &tick); + + rt_timer_start(&sd->dto_timer); + } + + rt_spin_unlock_irqrestore(&sd->irq_lock, level); +} + +static rt_bool_t sdio_dw_clear_pending_cmd_complete(struct sdio_dw *sd) +{ + if (!bitmap_test_bit(&sd->pending_events, EVENT_CMD_COMPLETE)) + { + return RT_FALSE; + } + + rt_timer_stop(&sd->cto_timer); + bitmap_clear_bit(&sd->pending_events, EVENT_CMD_COMPLETE); + + return RT_TRUE; +} + +static rt_bool_t sdio_dw_clear_pending_data_complete(struct sdio_dw *sd) +{ + if (!bitmap_test_bit(&sd->pending_events, EVENT_DATA_COMPLETE)) + { + return RT_FALSE; + } + + rt_timer_stop(&sd->dto_timer); + bitmap_clear_bit(&sd->pending_events, EVENT_DATA_COMPLETE); + + return RT_TRUE; +} + +static void sdio_dw_state_change(struct rt_work *work, void *work_data) +{ + rt_err_t err; + rt_uint32_t state, prev_state; + struct rt_mmcsd_cmd *cmd; + struct rt_mmcsd_req *req; + struct rt_mmcsd_data *data; + struct sdio_dw *sd = rt_container_of(work, struct sdio_dw, state_work); + + rt_hw_spin_lock(&sd->lock.lock); + + state = sd->state; + req = sd->req; + data = sd->data; + +_next_status: + prev_state = state; + + switch (state) + { + case STATE_IDLE: + case STATE_WAITING_CMD11_DONE: + break; + + case STATE_SENDING_CMD11: + case STATE_SENDING_CMD: + if (!sdio_dw_clear_pending_cmd_complete(sd)) + { + break; + } + + cmd = sd->cmd; + sd->cmd = RT_NULL; + err = sdio_dw_cmd_complete(sd, cmd); + if (cmd == req->sbc && !err) + { + sdio_dw_start_request(sd, req->cmd); + + goto _unlock; + } + + if (cmd->data && err) + { + if (err != -RT_ETIMEOUT && sd->dir_status == SDIO_DW_RECV_STATUS) + { + state = STATE_SENDING_DATA; + + goto _check_status; + } + + send_stop_abort(sd, data); + sdio_dw_stop_dma(sd); + state = STATE_SENDING_STOP; + break; + } + + if (!cmd->data || err) + { + sdio_dw_end_request(sd); + + goto _unlock; + } + + prev_state = state = STATE_SENDING_DATA; + + /* Fall through */ + case STATE_SENDING_DATA: + if (bitmap_test_bit(&sd->pending_events, EVENT_DATA_ERROR)) + { + bitmap_clear_bit(&sd->pending_events, EVENT_DATA_ERROR); + + if (!(sd->data_status & (PINT(DRTO) | PINT(EBE)))) + { + send_stop_abort(sd, data); + } + + sdio_dw_stop_dma(sd); + state = STATE_DATA_ERROR; + break; + } + + if (!bitmap_test_bit(&sd->pending_events, EVENT_XFER_COMPLETE)) + { + /* + * If all data-related interrupts don't come within the given time + * in reading data state. + */ + if (sd->dir_status == SDIO_DW_RECV_STATUS) + { + sdio_dw_set_drto(sd); + } + + break; + } + bitmap_clear_bit(&sd->pending_events, EVENT_XFER_COMPLETE); + + /* + * Handle an EVENT_DATA_ERROR that might have shown up before the + * transfer completed. This might not have been caught by the check + * above because the interrupt could have gone off between the previous + * check and the check for transfer complete. + * + * Technically this ought not be needed assuming we get a DATA_COMPLETE + * eventually (we'll notice the error and end the request), but it + * shouldn't hurt. + * + * This has the advantage of sending the stop command. + */ + if (bitmap_test_bit(&sd->pending_events, EVENT_DATA_ERROR)) + { + bitmap_clear_bit(&sd->pending_events, EVENT_DATA_ERROR); + + if (!(sd->data_status & (PINT(DRTO) | PINT(EBE)))) + { + send_stop_abort(sd, data); + } + + sdio_dw_stop_dma(sd); + state = STATE_DATA_ERROR; + break; + } + prev_state = state = STATE_DATA_BUSY; + + /* Fall through */ + case STATE_DATA_BUSY: + if (!sdio_dw_clear_pending_data_complete(sd)) + { + /* + * If data error interrupt comes but data over interrupt doesn't + * come within the given time. In reading data state. + */ + if (sd->dir_status == SDIO_DW_RECV_STATUS) + { + sdio_dw_set_drto(sd); + } + + break; + } + + sd->data = RT_NULL; + err = sdio_dw_data_complete(sd, data); + + if (!err) + { + if (!data->stop || req->sbc) + { + if (req->sbc && data->stop) + { + data->stop->err = RT_EOK; + } + + sdio_dw_end_request(sd); + + goto _unlock; + } + + /* Stop command for open-ended transfer */ + if (data->stop) + { + send_stop_abort(sd, data); + } + } + else + { + /* + * If we don't have a command complete now we'll never get one since + * we just reset everything; better end the request. + * + * If we do have a command complete we'll fall through to the + * STATE_SENDING_STOP command and everything will be peachy keen. + */ + if (!bitmap_test_bit(&sd->pending_events, EVENT_CMD_COMPLETE)) + { + sd->cmd = RT_NULL; + + sdio_dw_end_request(sd); + + goto _unlock; + } + } + + /* If err has non-zero, stop-abort command has been already issued. */ + prev_state = state = STATE_SENDING_STOP; + + /* Fall through */ + case STATE_SENDING_STOP: + if (!sdio_dw_clear_pending_cmd_complete(sd)) + { + break; + } + + /* CMD error in data command */ + if (req->cmd->err && req->data) + { + sdio_dw_reset(sd); + } + + sd->cmd = RT_NULL; + sd->data = RT_NULL; + + if (!req->sbc && req->stop) + { + sdio_dw_cmd_complete(sd, req->stop); + } + else + { + sd->cmd_status = 0; + } + + sdio_dw_end_request(sd); + goto _unlock; + + case STATE_DATA_ERROR: + if (!bitmap_test_bit(&sd->pending_events, EVENT_XFER_COMPLETE)) + { + break; + } + bitmap_clear_bit(&sd->pending_events, EVENT_XFER_COMPLETE); + + state = STATE_DATA_BUSY; + break; + + default: + break; + } + +_check_status: + if (state != prev_state) + { + goto _next_status; + } + + sd->state = state; +_unlock: + rt_hw_spin_unlock(&sd->lock.lock); +} + +static void sdio_dw_cmd11_timer(void *param) +{ + struct sdio_dw *sd = param; + + if (sd->state != STATE_SENDING_CMD11) + { + LOG_W("Unexpected CMD11 timeout"); + + return; + } + + sd->cmd_status = PINT(RTO); + bitmap_set_bit(&sd->pending_events, EVENT_CMD_COMPLETE); + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); +} + +static void sdio_dw_cto_timer(void *param) +{ + rt_ubase_t level; + rt_uint32_t pending; + struct sdio_dw *sd = param; + + level = rt_spin_lock_irqsave(&sd->irq_lock); + + /* + * If somehow we have very bad interrupt latency it's remotely possible that + * the timer could fire while the interrupt is still pending or while the + * interrupt is midway through running. Let's be paranoid and detect those + * two cases. Note that this is paranoia is somewhat justified because in + * this function we don't actually cancel the pending command in the + * controller, we just assume it will never come. + */ + /* Read-only mask reg */ + pending = sdio_dw_readl(sd, MINTSTS); + + if ((pending & (SDIO_DW_CMD_ERROR_FLAGS | PINT(CMD_DONE)))) + { + /* The interrupt should fire; no need to act but we can warn */ + LOG_W("Unexpected interrupt latency"); + + goto _unlock; + } + + if (bitmap_test_bit(&sd->pending_events, EVENT_CMD_COMPLETE)) + { + /* Presumably interrupt handler couldn't delete the timer */ + LOG_W("CTO timeout when already completed"); + + goto _unlock; + } + + /* + * Continued paranoia to make sure we're in the state we expect. + * This paranoia isn't really justified but it seems good to be safe. + */ + switch (sd->state) + { + case STATE_SENDING_CMD11: + case STATE_SENDING_CMD: + case STATE_SENDING_STOP: + /* + * If CMD_DONE interrupt does NOT come in sending command state, we + * should notify the driver to terminate current transfer and report a + * command timeout to the core. + */ + sd->cmd_status = PINT(RTO); + bitmap_set_bit(&sd->pending_events, EVENT_CMD_COMPLETE); + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); + break; + + default: + LOG_W("Unexpected command timeout, state %d", sd->state); + break; + } + +_unlock: + rt_spin_unlock_irqrestore(&sd->irq_lock, level); +} + +static void sdio_dw_dto_timer(void *param) +{ + rt_ubase_t level; + rt_uint32_t pending; + struct sdio_dw *sd = param; + + level = rt_spin_lock_irqsave(&sd->irq_lock); + + /* + * The DTO timer is much longer than the CTO timer, so it's even less likely + * that we'll these cases, but it pays to be paranoid. + */ + /* Read-only mask reg */ + pending = sdio_dw_readl(sd, MINTSTS); + + if ((pending & PINT(DATA_OVER))) + { + /* The interrupt should fire; no need to act but we can warn */ + LOG_W("Unexpected data interrupt latency"); + + goto _unlock; + } + + if (bitmap_test_bit(&sd->pending_events, EVENT_DATA_COMPLETE)) + { + /* Presumably interrupt handler couldn't delete the timer */ + LOG_W("DTO timeout when already completed"); + + goto _unlock; + } + + /* + * Continued paranoia to make sure we're in the state we expect. + * This paranoia isn't really justified but it seems good to be safe. + */ + switch (sd->state) + { + case STATE_SENDING_DATA: + case STATE_DATA_BUSY: + /* + * If DTO interrupt does NOT come in sending data state, we should + * notify the driver to terminate current transfer and report a data + * timeout to the core. + */ + sd->data_status = PINT(DRTO); + bitmap_set_bit(&sd->pending_events, EVENT_DATA_ERROR); + bitmap_set_bit(&sd->pending_events, EVENT_DATA_COMPLETE); + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); + break; + + default: + LOG_W("Unexpected data timeout, state %d", sd->state); + break; + } + +_unlock: + rt_spin_unlock_irqrestore(&sd->irq_lock, level); +} + +static void sdio_dw_cmd_interrupt(struct sdio_dw *sd, rt_uint32_t status) +{ + rt_timer_stop(&sd->cto_timer); + + if (!sd->cmd_status) + { + sd->cmd_status = status; + } + + /* Drain writebuffer */ + rt_hw_wmb(); + + bitmap_set_bit(&sd->pending_events, EVENT_CMD_COMPLETE); + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); +} + +static void sdio_dw_isr(int irqno, void *param) +{ + rt_uint32_t pending; + struct sdio_dw *sd = (struct sdio_dw *)param; + struct sdio_dw_slot *slot = sd->slot; + + /* Read-only mask reg */ + pending = sdio_dw_readl(sd, MINTSTS); + + if (pending) + { + if (sd->state == STATE_SENDING_CMD11 && (pending & PINT(VOLT_SWITCH))) + { + sdio_dw_writel(sd, RINTSTS, PINT(VOLT_SWITCH)); + pending &= ~PINT(VOLT_SWITCH); + + rt_hw_spin_lock(&sd->irq_lock.lock); + sdio_dw_cmd_interrupt(sd, pending); + rt_hw_spin_unlock(&sd->irq_lock.lock); + + rt_timer_stop(&sd->cmd11_timer); + } + + if ((pending & SDIO_DW_CMD_ERROR_FLAGS)) + { + rt_hw_spin_lock(&sd->irq_lock.lock); + + rt_timer_stop(&sd->cto_timer); + sdio_dw_writel(sd, RINTSTS, SDIO_DW_CMD_ERROR_FLAGS); + sd->cmd_status = pending; + rt_hw_wmb(); + bitmap_set_bit(&sd->pending_events, EVENT_CMD_COMPLETE); + + rt_hw_spin_unlock(&sd->irq_lock.lock); + } + + if ((pending & SDIO_DW_DATA_ERROR_FLAGS)) + { + rt_hw_spin_lock(&sd->irq_lock.lock); + + if ((sd->quirks & SDIO_DW_QUIRK_EXTENDED_TMOUT)) + { + rt_timer_stop(&sd->dto_timer); + } + + sdio_dw_writel(sd, RINTSTS, SDIO_DW_DATA_ERROR_FLAGS); + sd->data_status = pending; + rt_hw_wmb(); + bitmap_set_bit(&sd->pending_events, EVENT_DATA_ERROR); + + if ((sd->quirks & SDIO_DW_QUIRK_EXTENDED_TMOUT)) + { + /* In case of error, we cannot expect a DTO */ + bitmap_set_bit(&sd->pending_events, EVENT_DATA_COMPLETE); + } + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); + + rt_hw_spin_unlock(&sd->irq_lock.lock); + } + + if ((pending & PINT(DATA_OVER))) + { + rt_hw_spin_lock(&sd->irq_lock.lock); + + rt_timer_stop(&sd->dto_timer); + + sdio_dw_writel(sd, RINTSTS, PINT(DATA_OVER)); + if (!sd->data_status) + { + sd->data_status = pending; + } + rt_hw_wmb(); + + if (sd->dir_status == SDIO_DW_RECV_STATUS && sd->data && sd->data->buf) + { + sdio_dw_read_data_pio(sd, RT_TRUE); + } + bitmap_set_bit(&sd->pending_events, EVENT_DATA_COMPLETE); + + rt_workqueue_urgent_work(sd->state_wq, &sd->state_work); + + rt_hw_spin_unlock(&sd->irq_lock.lock); + } + + if ((pending & PINT(RXDR))) + { + sdio_dw_writel(sd, RINTSTS, PINT(RXDR)); + + if (sd->dir_status == SDIO_DW_RECV_STATUS && sd->data && sd->data->buf) + { + sdio_dw_read_data_pio(sd, RT_FALSE); + } + } + + if ((pending & PINT(TXDR))) + { + sdio_dw_writel(sd, RINTSTS, PINT(TXDR)); + + if (sd->dir_status == SDIO_DW_SEND_STATUS && sd->data && sd->data->buf) + { + sdio_dw_write_data_pio(sd); + } + } + + if ((pending & PINT(CMD_DONE))) + { + rt_hw_spin_lock(&sd->irq_lock.lock); + + sdio_dw_writel(sd, RINTSTS, PINT(CMD_DONE)); + sdio_dw_cmd_interrupt(sd, pending); + + rt_hw_spin_unlock(&sd->irq_lock.lock); + } + + if ((pending & PINT(CD))) + { + sdio_dw_writel(sd, RINTSTS, PINT(CD)); + mmcsd_change(slot->host); + } + + if ((pending & SDIO_DW_INT_SDIO(slot->sdio_id))) + { + sdio_dw_writel(sd, RINTSTS, SDIO_DW_INT_SDIO(slot->sdio_id)); + sdio_dw_mmc_enable_sdio_irq(slot->host, RT_FALSE); + sdio_irq_wakeup(slot->host); + } + } + + if (sd->use_dma != TRANS_MODE_IDMAC) + { + return; + } + + /* Handle IDMA interrupts */ + pending = sd->dma_64bit_address ? sdio_dw_readl(sd, IDSTS64) : sdio_dw_readl(sd, IDSTS); + + if ((pending & (PINTC(TI) | PINTC(RI)))) + { + if (sd->dma_64bit_address) + { + sdio_dw_writel(sd, IDSTS64, PINTC(TI) | PINTC(RI)); + sdio_dw_writel(sd, IDSTS64, PINTC(NI)); + } + else + { + sdio_dw_writel(sd, IDSTS, PINTC(TI) | PINTC(RI)); + sdio_dw_writel(sd, IDSTS, PINTC(NI)); + } + + if (!bitmap_test_bit(&sd->pending_events, EVENT_DATA_ERROR)) + { + sd->dma_ops->complete(sd); + } + } +} + +#ifdef RT_USING_OFW +static rt_err_t sdio_dw_parse_ofw(struct sdio_dw *sd) +{ + struct rt_ofw_node *np = sd->parent.ofw_node; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + rt_ofw_prop_read_u32(np, "fifo-depth", &sd->fifo_depth); + rt_ofw_prop_read_u32(np, "card-detect-delay", &sd->detect_delay_ms); + rt_ofw_prop_read_u32(np, "data-addr", &sd->data_addr_override); + + if (rt_ofw_prop_read_bool(np, "fifo-watermark-aligned")) + { + sd->wm_aligned = RT_TRUE; + } + + rt_ofw_prop_read_u32(np, "clock-frequency", &sd->bus_hz); + + if (drv_data && drv_data->parse_ofw) + { + return drv_data->parse_ofw(sd); + } + + return RT_EOK; +} +#else +rt_inline rt_err_t sdio_dw_parse_ofw(struct sdio_dw *sd) +{ + return -RT_ENOSYS; +} +#endif /* RT_USING_OFW */ + +static rt_err_t sdio_dw_init_slot(struct sdio_dw *sd) +{ + rt_err_t err; + struct sdio_dw_slot *slot; + struct rt_mmcsd_host *host = mmcsd_alloc_host(); + + if (!host) + { + return -RT_ENOMEM; + } + + slot = rt_calloc(1, sizeof(*slot)); + + if (!slot) + { + err = -RT_ENOMEM; + goto _free; + } + + err = sdio_regulator_get_supply(&sd->parent, host); + + if (err) + { + goto _free; + } + + host->ops = &sdio_dw_mmc_ops; + host->private_data = slot; + slot->host = host; + slot->sd = sd; + sd->slot = slot; + + slot->id = 0; + slot->sdio_id = sd->sdio_id0 + slot->id; + + err = sdio_ofw_parse(sd->parent.ofw_node, host); + + if (err) + { + goto _free; + } + + if (!host->valid_ocr) + { + host->valid_ocr = VDD_32_33 | VDD_33_34; + } + + if (sd->minimum_speed) + { + host->freq_min = sd->minimum_speed; + } + else + { + host->freq_min = SDIO_DW_FREQ_HZ_MIN; + } + + if (!host->freq_max) + { + host->freq_max = SDIO_DW_FREQ_HZ_MAX; + } + + /* Useful defaults if platform data is unset. */ + if (sd->use_dma == TRANS_MODE_IDMAC) + { + host->max_dma_segs = sd->ring_size; + host->max_blk_size = 65535; + host->max_seg_size = DESC_RING_BUF_SZ; + host->max_blk_count = (host->max_seg_size * sd->ring_size) / 512; + } + else if (sd->use_dma == TRANS_MODE_EDMAC) + { + host->max_dma_segs = 64; + host->max_blk_size = 65535; + host->max_blk_count = 65535; + host->max_seg_size = host->max_blk_size * host->max_blk_count; + } + else + { + /* TRANS_MODE_PIO */ + host->max_dma_segs = 64; + host->max_blk_size = 65535; + host->max_blk_count = 512; + host->max_seg_size = host->max_blk_size * host->max_blk_count; + } + + return RT_EOK; + +_free: + if (host) + { + mmcsd_free_host(host); + } + if (slot) + { + rt_free(slot); + } + return err; +} + +static void sdio_dw_free(struct sdio_dw *sd) +{ + if (sd->rstc) + { + rt_reset_control_assert(sd->rstc); + rt_reset_control_put(sd->rstc); + } + + if (sd->ciu_clk) + { + rt_clk_disable_unprepare(sd->ciu_clk); + rt_clk_put(sd->biu_clk); + } + + if (sd->biu_clk) + { + rt_clk_disable_unprepare(sd->biu_clk); + rt_clk_put(sd->ciu_clk); + } + + if (sd->dma_buf_cache) + { + rt_pages_free(sd->dma_buf_cache, rt_page_bits(DESC_RING_BUF_SZ)); + } + + if (sd->dma_buf) + { + rt_iounmap(sd->dma_buf); + } +} + +rt_err_t sdio_dw_probe(struct sdio_dw *sd) +{ + int i, len; + rt_err_t err = RT_EOK; + char dev_name[RT_NAME_MAX]; + const struct sdio_dw_drv_data *drv_data = sd->drv_data; + + err = sdio_dw_parse_ofw(sd); + + if (err && err != -RT_ENOSYS) + { + goto _free_res; + } + + if (rt_dm_dev_prop_read_bool(&sd->parent, "resets")) + { + if (!(sd->rstc = rt_reset_control_get_by_name(&sd->parent, "reset"))) + { + LOG_E("Reset controller not found"); + + err = -RT_EIO; + goto _free_res; + } + } + + if (sd->rstc) + { + rt_reset_control_assert(sd->rstc); + rt_hw_us_delay(20); + rt_reset_control_deassert(sd->rstc); + } + + sd->biu_clk = rt_clk_get_by_name(&sd->parent, "biu"); + sd->ciu_clk = rt_clk_get_by_name(&sd->parent, "ciu"); + + if (!sd->biu_clk || !sd->ciu_clk) + { + /* board has init clock */ + if (sd->bus_hz) + { + goto _out_clk; + } + + err = -RT_EIO; + goto _free_res; + } + + err = rt_clk_prepare_enable(sd->ciu_clk); + + if (err) + { + goto _free_res; + } + + rt_clk_set_rate(sd->ciu_clk, sd->bus_hz); + sd->bus_hz = rt_clk_get_rate(sd->ciu_clk); + + if (!sd->bus_hz) + { + LOG_E("Bus speed not found"); + } + +_out_clk: + if (drv_data && drv_data->init) + { + err = drv_data->init(sd); + + if (err) + { + goto _free_res; + } + } + + rt_spin_lock_init(&sd->lock); + rt_spin_lock_init(&sd->irq_lock); + + rt_pin_ctrl_confs_apply_by_name(&sd->parent, RT_NULL); + + /* + * Get the host data width - this assumes that HCON has been set with the + * correct values. + */ + i = SDIO_DW_GET_HDATA_WIDTH(sdio_dw_readl(sd, HCON)); + if (!i) + { + sd->push_data = sdio_dw_push_data16; + sd->pull_data = sdio_dw_pull_data16; + sd->data_shift = 1; + } + else if (i == 2) + { + sd->push_data = sdio_dw_push_data64; + sd->pull_data = sdio_dw_pull_data64; + sd->data_shift = 3; + } + else + { + /* Check for a reserved value, and warn if it is */ + if (i != 1) + { + LOG_W("HCON reports a reserved host data width, defaulting to 32-bit access"); + } + + sd->push_data = sdio_dw_push_data32; + sd->pull_data = sdio_dw_pull_data32; + sd->data_shift = 2; + } + + /* Reset all blocks */ + if (!sdio_dw_ctrl_reset(sd, SDIO_DW_CTRL_ALL_RESET_FLAGS)) + { + err = -RT_EIO; + + goto _free_res; + } + + sdio_dw_init_dma(sd); + + /* Clear the interrupts for the host controller */ + sdio_dw_writel(sd, RINTSTS, 0xffffffff); + /* Disable all mmc interrupt first */ + sdio_dw_writel(sd, INTMASK, 0); + + /* Put in max timeout */ + sdio_dw_writel(sd, TMOUT, 0xffffffff); + + /* + * FIFO threshold settings: + * Rx Mark = fifo_size / 2 - 1, + * Tx Mark = fifo_size / 2 + * DMA Size = 8 + */ + if (sd->fifo_depth) + { + /* + * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may have been + * overwritten by the bootloader, just like we're about to do, so if you + * know the value for your hardware, you should put it in the platform + * data. + */ + sd->fifo_depth = sdio_dw_readl(sd, FIFOTH); + sd->fifo_depth = 1 + ((sd->fifo_depth >> 16) & 0xfff); + } + sd->fifoth_val = SDIO_DW_SET_FIFOTH(0x2, sd->fifo_depth / 2 - 1, sd->fifo_depth / 2); + sdio_dw_writel(sd, FIFOTH, sd->fifoth_val); + + /* Disable clock to CIU */ + sdio_dw_writel(sd, CLKENA, 0); + sdio_dw_writel(sd, CLKSRC, 0); + + /* + * In 2.40a spec, Data offset is changed. + * Need to check the version-id and set data-offset for DATA register. + */ + sd->verid = SDIO_DW_GET_VERID(sdio_dw_readl(sd, VERID)); + LOG_D("Version ID is %04x", sd->verid); + + if (sd->data_addr_override) + { + sd->fifo_base = sd->base + sd->data_addr_override; + } + else if (sd->verid < SDIO_DW_240A) + { + sd->fifo_base = sd->base + DATA_OFFSET; + } + else + { + sd->fifo_base = sd->base + DATA_240A_OFFSET; + } + + /* + * Enable interrupts for command done, data over, data empty, receive ready + * and error such as transmit, receive timeout, crc error + */ + sdio_dw_writel(sd, INTMASK, PINT(CMD_DONE) | PINT(DATA_OVER) | PINT(TXDR) | PINT(RXDR) | SDIO_DW_ERROR_FLAGS); + /* Enable mci interrupt */ + sdio_dw_writel(sd, CTRL, SDIO_DW_CTRL_INT_ENABLE); + + /* Enable GPIO interrupt */ + sdio_dw_writel(sd, INTMASK, sdio_dw_readl(sd, INTMASK) | PINT(CD)); + + /* We need at least one slot to succeed */ + err = sdio_dw_init_slot(sd); + + if (err) + { + goto _free_res; + } + + /* Now that slots are all setup, we can enable card detect */ + sdio_dw_writel(sd, INTMASK, sdio_dw_readl(sd, INTMASK) | PINT(CD)); + + len = sdio_host_set_name(sd->slot->host, dev_name); + + sd->state_wq = rt_workqueue_create(dev_name, RT_SYSTEM_WORKQUEUE_STACKSIZE, + rt_min(RT_SDIO_THREAD_PRIORITY, RT_MMCSD_THREAD_PREORITY)); + + if (!sd->state_wq) + { + err = -RT_ENOMEM; + + goto _free_res; + } + + rt_work_init(&sd->state_work, sdio_dw_state_change, sd); + + rt_hw_interrupt_install(sd->irq, sdio_dw_isr, sd, dev_name); + rt_hw_interrupt_umask(sd->irq); + + rt_strncpy(&dev_name[len], "-cmd11", sizeof(dev_name) - len); + rt_timer_init(&sd->cmd11_timer, dev_name, sdio_dw_cmd11_timer, sd, + 0, RT_TIMER_FLAG_PERIODIC); + + rt_strncpy(&dev_name[len], "-cto", sizeof(dev_name) - len); + rt_timer_init(&sd->cto_timer, dev_name, sdio_dw_cto_timer, sd, + 0, RT_TIMER_FLAG_PERIODIC); + + rt_strncpy(&dev_name[len], "-dto", sizeof(dev_name) - len); + rt_timer_init(&sd->dto_timer, dev_name, sdio_dw_dto_timer, sd, + 0, RT_TIMER_FLAG_PERIODIC); + + mmcsd_change(sd->slot->host); + + return err; + +_free_res: + sdio_dw_free(sd); + + return err; +} + +rt_err_t sdio_dw_remove(struct sdio_dw *sd) +{ + if (sd->slot) + { + mmcsd_free_host(sd->slot->host); + } + + sdio_dw_writel(sd, RINTSTS, 0xffffffff); + /* Disable all mmc interrupt first */ + sdio_dw_writel(sd, INTMASK, 0); + + /* Disable clock to CIU */ + sdio_dw_writel(sd, CLKENA, 0); + sdio_dw_writel(sd, CLKSRC, 0); + + rt_hw_interrupt_mask(sd->irq); + rt_hw_interrupt_uninstall(sd->irq, sdio_dw_isr, sd); + + rt_timer_detach(&sd->cmd11_timer); + rt_timer_detach(&sd->cto_timer); + rt_timer_detach(&sd->dto_timer); + + sdio_dw_free(sd); + + return RT_EOK; +} diff --git a/components/drivers/sdio/host/sdio-dw.h b/components/drivers/sdio/host/sdio-dw.h new file mode 100644 index 000000000000..aa0db9182e9b --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw.h @@ -0,0 +1,359 @@ +/* + * 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 + */ + +#ifndef __SDIO_DW_H__ +#define __SDIO_DW_H__ + +#include "../sdio_dm.h" + +#define SDIO_DW_CTRL 0x000 +#define SDIO_DW_PWREN 0x004 +#define SDIO_DW_CLKDIV 0x008 +#define SDIO_DW_CLKSRC 0x00c +#define SDIO_DW_CLKENA 0x010 +#define SDIO_DW_TMOUT 0x014 +#define SDIO_DW_CTYPE 0x018 +#define SDIO_DW_BLKSIZ 0x01c +#define SDIO_DW_BYTCNT 0x020 +#define SDIO_DW_INTMASK 0x024 +#define SDIO_DW_CMDARG 0x028 +#define SDIO_DW_CMD 0x02c +#define SDIO_DW_RESP0 0x030 +#define SDIO_DW_RESP1 0x034 +#define SDIO_DW_RESP2 0x038 +#define SDIO_DW_RESP3 0x03c +#define SDIO_DW_MINTSTS 0x040 +#define SDIO_DW_RINTSTS 0x044 +#define SDIO_DW_STATUS 0x048 +#define SDIO_DW_FIFOTH 0x04c +#define SDIO_DW_CDETECT 0x050 +#define SDIO_DW_WRTPRT 0x054 +#define SDIO_DW_GPIO 0x058 +#define SDIO_DW_TCBCNT 0x05c +#define SDIO_DW_TBBCNT 0x060 +#define SDIO_DW_DEBNCE 0x064 +#define SDIO_DW_USRID 0x068 +#define SDIO_DW_VERID 0x06c +#define SDIO_DW_HCON 0x070 +#define SDIO_DW_UHS_REG 0x074 +#define SDIO_DW_RST_N 0x078 +#define SDIO_DW_BMOD 0x080 +#define SDIO_DW_PLDMND 0x084 +#define SDIO_DW_DBADDR 0x088 +#define SDIO_DW_IDSTS 0x08c +#define SDIO_DW_IDINTEN 0x090 +#define SDIO_DW_DSCADDR 0x094 +#define SDIO_DW_BUFADDR 0x098 +#define SDIO_DW_CDTHRCTL 0x100 +#define SDIO_DW_UHS_REG_EXT 0x108 +#define SDIO_DW_DDR_REG 0x10c +#define SDIO_DW_ENABLE_SHIFT 0x110 +#define SDIO_DW_DATA(x) (x) +/* + * Registers to support idmac 64-bit address mode + */ +#define SDIO_DW_DBADDRL 0x088 +#define SDIO_DW_DBADDRU 0x08c +#define SDIO_DW_IDSTS64 0x090 +#define SDIO_DW_IDINTEN64 0x094 +#define SDIO_DW_DSCADDRL 0x098 +#define SDIO_DW_DSCADDRU 0x09c +#define SDIO_DW_BUFADDRL 0x0a0 +#define SDIO_DW_BUFADDRU 0x0a4 + +/* Support for longer data read timeout */ +#define SDIO_DW_QUIRK_EXTENDED_TMOUT RT_BIT(0) + +#define SDIO_DW_240A 0x240a +#define SDIO_DW_280A 0x280a + +/* + * Data offset is difference according to Version + * Lower than 2.40a : data register offest is 0x100 + */ +#define DATA_OFFSET 0x100 +#define DATA_240A_OFFSET 0x200 + +/* Control register defines */ +#define SDIO_DW_CTRL_USE_IDMAC RT_BIT(25) +#define SDIO_DW_CTRL_CEATA_INT_EN RT_BIT(11) +#define SDIO_DW_CTRL_SEND_AS_CCSD RT_BIT(10) +#define SDIO_DW_CTRL_SEND_CCSD RT_BIT(9) +#define SDIO_DW_CTRL_ABRT_READ_DATA RT_BIT(8) +#define SDIO_DW_CTRL_SEND_IRQ_RESP RT_BIT(7) +#define SDIO_DW_CTRL_READ_WAIT RT_BIT(6) +#define SDIO_DW_CTRL_DMA_ENABLE RT_BIT(5) +#define SDIO_DW_CTRL_INT_ENABLE RT_BIT(4) +#define SDIO_DW_CTRL_DMA_RESET RT_BIT(2) +#define SDIO_DW_CTRL_FIFO_RESET RT_BIT(1) +#define SDIO_DW_CTRL_RESET RT_BIT(0) +/* Clock Enable register defines */ +#define SDIO_DW_CLKEN_LOW_PWR RT_BIT(16) +#define SDIO_DW_CLKEN_ENABLE RT_BIT(0) +/* Time-out register defines */ +#define SDIO_DW_TMOUT_DATA(n) ((n) << 8) +#define SDIO_DW_TMOUT_DATA_MSK 0xffffff00 +#define SDIO_DW_TMOUT_RESP(n) ((n) & 0xff) +#define SDIO_DW_TMOUT_RESP_MSK 0xff +/* Card-type register defines */ +#define SDIO_DW_CTYPE_8BIT RT_BIT(16) +#define SDIO_DW_CTYPE_4BIT RT_BIT(0) +#define SDIO_DW_CTYPE_1BIT 0 +/* Interrupt status & mask register defines */ +#define SDIO_DW_INT_SDIO(n) RT_BIT(16 + (n)) +#define SDIO_DW_INT_RAW_SDIO RT_BIT(24) +#define SDIO_DW_INT_EBE RT_BIT(15) +#define SDIO_DW_INT_ACD RT_BIT(14) +#define SDIO_DW_INT_SBE RT_BIT(13) +#define SDIO_DW_INT_HLE RT_BIT(12) +#define SDIO_DW_INT_FRUN RT_BIT(11) +#define SDIO_DW_INT_HTO RT_BIT(10) +#define SDIO_DW_INT_VOLT_SWITCH RT_BIT(10) +#define SDIO_DW_INT_DRTO RT_BIT(9) +#define SDIO_DW_INT_RTO RT_BIT(8) +#define SDIO_DW_INT_DCRC RT_BIT(7) +#define SDIO_DW_INT_RCRC RT_BIT(6) +#define SDIO_DW_INT_RXDR RT_BIT(5) +#define SDIO_DW_INT_TXDR RT_BIT(4) +#define SDIO_DW_INT_DATA_OVER RT_BIT(3) +#define SDIO_DW_INT_CMD_DONE RT_BIT(2) +#define SDIO_DW_INT_RESP_ERR RT_BIT(1) +#define SDIO_DW_INT_CD RT_BIT(0) +#define SDIO_DW_INT_ERROR 0xbfc2 +/* Command register defines */ +#define SDIO_DW_CMD_START RT_BIT(31) +#define SDIO_DW_CMD_USE_HOLD_REG RT_BIT(29) +#define SDIO_DW_CMD_VOLT_SWITCH RT_BIT(28) +#define SDIO_DW_CMD_CCS_EXP RT_BIT(23) +#define SDIO_DW_CMD_CEATA_RD RT_BIT(22) +#define SDIO_DW_CMD_UPD_CLK RT_BIT(21) +#define SDIO_DW_CMD_INIT RT_BIT(15) +#define SDIO_DW_CMD_STOP RT_BIT(14) +#define SDIO_DW_CMD_PRV_DAT_WAIT RT_BIT(13) +#define SDIO_DW_CMD_SEND_STOP RT_BIT(12) +#define SDIO_DW_CMD_STRM_MODE RT_BIT(11) +#define SDIO_DW_CMD_DAT_WR RT_BIT(10) +#define SDIO_DW_CMD_DAT_EXP RT_BIT(9) +#define SDIO_DW_CMD_RESP_CRC RT_BIT(8) +#define SDIO_DW_CMD_RESP_LONG RT_BIT(7) +#define SDIO_DW_CMD_RESP_EXP RT_BIT(6) +#define SDIO_DW_CMD_INDX(n) ((n) & 0x1f) +/* Status register defines */ +#define SDIO_DW_GET_FCNT(x) (((x) >> 17) & 0x1fff) +#define SDIO_DW_STATUS_DMA_REQ RT_BIT(31) +#define SDIO_DW_STATUS_BUSY RT_BIT(9) +/* FIFOTH register defines */ +#define SDIO_DW_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | ((r) & 0xfff) << 16 | ((t) & 0xfff)) +/* HCON register defines */ +#define DMA_INTERFACE_IDMA (0x0) +#define DMA_INTERFACE_DWDMA (0x1) +#define DMA_INTERFACE_GDMA (0x2) +#define DMA_INTERFACE_NODMA (0x3) +#define SDIO_DW_GET_TRANS_MODE(x) (((x) >> 16) & 0x3) +#define SDIO_DW_GET_SLOT_NUM(x) ((((x) >> 1) & 0x1f) + 1) +#define SDIO_DW_GET_HDATA_WIDTH(x) (((x) >> 7) & 0x7) +#define SDIO_DW_GET_ADDR_CONFIG(x) (((x) >> 27) & 0x1) +/* Internal DMAC interrupt defines */ +#define SDIO_DW_IDMAC_INT_AI RT_BIT(9) +#define SDIO_DW_IDMAC_INT_NI RT_BIT(8) +#define SDIO_DW_IDMAC_INT_CES RT_BIT(5) +#define SDIO_DW_IDMAC_INT_DU RT_BIT(4) +#define SDIO_DW_IDMAC_INT_FBE RT_BIT(2) +#define SDIO_DW_IDMAC_INT_RI RT_BIT(1) +#define SDIO_DW_IDMAC_INT_TI RT_BIT(0) +/* Internal DMAC bus mode bits */ +#define SDIO_DW_IDMAC_ENABLE RT_BIT(7) +#define SDIO_DW_IDMAC_FB RT_BIT(1) +#define SDIO_DW_IDMAC_SWRESET RT_BIT(0) +/* H/W reset */ +#define SDIO_DW_RST_HWACTIVE 0x1 +/* Version ID register define */ +#define SDIO_DW_GET_VERID(x) ((x) & 0xffff) +/* Card read threshold */ +#define SDIO_DW_SET_THLD(v, x) (((v) & 0xfff) << 16 | (x)) +#define SDIO_DW_CARD_WR_THR_EN RT_BIT(2) +#define SDIO_DW_CARD_RD_THR_EN RT_BIT(0) +/* UHS-1 register defines */ +#define SDIO_DW_UHS_DDR RT_BIT(16) +#define SDIO_DW_UHS_18V RT_BIT(0) +/* DDR register defines */ +#define SDIO_DW_DDR_HS400 RT_BIT(31) +/* Enable shift register defines */ +#define SDIO_DW_ENABLE_PHASE RT_BIT(0) +/* All ctrl reset bits */ +#define SDIO_DW_CTRL_ALL_RESET_FLAGS (SDIO_DW_CTRL_RESET | SDIO_DW_CTRL_FIFO_RESET | SDIO_DW_CTRL_DMA_RESET) + +struct sdio_dw +{ + struct rt_device parent; + + struct rt_workqueue *state_wq; + struct rt_work state_work; + + void *base; + void *fifo_base; + rt_ubase_t base_phy; + rt_uint32_t data_addr_override; + rt_bool_t wm_aligned; + + int irq; + int sdio_id0; + rt_uint32_t verid; + rt_uint32_t quirks; + rt_uint32_t bus_hz; + rt_bool_t fifo_mode; + rt_uint32_t fifo_depth; + rt_uint32_t fifoth_val; + rt_uint32_t detect_delay_ms; + rt_uint32_t current_speed; + rt_uint32_t minimum_speed; + void *priv; + + rt_uint32_t vqmmc_enabled; + rt_uint32_t cmd_status; + rt_uint32_t data_status; + rt_uint32_t stop_cmdr; + rt_uint32_t dir_status; +#define STATE_IDLE 0 +#define STATE_SENDING_CMD 1 +#define STATE_SENDING_DATA 2 +#define STATE_DATA_BUSY 3 +#define STATE_SENDING_STOP 4 +#define STATE_DATA_ERROR 5 +#define STATE_SENDING_CMD11 6 +#define STATE_WAITING_CMD11_DONE 7 + rt_uint32_t state; +#define EVENT_CMD_COMPLETE 0 +#define EVENT_XFER_COMPLETE 1 +#define EVENT_DATA_COMPLETE 2 +#define EVENT_DATA_ERROR 3 + bitmap_t pending_events; + + struct rt_mmcsd_req *req; + struct rt_mmcsd_data *data; + struct rt_mmcsd_cmd *cmd; + struct rt_mmcsd_cmd stop_abort; + rt_uint32_t prev_blksz; + rt_uint8_t timing; + + struct rt_clk *biu_clk; + struct rt_clk *ciu_clk; + + void *last_buf; + rt_uint32_t last_remain; + + int data_shift; + rt_uint8_t part_buf_start; + rt_uint8_t part_buf_count; + union + { + rt_uint64_t part_buf; + rt_uint16_t part_buf16; + rt_uint32_t part_buf32; + rt_uint64_t part_buf64; + }; + void (*push_data)(struct sdio_dw *sd, void *buf, int cnt); + void (*pull_data)(struct sdio_dw *sd, void *buf, int cnt); + + /* DMA interface members */ +#define TRANS_MODE_PIO 0 +#define TRANS_MODE_IDMAC 1 +#define TRANS_MODE_EDMAC 2 + rt_bool_t use_dma; + rt_bool_t using_dma; + rt_bool_t dma_64bit_address; + rt_size_t ring_size; + void *dma_buf; + void *dma_buf_cache; + rt_ubase_t dma_buf_phy; + const struct sdio_dw_dma_ops *dma_ops; + + struct rt_timer cmd11_timer; + struct rt_timer cto_timer; + struct rt_timer dto_timer; + + struct rt_reset_control *rstc; + + struct sdio_dw_slot *slot; + const struct sdio_dw_drv_data *drv_data; + + struct rt_spinlock lock, irq_lock; +}; + +/* DMA ops for Internal/External DMAC interface */ +struct sdio_dw_dma_ops +{ + rt_err_t (*init)(struct sdio_dw *sd); + rt_err_t (*start)(struct sdio_dw *sd); + rt_err_t (*complete)(struct sdio_dw *sd); + rt_err_t (*stop)(struct sdio_dw *sd); + rt_err_t (*cleanup)(struct sdio_dw *sd); + rt_err_t (*exit)(struct sdio_dw *sd); +}; + +struct sdio_dw_slot +{ + struct rt_mmcsd_host *host; + struct sdio_dw *sd; + + rt_uint32_t ctype; + + struct rt_mmcsd_req *req; + + rt_uint32_t clock; + rt_uint32_t clk_old; + +#define DW_MMC_CARD_PRESENT 0 +#define DW_MMC_CARD_NEED_INIT 1 +#define DW_MMC_CARD_NO_LOW_PWR 2 +#define DW_MMC_CARD_NO_USE_HOLD 3 +#define DW_MMC_CARD_NEEDS_POLL 4 + bitmap_t flags; + + int id; + int sdio_id; +}; + +struct sdio_dw_drv_data +{ + rt_ubase_t *caps; + rt_uint32_t num_caps; + rt_uint32_t common_caps; + + rt_err_t (*init)(struct sdio_dw *sd); + rt_err_t (*set_iocfg)(struct sdio_dw *sd, struct rt_mmcsd_io_cfg *ios); + rt_err_t (*parse_ofw)(struct sdio_dw *sd); + rt_err_t (*execute_tuning)(struct sdio_dw_slot *slot, rt_uint32_t opcode); + rt_err_t (*prepare_hs400_tuning)(struct sdio_dw *sd, struct rt_mmcsd_io_cfg *ios); + rt_err_t (*switch_voltage)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *ios); + rt_err_t (*set_data_timeout)(struct sdio_dw *sd, rt_uint32_t timeout_ns); + rt_uint32_t (*get_drto_clks)(struct sdio_dw *sd); +}; + +#define sdio_dw_writel(sd, reg, val) HWREG32((sd)->base + SDIO_DW_##reg) = (val) +#define sdio_dw_writew(sd, reg, val) HWREG16((sd)->base + SDIO_DW_##reg) = (val) +#define sdio_dw_writeb(sd, reg, val) HWREG8((sd)->base + SDIO_DW_##reg) = (val) + +#define sdio_dw_readl(sd, reg) HWREG32((sd)->base + SDIO_DW_##reg) +#define sdio_dw_readw(sd, reg) HWREG16((sd)->base + SDIO_DW_##reg) +#define sdio_dw_readb(sd, reg) HWREG8((sd)->base + SDIO_DW_##reg) + +#define sdio_dw_fifo_writew(sd, val) HWREG16((sd)->fifo_base) = (val) +#define sdio_dw_fifo_writel(sd, val) HWREG32((sd)->fifo_base) = (val) +#define sdio_dw_fifo_writeq(sd, val) HWREG64((sd)->fifo_base) = (val) + +#define sdio_dw_fifo_readw(sd) HWREG16((sd)->fifo_base) +#define sdio_dw_fifo_readl(sd) HWREG32((sd)->fifo_base) +#define sdio_dw_fifo_readq(sd) HWREG64((sd)->fifo_base) + +rt_err_t sdio_dw_probe(struct sdio_dw *sd); +rt_err_t sdio_dw_remove(struct sdio_dw *sd); + +#endif /* __SDIO_DW_H__ */ diff --git a/components/drivers/sdio/host/sdio-dw_rockchip.c b/components/drivers/sdio/host/sdio-dw_rockchip.c new file mode 100644 index 000000000000..c5866ccaf43b --- /dev/null +++ b/components/drivers/sdio/host/sdio-dw_rockchip.c @@ -0,0 +1,350 @@ +/* + * 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 "sdio-dw.h" +#include "sdio-dw-platfrom.h" + +#define DBG_TAG "sdio.dw.rockchip" +#define DBG_LVL DBG_INFO +#include + +#define RK3288_CLKGEN_DIV 2 + +struct phases_range +{ + int start; + int end; +}; + +struct sdio_dw_rockchip_platfrom_data +{ + struct rt_clk *drv_clk; + struct rt_clk *sample_clk; + + rt_uint32_t default_sample_phase; + rt_uint32_t num_phases; + struct phases_range phases[]; +}; + +static const rt_uint32_t freqs[] = +{ + 100000, 200000, 300000, 400000 +}; + +static rt_err_t sdio_dw_rockchip_probe(struct rt_platform_device *pdev) +{ + const struct sdio_dw_drv_data *drv_data = pdev->id->data; + + return sdio_dw_platfrom_register(pdev, drv_data); +} + +static rt_err_t sdio_dw_rockchip_init(struct sdio_dw *sd) +{ + /* It is slot 8 on Rockchip SoCs */ + sd->sdio_id0 = 8; + + if (rt_ofw_node_is_compatible(sd->parent.ofw_node, "rockchip,rk3288-dw-mshc")) + { + rt_base_t rate; + + sd->bus_hz /= RK3288_CLKGEN_DIV; + + /* + * clock driver will fail if the clock is less than the lowest source + * clock divided by the internal clock divider. Test for the lowest + * available clock and set the minimum freq to clock / clock divider. + */ + for (int i = 0; i < RT_ARRAY_SIZE(freqs); ++i) + { + rate = rt_clk_round_rate(sd->ciu_clk, freqs[i] * RK3288_CLKGEN_DIV); + + if (rate > 0) + { + sd->minimum_speed = rate / RK3288_CLKGEN_DIV; + + break; + } + } + + if (rate < 0) + { + LOG_W("No valid minimum freq error = %s", rt_strerror(rate)); + } + } + + return RT_EOK; +} + +static rt_err_t sdio_dw_rk3288_set_iocfg(struct sdio_dw *sd, struct rt_mmcsd_io_cfg *ios) +{ + rt_uint32_t freq, bus_hz; + struct sdio_dw_rockchip_platfrom_data *pdata = sd->priv; + + if (!ios->clock) + { + return RT_EOK; + } + + freq = ios->clock * RK3288_CLKGEN_DIV; + + /* + * The clock frequency chosen here affects CLKDIV in the dw_mmc core. + * That can be either 0 or 1, but it must be set to 1 for eMMC DDR52 + * 8-bit mode. It will be set to 0 for all other modes. + */ + if (ios->bus_width == MMCSD_BUS_WIDTH_8 && ios->timing == MMCSD_TIMING_MMC_DDR52) + { + freq *= 2; + } + + rt_clk_set_rate(sd->ciu_clk, freq); + bus_hz = rt_clk_get_rate(sd->ciu_clk) / RK3288_CLKGEN_DIV; + + if (bus_hz != sd->bus_hz) + { + sd->bus_hz = bus_hz; + sd->current_speed = 0; + } + + if (pdata->sample_clk && ios->timing <= MMCSD_TIMING_SD_HS) + { + rt_clk_set_phase(pdata->sample_clk, pdata->default_sample_phase); + } + + if (pdata->drv_clk) + { + int phase = 90; + + switch (ios->timing) + { + case MMCSD_TIMING_MMC_DDR52: + /* + * Since clock in rate with MMC_DDR52 is doubled when + * bus width is 8 we need to double the phase offset + * to get the same timings. + */ + if (ios->bus_width == MMCSD_BUS_WIDTH_8) + { + phase = 180; + } + break; + case MMCSD_TIMING_UHS_SDR104: + case MMCSD_TIMING_MMC_HS200: + /* + * In the case of 150 MHz clock (typical max for + * Rockchip SoCs), 90 degree offset will add a delay + * of 1.67 ns. That will meet min hold time of .8 ns + * as long as clock output delay is < .87 ns. On + * SoCs measured this seems to be OK, but it doesn't + * hurt to give margin here, so we use 180. + */ + phase = 180; + break; + } + + rt_clk_set_phase(pdata->drv_clk, phase); + } + + return RT_EOK; +} + +static rt_err_t sdio_dw_rk3288_parse_ofw(struct sdio_dw *sd) +{ + rt_err_t err = RT_EOK; + rt_uint32_t num_phases; + struct rt_ofw_node *np = sd->parent.ofw_node; + struct sdio_dw_rockchip_platfrom_data *pdata; + + if (rt_ofw_prop_read_u32(np, "rockchip,desired-num-phases", &num_phases)) + { + num_phases = 360; + } + + pdata = rt_malloc(sizeof(*pdata) + sizeof(struct phases_range) * num_phases); + + if (!pdata) + { + return -RT_ENOMEM; + } + + pdata->num_phases = num_phases; + + if (rt_ofw_prop_read_u32(np, "rockchip,default-sample-phase", &pdata->default_sample_phase)) + { + pdata->default_sample_phase = 0; + } + + pdata->drv_clk = rt_ofw_get_clk_by_name(np, "ciu-drive"); + + if (!pdata->drv_clk) + { + pdata->drv_clk = rt_ofw_get_clk_by_name(np, "ciu-drv"); + } + + pdata->sample_clk = rt_ofw_get_clk_by_name(np, "ciu-sample"); + + sd->priv = pdata; + + return err; +} + +#define TUNING_ITERATION_TO_PHASE(i, num_phases) \ + (RT_DIV_ROUND_UP((i) * 360, num_phases)) + +static rt_err_t sdio_dw_rk3288_execute_tuning(struct sdio_dw_slot *slot, + rt_uint32_t opcode) +{ + rt_err_t err = RT_EOK; + rt_bool_t tuning, prev_tuning = 0, first_tuning; + int range_count = 0, longest_range_len = -1, longest_range = -1, middle_phase; + struct rt_mmcsd_host *host = slot->host; + struct sdio_dw_rockchip_platfrom_data *pdata = slot->sd->priv; + struct phases_range *ranges = pdata->phases; + + if (!pdata->sample_clk) + { + return -RT_EIO; + } + + for (int i = 0; i < pdata->num_phases;) + { + rt_clk_set_phase(pdata->sample_clk, + TUNING_ITERATION_TO_PHASE(i, pdata->num_phases)); + + tuning = !mmcsd_send_tuning(host, opcode, RT_NULL); + + if (i == 0) + { + first_tuning = tuning; + } + + if ((!prev_tuning) && tuning) + { + ++range_count; + ranges[range_count - 1].start = i; + } + if (tuning) + { + ranges[range_count - 1].end = i; + ++i; + } + else if (i == pdata->num_phases - 1) + { + /* No extra skipping rules if we're at the end */ + ++i; + } + else + { + /* + * No need to check too close to an invalid one since + * testing bad phases is slow. Skip 20 degrees. + */ + i += RT_DIV_ROUND_UP(20 * pdata->num_phases, 360); + + /* Always test the last one */ + if (i >= pdata->num_phases) + { + i = pdata->num_phases - 1; + } + } + + prev_tuning = tuning; + } + + if (range_count == 0) + { + LOG_W("All phases bad!"); + + return -RT_EIO; + } + + /* wrap around case, merge the end points */ + if (range_count > 1 && first_tuning && tuning) + { + ranges[0].start = ranges[range_count - 1].start; + --range_count; + } + + if (ranges[0].start == 0 && ranges[0].end == pdata->num_phases - 1) + { + rt_clk_set_phase(pdata->sample_clk, pdata->default_sample_phase); + LOG_I("All phases work, using default phase %u", pdata->default_sample_phase); + + return RT_EOK; + } + + /* Find the longest range */ + for (int i = 0; i < range_count; ++i) + { + int len = (ranges[i].end - ranges[i].start + 1); + + if (len < 0) + { + len += pdata->num_phases; + } + + if (longest_range_len < len) + { + longest_range_len = len; + longest_range = i; + } + + LOG_D("%s phase range %d-%d (%d len)", + "Good", + TUNING_ITERATION_TO_PHASE(ranges[i].start, pdata->num_phases), + TUNING_ITERATION_TO_PHASE(ranges[i].end, pdata->num_phases), + len); + } + + LOG_D("%s phase range %d-%d (%d len)", + "Best", + TUNING_ITERATION_TO_PHASE(ranges[longest_range].start, pdata->num_phases), + TUNING_ITERATION_TO_PHASE(ranges[longest_range].end, pdata->num_phases), + longest_range_len); + + middle_phase = ranges[longest_range].start + longest_range_len / 2; + middle_phase %= pdata->num_phases; + LOG_I("Successfully tuned phase to %d", + TUNING_ITERATION_TO_PHASE(middle_phase, pdata->num_phases)); + + rt_clk_set_phase(pdata->sample_clk, + TUNING_ITERATION_TO_PHASE(middle_phase, pdata->num_phases)); + + return err; +} + +static const struct sdio_dw_drv_data rk2928_drv_data = +{ + .init = sdio_dw_rockchip_init, +}; + +static const struct sdio_dw_drv_data rk3288_drv_data = +{ + .init = sdio_dw_rockchip_init, + .set_iocfg = sdio_dw_rk3288_set_iocfg, + .parse_ofw = sdio_dw_rk3288_parse_ofw, + .execute_tuning = sdio_dw_rk3288_execute_tuning, +}; + +static const struct rt_ofw_node_id sdio_dw_rockchip_ofw_ids[] = +{ + { .compatible = "rockchip,rk2928-dw-mshc", .data = &rk2928_drv_data }, + { .compatible = "rockchip,rk3288-dw-mshc", .data = &rk3288_drv_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver sdio_dw_rockchip_driver = +{ + .name = "dw-mmc-rockchip", + .ids = sdio_dw_rockchip_ofw_ids, + + .probe = sdio_dw_rockchip_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(sdio_dw_rockchip_driver); diff --git a/components/drivers/sdio/mmcsd_core.c b/components/drivers/sdio/mmcsd_core.c index 77570268c199..00776a90a862 100644 --- a/components/drivers/sdio/mmcsd_core.c +++ b/components/drivers/sdio/mmcsd_core.c @@ -549,6 +549,281 @@ rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr) return ocr; } +rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage) +{ + rt_err_t err = RT_EOK; + unsigned char old_signal_voltage = host->io_cfg.signal_voltage; + + host->io_cfg.signal_voltage = signal_voltage; + if (host->ops->signal_voltage_switch) + { + err = host->ops->signal_voltage_switch(host, &host->io_cfg); + } + + if (err) + { + host->io_cfg.signal_voltage = old_signal_voltage; + } + + return err; +} + +void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host) +{ + /* 3.3V -> 1.8v -> 1.2v */ + if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_330)) + { + LOG_D("Initial signal voltage of %sv", "3.3"); + } + else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180)) + { + LOG_D("Initial signal voltage of %sv", "1.8"); + } + else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_120)) + { + LOG_D("Initial signal voltage of %sv", "1.2"); + } +} + +rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host) +{ + rt_uint32_t old_clock = host->io_cfg.clock; + + host->io_cfg.clock = 0; + mmcsd_set_iocfg(host); + + if (mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180)) + { + return -RT_ERROR; + } + + /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ + rt_thread_mdelay(10); + + host->io_cfg.clock = old_clock; + mmcsd_set_iocfg(host); + + return RT_EOK; +} + +static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr); + +rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr) +{ + rt_err_t err = RT_EOK; + struct rt_mmcsd_cmd cmd; + + if (!host->ops->signal_voltage_switch) + { + return -RT_EINVAL; + } + + if (!host->ops->card_busy) + { + LOG_W("%s: Cannot verify signal voltage switch", host->name); + } + + rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); + + cmd.cmd_code = SD_SWITCH_VOLTAGE; + cmd.arg = 0; + cmd.flags = RESP_R1 | CMD_AC; + + err = mmcsd_send_cmd(host, &cmd, 0); + if (err) + { + goto power_cycle; + } + + if (!controller_is_spi(host) && (cmd.resp[0] & R1_ERROR)) + { + return -RT_EIO; + } + + /* + * The card should drive cmd and dat[0:3] low immediately + * after the response of cmd11, but wait 1 ms to be sure + */ + rt_thread_mdelay(1); + if (host->ops->card_busy && !host->ops->card_busy(host)) + { + err = -RT_ERROR; + goto power_cycle; + } + + if (mmcsd_host_set_uhs_voltage(host)) + { + /* + * Voltages may not have been switched, but we've already + * sent CMD11, so a power cycle is required anyway + */ + err = -RT_ERROR; + goto power_cycle; + } + + /* Wait for at least 1 ms according to spec */ + rt_thread_mdelay(1); + + /* + * Failure to switch is indicated by the card holding + * dat[0:3] low + */ + if (host->ops->card_busy && host->ops->card_busy(host)) + { + err = -RT_ERROR; + } + +power_cycle: + if (err) + { + LOG_D("%s: Signal voltage switch failed, power cycling card", host->name); + mmcsd_power_cycle(host, ocr); + } + + return err; +} + +static const rt_uint8_t tuning_blk_pattern_4bit[] = +{ + 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + +static const rt_uint8_t tuning_blk_pattern_8bit[] = +{ + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + +rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error) +{ + rt_err_t err = RT_EOK; + int size; + rt_uint8_t *data_buf; + const rt_uint8_t *tuning_block_pattern; + struct rt_mmcsd_req req = {}; + struct rt_mmcsd_cmd cmd = {}; + struct rt_mmcsd_data data = {}; + struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg; + + if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8) + { + tuning_block_pattern = tuning_blk_pattern_8bit; + size = sizeof(tuning_blk_pattern_8bit); + } + else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4) + { + tuning_block_pattern = tuning_blk_pattern_4bit; + size = sizeof(tuning_blk_pattern_4bit); + } + else + { + return -RT_EINVAL; + } + + data_buf = rt_malloc(size); + if (!data_buf) + { + return -RT_ENOMEM; + } + + rt_memset(data_buf, 0, size); + rt_memset(&req, 0, sizeof(struct rt_mmcsd_req)); + rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); + rt_memset(&data, 0, sizeof(struct rt_mmcsd_data)); + + req.cmd = &cmd; + req.data = &data; + + cmd.cmd_code = opcode; + cmd.flags = RESP_R1 | CMD_ADTC; + + data.blksize = size; + data.blks = 1; + data.flags = DATA_DIR_READ; + + /* + * According to the tuning specs, Tuning process + * is normally shorter 40 executions of CMD19, + * and timeout value should be shorter than 150 ms + */ + data.timeout_ns = 150 * 1000000; + + mmcsd_send_request(host, &req); + + if (cmd_error) + { + *cmd_error = cmd.err; + } + + if (cmd.err) + { + err = cmd.err; + goto out_free; + } + + if (data.err) + { + err = data.err; + goto out_free; + } + + if (rt_memcmp(data_buf, tuning_block_pattern, size)) + { + err = -RT_EIO; + } + +out_free: + rt_free(data_buf); + + return err; +} + +rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode) +{ + struct rt_mmcsd_cmd cmd = {}; + + /* + * eMMC specification specifies that CMD12 can be used to stop a tuning + * command, but SD specification does not, so do nothing unless it is eMMC. + */ + if (opcode != SEND_TUNING_BLOCK_HS200) + { + return 0; + } + + cmd.cmd_code = STOP_TRANSMISSION; + cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC; + + /* + * For drivers that override R1 to R1b, set an arbitrary timeout based + * on the tuning timeout i.e. 150ms. + */ + cmd.busy_timeout = 150; + + return mmcsd_send_cmd(host, &cmd, 0); +} + static void mmcsd_power_up(struct rt_mmcsd_host *host) { int bit = __rt_fls(host->valid_ocr) - 1; @@ -568,6 +843,8 @@ static void mmcsd_power_up(struct rt_mmcsd_host *host) host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1; mmcsd_set_iocfg(host); + mmcsd_set_initial_signal_voltage(host); + /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. @@ -599,6 +876,17 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host) mmcsd_set_iocfg(host); } +static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr) +{ + mmcsd_power_off(host); + + /* Wait at least 1 ms according to SD spec */ + rt_thread_mdelay(1); + + mmcsd_power_up(host); + mmcsd_select_voltage(host, ocr); +} + int mmcsd_wait_cd_changed(rt_int32_t timeout) { struct rt_mmcsd_host *host; diff --git a/components/drivers/sdio/regulator.c b/components/drivers/sdio/regulator.c new file mode 100644 index 000000000000..005a38ff9acb --- /dev/null +++ b/components/drivers/sdio/regulator.c @@ -0,0 +1,248 @@ +/* + * 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 "sdio_dm.h" + +#define DBG_TAG "sdio.regulator" +#define DBG_LVL DBG_INFO +#include + +static rt_err_t ocrbitnum_to_vdd(int vdd_bit, int *min_uvolt, int *max_uvolt) +{ + int tmp; + + if (!vdd_bit) + { + return -RT_EINVAL; + } + + tmp = vdd_bit - rt_ilog2(VDD_165_195); + + if (tmp == 0) + { + *min_uvolt = 1650 * 1000; + *max_uvolt = 1950 * 1000; + } + else + { + *min_uvolt = 1900 * 1000 + tmp * 100 * 1000; + *max_uvolt = *min_uvolt + 100 * 1000; + } + + return 0; +} + +rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host, + struct rt_regulator *supply, rt_uint16_t vdd_bit) +{ + rt_err_t err = RT_EOK; + + if (!host) + { + return -RT_EINVAL; + } + + if (!supply) + { + return RT_EOK; + } + + if (vdd_bit) + { + int min_uvolt, max_uvolt; + + ocrbitnum_to_vdd(vdd_bit, &min_uvolt, &max_uvolt); + + err = rt_regulator_set_voltage(supply, min_uvolt, max_uvolt); + + if (!err && host->supply.regulator_enabled) + { + err = rt_regulator_enable(supply); + + if (!err) + { + host->supply.regulator_enabled = RT_TRUE; + } + } + } + else if (host->supply.regulator_enabled) + { + err = rt_regulator_disable(supply); + + if (!err) + { + host->supply.regulator_enabled = RT_FALSE; + } + } + + if (err) + { + LOG_E("Set regulator OCR %d error = %s", vdd_bit, rt_strerror(err)); + } + + return err; +} + +static int regulator_set_voltage_if_supported(struct rt_regulator *regulator, + int min_uvolt, int target_uvolt, int max_uvolt) +{ + if (!rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt)) + { + return -RT_EINVAL; + } + + if (rt_regulator_get_voltage(regulator) == target_uvolt) + { + return RT_EOK; + } + + return rt_regulator_set_voltage_triplet(regulator, min_uvolt, target_uvolt, + max_uvolt); +} + +rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *ios) +{ + rt_err_t err; + int uvolt, min_uvolt, max_uvolt; + + if (host->supply.vqmmc) + { + return -RT_EINVAL; + } + + switch (ios->signal_voltage) + { + case MMCSD_SIGNAL_VOLTAGE_120: + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 1100000, 1200000, 1300000); + + case MMCSD_SIGNAL_VOLTAGE_180: + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 1700000, 1800000, 1950000); + + case MMCSD_SIGNAL_VOLTAGE_330: + err = ocrbitnum_to_vdd(host->io_cfg.vdd, &uvolt, &max_uvolt); + + if (err) + { + return err; + } + + min_uvolt = rt_max(uvolt - 300000, 2700000); + max_uvolt = rt_min(max_uvolt + 200000, 3600000); + + err = regulator_set_voltage_if_supported(host->supply.vqmmc, + min_uvolt, uvolt, max_uvolt); + if (err >= 0) + { + return err; + } + + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 2700000, uvolt, 3600000); + + default: + return -RT_EINVAL; + } +} + +rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host) +{ + if (!dev || !host) + { + return -RT_EINVAL; + } + + host->supply.vmmc = rt_regulator_get_optional(dev, "vmmc"); + host->supply.vqmmc = rt_regulator_get_optional(dev, "vqmmc"); + + if (!host->supply.vmmc) + { + if (rt_dm_dev_prop_read_bool(dev, "vmmc-supply")) + { + goto _fail; + } + else + { + LOG_D("No vmmc regulator found"); + } + } + + if (!host->supply.vqmmc) + { + if (rt_dm_dev_prop_read_bool(dev, "vqmmc-supply")) + { + goto _fail; + } + else + { + LOG_D("No vqmmc regulator found"); + } + } + + return RT_EOK; + +_fail: + if (host->supply.vmmc) + { + rt_regulator_put(host->supply.vmmc); + host->supply.vmmc = RT_NULL; + } + + return -RT_EIO; +} + +rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host) +{ + struct rt_mmcsd_supply *supply; + + if (!host) + { + return -RT_EINVAL; + } + + supply = &host->supply; + + if (supply->vqmmc && !supply->vqmmc_enabled) + { + rt_err_t err = rt_regulator_enable(supply->vqmmc); + + if (err) + { + LOG_E("Enabling vqmmc regulator failed error = %s", rt_strerror(err)); + } + else + { + supply->vqmmc_enabled = RT_TRUE; + } + } + + return RT_EOK; +} + +void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host) +{ + struct rt_mmcsd_supply *supply; + + if (!host) + { + return; + } + + supply = &host->supply; + + if (supply->vqmmc && supply->vqmmc_enabled) + { + rt_regulator_disable(supply->vqmmc); + + supply->vqmmc_enabled = RT_FALSE; + } +} diff --git a/components/drivers/sdio/sdio_dm.c b/components/drivers/sdio/sdio_dm.c new file mode 100644 index 000000000000..0544b574fc50 --- /dev/null +++ b/components/drivers/sdio/sdio_dm.c @@ -0,0 +1,107 @@ +/* + * 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 "sdio_dm.h" + +#define DBG_TAG "sdio.dm" +#define DBG_LVL DBG_INFO +#include + +int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname) +{ + static volatile rt_atomic_t uid = 0; + + if (host) + { + int id = (int)rt_hw_atomic_add(&uid, 1), res; + + res = rt_snprintf(host->name, RT_NAME_MAX, "sd%u", id); + + if (out_devname) + { + rt_strncpy(out_devname, host->name, RT_NAME_MAX); + } + + return res; + } + + return -RT_EINVAL; +} + +#ifdef RT_USING_OFW +rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host) +{ + rt_uint32_t bus_width = 1; + + if (!dev_np) + { + return -RT_EINVAL; + } + + host->flags = MMCSD_MUTBLKWRITE; + rt_ofw_prop_read_u32(dev_np, "bus-width", &bus_width); + + switch (bus_width) + { + case 0x8: + host->flags |= MMCSD_BUSWIDTH_8; + break; + + case 0x4: + host->flags |= MMCSD_BUSWIDTH_4; + break; + + case 0x1: + break; + + default: + LOG_E("Invalid \"bus-width\" value %d", bus_width); + return -RT_EIO; + } + + rt_ofw_prop_read_u32(dev_np, "max-frequency", &host->freq_max); + + if (rt_ofw_prop_read_bool(dev_np, "cap-sdio-irq")) + { + host->flags |= MMCSD_SUP_SDIO_IRQ; + } + + if (rt_ofw_prop_read_bool(dev_np, "cap-sd-highspeed") || + rt_ofw_prop_read_bool(dev_np, "cap-mmc-highspeed")) + { + host->flags |= MMCSD_SUP_HIGHSPEED; + } + + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-3_3v")) + { + host->flags |= MMCSD_SUP_DDR_3V3; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_8v")) + { + host->flags |= MMCSD_SUP_DDR_1V8; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_2v")) + { + host->flags |= MMCSD_SUP_DDR_1V2; + } + + if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_2v")) + { + host->flags |= MMCSD_SUP_HS200_1V2; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_8v")) + { + host->flags |= MMCSD_SUP_HS200_1V8; + } + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/sdio/sdio_dm.h b/components/drivers/sdio/sdio_dm.h new file mode 100644 index 000000000000..f6da0df9556a --- /dev/null +++ b/components/drivers/sdio/sdio_dm.h @@ -0,0 +1,39 @@ +/* + * 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 + */ + +#ifndef __SDIO_DM_H__ +#define __SDIO_DM_H__ + +#include +#include +#include + +int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname); + +#ifdef RT_USING_REGULATOR +rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host, + struct rt_regulator *supply, rt_uint16_t vdd_bit); +rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *ios); +rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host); +rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host); +void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host); +#endif /* RT_USING_REGULATOR */ + +#ifdef RT_USING_OFW +rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host); +#else +rt_inline rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +#endif /* __SDIO_DM_H__ */ diff --git a/components/drivers/sensor/Kconfig b/components/drivers/sensor/Kconfig new file mode 100755 index 000000000000..469f6c63e07f --- /dev/null +++ b/components/drivers/sensor/Kconfig @@ -0,0 +1,19 @@ +menuconfig RT_USING_SENSOR + bool "Using Sensor device drivers" + select RT_USING_PIN + default n + +if RT_USING_SENSOR + config RT_USING_SENSOR_CMD + bool "Using Sensor cmd" + select PKG_USING_RT_VSNPRINTF_FULL + default y +endif + +config RT_ADC_ROCKCHIP_TSADC + bool "Rockchip TSADC(thermal) driver" + depends on RT_USING_DM + depends on RT_USING_SENSOR + select RT_MFD_SYSCON + select RT_USING_RESET + default n diff --git a/components/drivers/sensor/SConscript b/components/drivers/sensor/SConscript index c25e2fe4b031..013db33d5b29 100644 --- a/components/drivers/sensor/SConscript +++ b/components/drivers/sensor/SConscript @@ -9,6 +9,9 @@ CPPPATH = [cwd, cwd + '/../include'] if GetDepend('RT_USING_SENSOR_CMD'): src += ['sensor_cmd.c'] +if GetDepend(['RT_ADC_ROCKCHIP_TSADC']): + src += ['sensor-rockchip_tsadc.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SENSOR', 'RT_USING_DEVICE'], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/sensor/sensor-rockchip_tsadc.c b/components/drivers/sensor/sensor-rockchip_tsadc.c new file mode 100644 index 000000000000..400775de8ff2 --- /dev/null +++ b/components/drivers/sensor/sensor-rockchip_tsadc.c @@ -0,0 +1,1663 @@ +/* + * 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 "sensor.rk-tsadc" +#define DBG_LVL DBG_INFO +#include + +/* + * TSADC Sensor Register description: + * + * TSADCV2_* are used for RK3288 SoCs, the other chips can reuse it. + * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) + */ +#define TSADCV2_USER_CON 0x00 +#define TSADCV2_AUTO_CON 0x04 +#define TSADCV2_INT_EN 0x08 +#define TSADCV2_INT_PD 0x0c +#define TSADCV3_AUTO_SRC_CON 0x0c +#define TSADCV3_HT_INT_EN 0x14 +#define TSADCV3_HSHUT_GPIO_INT_EN 0x18 +#define TSADCV3_HSHUT_CRU_INT_EN 0x1c +#define TSADCV3_INT_PD 0x24 +#define TSADCV3_HSHUT_PD 0x28 +#define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) +#define TSADCV2_COMP_INT(chn) (0x30 + (chn) * 0x04) +#define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) +#define TSADCV3_DATA(chn) (0x2c + (chn) * 0x04) +#define TSADCV3_COMP_INT(chn) (0x6c + (chn) * 0x04) +#define TSADCV3_COMP_SHUT(chn) (0x10c + (chn) * 0x04) +#define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 +#define TSADCV3_HIGHT_INT_DEBOUNCE 0x14c +#define TSADCV3_HIGHT_TSHUT_DEBOUNCE 0x150 +#define TSADCV2_AUTO_PERIOD 0x68 +#define TSADCV2_AUTO_PERIOD_HT 0x6c +#define TSADCV3_AUTO_PERIOD 0x154 +#define TSADCV3_AUTO_PERIOD_HT 0x158 + +#define TSADCV2_AUTO_EN RT_BIT(0) +#define TSADCV2_AUTO_EN_MASK RT_BIT(16) +#define TSADCV2_AUTO_SRC_EN(chn) RT_BIT(4 + (chn)) +#define TSADCV3_AUTO_SRC_EN(chn) RT_BIT(chn) +#define TSADCV3_AUTO_SRC_EN_MASK(chn) RT_BIT(16 + chn) +#define TSADCV2_AUTO_TSHUT_POLARITY_HIGH RT_BIT(8) +#define TSADCV2_AUTO_TSHUT_POLARITY_MASK RT_BIT(24) + +#define TSADCV3_AUTO_Q_SEL_EN RT_BIT(1) + +#define TSADCV2_INT_SRC_EN(chn) RT_BIT(chn) +#define TSADCV2_INT_SRC_EN_MASK(chn) RT_BIT(16 + (chn)) +#define TSADCV2_SHUT_2GPIO_SRC_EN(chn) RT_BIT(4 + (chn)) +#define TSADCV2_SHUT_2CRU_SRC_EN(chn) RT_BIT(8 + (chn)) + +#define TSADCV2_INT_PD_CLEAR_MASK (~RT_BIT(8)) +#define TSADCV3_INT_PD_CLEAR_MASK (~RT_BIT(16)) +#define TSADCV4_INT_PD_CLEAR_MASK 0xffffffff + +#define TSADCV2_DATA_MASK 0xfff +#define TSADCV3_DATA_MASK 0x3ff +#define TSADCV4_DATA_MASK 0x1ff + +#define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 +#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 +#define TSADCV2_AUTO_PERIOD_TIME 250 /* 250ms */ +#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* 50ms */ +#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ +#define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */ + +#define TSADCV5_AUTO_PERIOD_TIME 1622 /* 2.5ms */ +#define TSADCV5_AUTO_PERIOD_HT_TIME 1622 /* 2.5ms */ +#define TSADCV6_AUTO_PERIOD_TIME 5000 /* 2.5ms */ +#define TSADCV6_AUTO_PERIOD_HT_TIME 5000 /* 2.5ms */ + +#define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ +#define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */ + +#define GRF_SARADC_TESTBIT 0x0e644 +#define GRF_TSADC_TESTBIT_L 0x0e648 +#define GRF_TSADC_TESTBIT_H 0x0e64c + +#define PX30_GRF_SOC_CON2 0x0408 + +#define RK3568_GRF_TSADC_CON 0x0600 +#define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0) +#define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1) +#define RK3568_GRF_TSADC_ANA_REG2 (0x10001 << 2) +#define RK3568_GRF_TSADC_TSEN (0x10001 << 8) + +#define RK3588_GRF0_TSADC_CON 0x0100 + +#define RK3588_GRF0_TSADC_TRM (0xff0077 << 0) +#define RK3588_GRF0_TSADC_SHUT_2CRU (0x30003 << 10) +#define RK3588_GRF0_TSADC_SHUT_2GPIO (0x70007 << 12) + +#define GRF_SARADC_TESTBIT_ON (0x10001 << 2) +#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) +#define GRF_TSADC_VCM_EN_L (0x10001 << 7) +#define GRF_TSADC_VCM_EN_H (0x10001 << 7) + +#define GRF_CON_TSADC_CH_INV (0x10001 << 1) + +#define TEMP_INVALID ((int)(RT_UINT32_MAX >> 1)) +#define TEMP_SCALE 1000 + +/* + * If the temperature over a period of time High, + * the resulting TSHUT gave CRU module,let it reset the entire chip, + * or via GPIO give PMIC. + */ +enum tshut_mode +{ + TSHUT_MODE_CRU = 0, + TSHUT_MODE_GPIO, +}; + +/* The system Temperature Sensors tshut(tshut) polarity */ +enum tshut_polarity +{ + TSHUT_LOW_ACTIVE = 0, + TSHUT_HIGH_ACTIVE, +}; + +/* The conversion table has the adc value and temperature. */ +enum adc_sort_mode +{ + ADC_DECREMENT = 0, /* the adc value is of diminishing.(e.g. rk3288_code_table) */ + ADC_INCREMENT, /* the adc value is incremental.(e.g. rk3368_code_table) */ +}; + +struct chip_tsadc_table +{ + const struct tsadc_table *id; + rt_size_t length; + + rt_uint32_t data_mask; + enum adc_sort_mode mode; +}; + +struct rockchip_tsadc_chip +{ + /* The sensor id of chip correspond to the ADC channel */ + int chn_offset; + int chn_num; + const char * const *chn_name; + + /* The hardware-controlled tshut property */ + int tshut_temp; + enum tshut_mode tshut_mode; + enum tshut_polarity tshut_polarity; + + /* Chip-wide methods */ + void (*initialize)(struct rt_syscon *grf, void *reg, enum tshut_polarity p); + void (*irq_ack)(void *reg); + void (*control)(void *reg, rt_bool_t on); + + /* Per-sensor methods */ + rt_err_t (*get_temp)(const struct chip_tsadc_table *table, int chn, void *reg, int *temp); + rt_err_t (*set_alarm_temp)(const struct chip_tsadc_table *table, int chn, void *reg, int temp); + rt_err_t (*set_tshut_temp)(const struct chip_tsadc_table *table, int chn, void *reg, int temp); + void (*set_tshut_mode)(int chn, void *reg, enum tshut_mode m); + + /* Per-table methods */ + struct chip_tsadc_table table; +}; + +struct tsadc_table +{ + rt_uint32_t code; /* the value of adc channel */ + int temp; /* the temperature */ +}; + +struct rockchip_tsadc; + +struct rockchip_tsadc_channel +{ + struct rt_sensor_device parent; + + int id; + struct rockchip_tsadc *rk_tsadc; +}; +#define raw_to_rockchip_tsadc_channel(raw) rt_container_of(raw, struct rockchip_tsadc_channel, parent) + +struct rockchip_tsadc +{ + struct rt_device parent; + + int irq; + void *regs; + struct rt_syscon *grf; + + struct rt_clk *clk; + struct rt_clk *pclk; + + struct rt_reset_control *rstc; + + int tshut_temp; + enum tshut_mode tshut_mode; + enum tshut_polarity tshut_polarity; + + const struct rockchip_tsadc_chip *chip; + struct rockchip_tsadc_channel channels[0]; +}; + +static rt_uint32_t rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table, + int temp) +{ + rt_ubase_t num; + rt_uint32_t denom, error = table->data_mask; + int high = (table->length - 1) - 1, low = 0, mid = (high + low) / 2; + + /* Return mask code data when the temp is over table range */ + if (temp < table->id[low].temp || temp > table->id[high].temp) + { + goto _exit; + } + + while (low <= high) + { + if (temp == table->id[mid].temp) + { + return table->id[mid].code; + } + else if (temp < table->id[mid].temp) + { + high = mid - 1; + } + else + { + low = mid + 1; + } + + mid = (low + high) / 2; + } + + /* + * The conversion code granularity provided by the table. Let's + * assume that the relationship between temperature and + * analog value between 2 table entries is linear and interpolate + * to produce less granular result. + */ + num = rt_abs(table->id[mid + 1].code - table->id[mid].code); + num *= temp - table->id[mid].temp; + denom = table->id[mid + 1].temp - table->id[mid].temp; + + switch (table->mode) + { + case ADC_DECREMENT: + return table->id[mid].code - (num / denom); + + case ADC_INCREMENT: + return table->id[mid].code + (num / denom); + + default: + LOG_E("Temp to Code: unknown table mode: %d", table->mode); + + return error; + } + +_exit: + LOG_E("Temp to Code: invalid temperature, temp = %d error = %d", temp, error); + + return error; +} + +static rt_err_t rk_tsadcv2_code_to_temp(const struct chip_tsadc_table *table, + rt_uint32_t code, int *temp) +{ + rt_ubase_t denom; + rt_uint32_t low = 1, high = table->length - 1, mid = (low + high) / 2, num; + + switch (table->mode) + { + case ADC_DECREMENT: + code &= table->data_mask; + + if (code <= table->id[high].code) + { + return -RT_ERROR; + } + + while (low <= high) + { + if (code >= table->id[mid].code && code < table->id[mid - 1].code) + { + break; + } + else if (code < table->id[mid].code) + { + low = mid + 1; + } + else + { + high = mid - 1; + } + + mid = (low + high) / 2; + } + break; + + case ADC_INCREMENT: + code &= table->data_mask; + + if (code < table->id[low].code) + { + return -RT_ERROR; + } + + while (low <= high) + { + if (code <= table->id[mid].code && code > table->id[mid - 1].code) + { + break; + } + else if (code > table->id[mid].code) + { + low = mid + 1; + } + else + { + high = mid - 1; + } + + mid = (low + high) / 2; + } + break; + + default: + LOG_E("Code to Temp: unknown table mode: %d", table->mode); + + return -RT_EINVAL; + } + + /* + * The 5C granularity provided by the table is too much. Let's + * assume that the relationship between sensor readings and + * temperature between 2 table entries is linear and interpolate + * to produce less granular result. + */ + num = table->id[mid].temp - table->id[mid - 1].temp; + num *= rt_abs(table->id[mid - 1].code - code); + denom = rt_abs(table->id[mid - 1].code - table->id[mid].code); + *temp = table->id[mid - 1].temp + (num / denom); + + return 0; +} + +/* + * Initialize TASDC Controller. + * + * (1) Set TSADC_V2_AUTO_PERIOD: + * Configure the interleave between every two accessing of + * TSADC in normal operation. + * + * (2) Set TSADCV2_AUTO_PERIOD_HT: + * Configure the interleave between every two accessing of + * TSADC after the temperature is higher than COM_SHUT or COM_INT. + * + * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: + * If the temperature is higher than COMP_INT or COMP_SHUT for + * "debounce" times, TSADC controller will generate interrupt or TSHUT. + */ +static void rk_tsadcv2_initialize(struct rt_syscon *grf, void *regs, + enum tshut_polarity tshut_polarity) +{ + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } + else + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } + + HWREG32(regs + TSADCV2_AUTO_PERIOD) = TSADCV2_AUTO_PERIOD_TIME; + HWREG32(regs + TSADCV2_HIGHT_INT_DEBOUNCE) = TSADCV2_HIGHT_INT_DEBOUNCE_COUNT; + HWREG32(regs + TSADCV2_AUTO_PERIOD_HT) = TSADCV2_AUTO_PERIOD_HT_TIME; + HWREG32(regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE) = TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT; +} + +/* + * Initialize TASDC Controller. + * (1) The tsadc control power sequence. + * + * (2) Set TSADC_V2_AUTO_PERIOD: + * Configure the interleave between every two accessing of + * TSADC in normal operation. + * + * (2) Set TSADCV2_AUTO_PERIOD_HT: + * Configure the interleave between every two accessing of + * TSADC after the temperature is higher than COM_SHUT or COM_INT. + * + * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: + * If the temperature is higher than COMP_INT or COMP_SHUT for + * "debounce" times, TSADC controller will generate interrupt or TSHUT. + */ +static void rk_tsadcv3_initialize(struct rt_syscon *grf, void *regs, + enum tshut_polarity tshut_polarity) +{ + /* The tsadc control power sequence */ + if (!grf) + { + /* Set interleave value to workround ic time sync issue */ + HWREG32(regs + TSADCV2_USER_CON) = TSADCV2_USER_INTER_PD_SOC; + HWREG32(regs + TSADCV2_AUTO_PERIOD) = TSADCV2_AUTO_PERIOD_TIME; + HWREG32(regs + TSADCV2_HIGHT_INT_DEBOUNCE) = TSADCV2_HIGHT_INT_DEBOUNCE_COUNT; + HWREG32(regs + TSADCV2_AUTO_PERIOD_HT) = TSADCV2_AUTO_PERIOD_HT_TIME; + HWREG32(regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE) = TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT; + + } + else + { + /* Enable the voltage common mode feature */ + rt_syscon_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_VCM_EN_L); + rt_syscon_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_VCM_EN_H); + rt_hw_us_delay(15); + + rt_syscon_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON); + rt_syscon_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON); + rt_hw_us_delay(90); + + HWREG32(regs + TSADCV2_AUTO_PERIOD) = TSADCV3_AUTO_PERIOD_TIME; + HWREG32(regs + TSADCV2_HIGHT_INT_DEBOUNCE) = TSADCV2_HIGHT_INT_DEBOUNCE_COUNT; + HWREG32(regs + TSADCV2_AUTO_PERIOD_HT) = TSADCV3_AUTO_PERIOD_HT_TIME; + HWREG32(regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE) = TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT; + } + + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } + else + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } +} + +static void rk_tsadcv4_initialize(struct rt_syscon *grf, void *regs, + enum tshut_polarity tshut_polarity) +{ + rk_tsadcv2_initialize(grf, regs, tshut_polarity); + + rt_syscon_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV); +} + +static void rk_tsadcv7_initialize(struct rt_syscon *grf, void *regs, + enum tshut_polarity tshut_polarity) +{ + HWREG32(regs + TSADCV2_USER_CON) = TSADCV5_USER_INTER_PD_SOC; + HWREG32(regs + TSADCV2_AUTO_PERIOD) = TSADCV5_AUTO_PERIOD_TIME; + HWREG32(regs + TSADCV2_HIGHT_INT_DEBOUNCE) = TSADCV2_HIGHT_INT_DEBOUNCE_COUNT; + HWREG32(regs + TSADCV2_AUTO_PERIOD_HT) = TSADCV5_AUTO_PERIOD_HT_TIME; + HWREG32(regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE) = TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT; + + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } + else + { + HWREG32(regs + TSADCV2_AUTO_CON) = 0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH; + } + + /* The general register file will is optional and might not be available. */ + if (grf) + { + rt_syscon_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_TSEN); + rt_hw_us_delay(15); + + rt_syscon_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG0); + rt_syscon_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG1); + rt_syscon_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG2); + rt_hw_us_delay(100); + } +} + +static void rk_tsadcv8_initialize(struct rt_syscon *grf, void *regs, + enum tshut_polarity tshut_polarity) +{ + HWREG32(regs + TSADCV3_AUTO_PERIOD) = TSADCV6_AUTO_PERIOD_TIME; + HWREG32(regs + TSADCV3_AUTO_PERIOD_HT) = TSADCV6_AUTO_PERIOD_HT_TIME; + HWREG32(regs + TSADCV3_HIGHT_INT_DEBOUNCE) = TSADCV2_HIGHT_INT_DEBOUNCE_COUNT; + HWREG32(regs + TSADCV3_HIGHT_TSHUT_DEBOUNCE) = TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT; + + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + { + HWREG32(regs + TSADCV2_AUTO_CON) = TSADCV2_AUTO_TSHUT_POLARITY_HIGH | + TSADCV2_AUTO_TSHUT_POLARITY_MASK; + } + else + { + HWREG32(regs + TSADCV2_AUTO_CON) = TSADCV2_AUTO_TSHUT_POLARITY_MASK; + } +} + +static void rk_tsadcv2_irq_ack(void *regs) +{ + rt_uint32_t val; + + val = HWREG32(regs + TSADCV2_INT_PD); + HWREG32(regs + TSADCV2_INT_PD) = val & TSADCV2_INT_PD_CLEAR_MASK; +} + +static void rk_tsadcv3_irq_ack(void *regs) +{ + rt_uint32_t val; + + val = HWREG32(regs + TSADCV2_INT_PD); + HWREG32(regs + TSADCV2_INT_PD) = val & TSADCV3_INT_PD_CLEAR_MASK; +} + +static void rk_tsadcv4_irq_ack(void *regs) +{ + rt_uint32_t val; + + val = HWREG32(regs + TSADCV3_INT_PD); + HWREG32(regs + TSADCV3_INT_PD) = val & TSADCV4_INT_PD_CLEAR_MASK; + + val = HWREG32(regs + TSADCV3_HSHUT_PD); + HWREG32(regs + TSADCV3_HSHUT_PD) = val & TSADCV3_INT_PD_CLEAR_MASK; +} + +static void rk_tsadcv2_control(void *regs, rt_bool_t enable) +{ + rt_uint32_t val = HWREG32(regs + TSADCV2_AUTO_CON); + + if (enable) + { + val |= TSADCV2_AUTO_EN; + } + else + { + val &= ~TSADCV2_AUTO_EN; + } + + HWREG32(regs + TSADCV2_AUTO_CON) = val; +} + +/* + * The tsadc controller is enabled or disabled. + * NOTE: TSADC controller works at auto mode, and some SoCs need set the + * tsadc_q_sel bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output + * adc value if setting this bit to enable. + */ +static void rk_tsadcv3_control(void *regs, rt_bool_t enable) +{ + rt_uint32_t val = HWREG32(regs + TSADCV2_AUTO_CON); + + if (enable) + { + val |= TSADCV2_AUTO_EN | TSADCV3_AUTO_Q_SEL_EN; + } + else + { + val &= ~TSADCV2_AUTO_EN; + } + + HWREG32(regs + TSADCV2_AUTO_CON) = val; +} + +static void rk_tsadcv4_control(void *regs, rt_bool_t enable) +{ + rt_uint32_t val; + + if (enable) + { + val = TSADCV2_AUTO_EN | TSADCV2_AUTO_EN_MASK; + } + else + { + val = TSADCV2_AUTO_EN_MASK; + } + + HWREG32(regs + TSADCV2_AUTO_CON) = val; +} + +static rt_err_t rk_tsadcv2_get_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int *temp) +{ + rt_uint32_t val = HWREG32(regs + TSADCV2_DATA(chn)); + + return rk_tsadcv2_code_to_temp(table, val, temp); +} + +static rt_err_t rk_tsadcv4_get_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int *temp) +{ + rt_uint32_t val = HWREG32(regs + TSADCV3_DATA(chn)); + + return rk_tsadcv2_code_to_temp(table, val, temp); +} + +static rt_err_t rk_tsadcv2_alarm_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int temp) +{ + rt_uint32_t alarm_value; + rt_uint32_t int_en, int_clr; + + /* + * In some cases, some sensors didn't need the trip points, the + * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm + * in the end, ignore this case and disable the high temperature + * interrupt. + */ + if (temp == TEMP_INVALID) + { + int_clr = HWREG32(regs + TSADCV2_INT_EN); + int_clr &= ~TSADCV2_INT_SRC_EN(chn); + HWREG32(regs + TSADCV2_INT_EN) = int_clr; + + return RT_EOK; + } + + alarm_value = rk_tsadcv2_temp_to_code(table, temp); + + if (alarm_value == table->data_mask) + { + return -RT_EINVAL; + } + + HWREG32(regs + TSADCV2_COMP_INT(chn)) = alarm_value & table->data_mask; + int_en = HWREG32(regs + TSADCV2_INT_EN); + int_en |= TSADCV2_INT_SRC_EN(chn); + HWREG32(regs + TSADCV2_INT_EN) = int_en; + + return RT_EOK; +} + +static rt_err_t rk_tsadcv3_alarm_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int temp) +{ + rt_uint32_t alarm_value; + + /* + * In some cases, some sensors didn't need the trip points, the + * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm + * in the end, ignore this case and disable the high temperature + * interrupt. + */ + if (temp == TEMP_INVALID) + { + HWREG32(regs + TSADCV3_HT_INT_EN) = TSADCV2_INT_SRC_EN_MASK(chn); + + return RT_EOK; + } + + alarm_value = rk_tsadcv2_temp_to_code(table, temp); + + if (alarm_value == table->data_mask) + { + return -RT_EINVAL; + } + + HWREG32(regs + TSADCV3_COMP_INT(chn)) = alarm_value & table->data_mask; + HWREG32(regs + TSADCV3_HT_INT_EN) = + TSADCV2_INT_SRC_EN(chn) | TSADCV2_INT_SRC_EN_MASK(chn); + + return RT_EOK; +} + +static rt_err_t rk_tsadcv2_tshut_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int temp) +{ + rt_uint32_t val, tshut_value = rk_tsadcv2_temp_to_code(table, temp); + + if (tshut_value == table->data_mask) + { + return -RT_EINVAL; + } + + HWREG32(regs + TSADCV2_COMP_SHUT(chn)) = tshut_value; + val = HWREG32(regs + TSADCV2_AUTO_CON); + HWREG32(regs + TSADCV2_AUTO_CON) = val | TSADCV2_AUTO_SRC_EN(chn); + + return RT_EOK; +} + +static rt_err_t rk_tsadcv3_tshut_temp(const struct chip_tsadc_table *table, + int chn, void *regs, int temp) +{ + rt_uint32_t tshut_value = rk_tsadcv2_temp_to_code(table, temp); + + if (tshut_value == table->data_mask) + { + return -RT_EINVAL; + } + + HWREG32(regs + TSADCV3_COMP_SHUT(chn)) = tshut_value; + HWREG32(regs + TSADCV3_AUTO_SRC_CON) = + TSADCV3_AUTO_SRC_EN(chn) | TSADCV3_AUTO_SRC_EN_MASK(chn); + + return RT_EOK; +} + +static void rk_tsadcv2_tshut_mode(int chn, void *regs, enum tshut_mode mode) +{ + rt_uint32_t val = HWREG32(regs + TSADCV2_INT_EN); + + if (mode == TSHUT_MODE_GPIO) + { + val &= ~TSADCV2_SHUT_2CRU_SRC_EN(chn); + val |= TSADCV2_SHUT_2GPIO_SRC_EN(chn); + } + else + { + val &= ~TSADCV2_SHUT_2GPIO_SRC_EN(chn); + val |= TSADCV2_SHUT_2CRU_SRC_EN(chn); + } + + HWREG32(regs + TSADCV2_INT_EN) = val; +} + +static void rk_tsadcv3_tshut_mode(int chn, void *regs, enum tshut_mode mode) +{ + rt_uint32_t val_gpio, val_cru; + + if (mode == TSHUT_MODE_GPIO) + { + val_gpio = TSADCV2_INT_SRC_EN(chn) | TSADCV2_INT_SRC_EN_MASK(chn); + val_cru = TSADCV2_INT_SRC_EN_MASK(chn); + } + else + { + val_cru = TSADCV2_INT_SRC_EN(chn) | TSADCV2_INT_SRC_EN_MASK(chn); + val_gpio = TSADCV2_INT_SRC_EN_MASK(chn); + } + + HWREG32(regs + TSADCV3_HSHUT_GPIO_INT_EN) = val_gpio; + HWREG32(regs + TSADCV3_HSHUT_CRU_INT_EN) = val_cru; +} + +static const struct tsadc_table rk3328_code_table[] = +{ + { 0, -40000 }, + { 296, -40000 }, + { 304, -35000 }, + { 313, -30000 }, + { 331, -20000 }, + { 340, -15000 }, + { 349, -10000 }, + { 359, -5000 }, + { 368, 0 }, + { 378, 5000 }, + { 388, 10000 }, + { 398, 15000 }, + { 408, 20000 }, + { 418, 25000 }, + { 429, 30000 }, + { 440, 35000 }, + { 451, 40000 }, + { 462, 45000 }, + { 473, 50000 }, + { 485, 55000 }, + { 496, 60000 }, + { 508, 65000 }, + { 521, 70000 }, + { 533, 75000 }, + { 546, 80000 }, + { 559, 85000 }, + { 572, 90000 }, + { 586, 95000 }, + { 600, 100000 }, + { 614, 105000 }, + { 629, 110000 }, + { 644, 115000 }, + { 659, 120000 }, + { 675, 125000 }, + { TSADCV2_DATA_MASK, 125000 }, +}; + +static const char * const chn_name_common[] = +{ + "CPU", "GPU", +}; + +static const struct rockchip_tsadc_chip px30_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* 2 channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv4_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3328_code_table, + .length = RT_ARRAY_SIZE(rk3328_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rv1108_table[] = +{ + { 0, -40000 }, + { 374, -40000 }, + { 382, -35000 }, + { 389, -30000 }, + { 397, -25000 }, + { 405, -20000 }, + { 413, -15000 }, + { 421, -10000 }, + { 429, -5000 }, + { 436, 0 }, + { 444, 5000 }, + { 452, 10000 }, + { 460, 15000 }, + { 468, 20000 }, + { 476, 25000 }, + { 483, 30000 }, + { 491, 35000 }, + { 499, 40000 }, + { 507, 45000 }, + { 515, 50000 }, + { 523, 55000 }, + { 531, 60000 }, + { 539, 65000 }, + { 547, 70000 }, + { 555, 75000 }, + { 562, 80000 }, + { 570, 85000 }, + { 578, 90000 }, + { 586, 95000 }, + { 594, 100000 }, + { 602, 105000 }, + { 610, 110000 }, + { 618, 115000 }, + { 626, 120000 }, + { 634, 125000 }, + { TSADCV2_DATA_MASK, 125000 }, +}; + +static const struct rockchip_tsadc_chip rv1108_tsadc_data = +{ + /* cpu */ + .chn_offset = 0, + .chn_num = 1, /* one channel for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rv1108_table, + .length = RT_ARRAY_SIZE(rv1108_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3228_code_table[] = +{ + { 0, -40000 }, + { 588, -40000 }, + { 593, -35000 }, + { 598, -30000 }, + { 603, -25000 }, + { 608, -20000 }, + { 613, -15000 }, + { 618, -10000 }, + { 623, -5000 }, + { 629, 0 }, + { 634, 5000 }, + { 639, 10000 }, + { 644, 15000 }, + { 649, 20000 }, + { 654, 25000 }, + { 660, 30000 }, + { 665, 35000 }, + { 670, 40000 }, + { 675, 45000 }, + { 681, 50000 }, + { 686, 55000 }, + { 691, 60000 }, + { 696, 65000 }, + { 702, 70000 }, + { 707, 75000 }, + { 712, 80000 }, + { 717, 85000 }, + { 723, 90000 }, + { 728, 95000 }, + { 733, 100000 }, + { 738, 105000 }, + { 744, 110000 }, + { 749, 115000 }, + { 754, 120000 }, + { 760, 125000 }, + { TSADCV2_DATA_MASK, 125000 }, +}; + +static const struct rockchip_tsadc_chip rk3228_tsadc_data = +{ + /* cpu */ + .chn_offset = 0, + .chn_num = 1, /* one channel for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3228_code_table, + .length = RT_ARRAY_SIZE(rk3228_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3288_code_table[] = +{ + { TSADCV2_DATA_MASK, -40000 }, + { 3800, -40000 }, + { 3792, -35000 }, + { 3783, -30000 }, + { 3774, -25000 }, + { 3765, -20000 }, + { 3756, -15000 }, + { 3747, -10000 }, + { 3737, -5000 }, + { 3728, 0 }, + { 3718, 5000 }, + { 3708, 10000 }, + { 3698, 15000 }, + { 3688, 20000 }, + { 3678, 25000 }, + { 3667, 30000 }, + { 3656, 35000 }, + { 3645, 40000 }, + { 3634, 45000 }, + { 3623, 50000 }, + { 3611, 55000 }, + { 3600, 60000 }, + { 3588, 65000 }, + { 3575, 70000 }, + { 3563, 75000 }, + { 3550, 80000 }, + { 3537, 85000 }, + { 3524, 90000 }, + { 3510, 95000 }, + { 3496, 100000 }, + { 3482, 105000 }, + { 3467, 110000 }, + { 3452, 115000 }, + { 3437, 120000 }, + { 3421, 125000 }, + { 0, 125000 }, +}; + +static const struct rockchip_tsadc_chip rk3288_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 1, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv2_irq_ack, + .control = rk_tsadcv2_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3288_code_table, + .length = RT_ARRAY_SIZE(rk3288_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_DECREMENT, + }, +}; + +static const struct rockchip_tsadc_chip rk3308_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3328_code_table, + .length = RT_ARRAY_SIZE(rk3328_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct rockchip_tsadc_chip rk3328_tsadc_data = +{ + /* cpu */ + .chn_offset = 0, + .chn_num = 1, /* one channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3328_code_table, + .length = RT_ARRAY_SIZE(rk3328_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct rockchip_tsadc_chip rk3366_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv3_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3228_code_table, + .length = RT_ARRAY_SIZE(rk3228_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3368_code_table[] = +{ + { 0, -40000 }, + { 106, -40000 }, + { 108, -35000 }, + { 110, -30000 }, + { 112, -25000 }, + { 114, -20000 }, + { 116, -15000 }, + { 118, -10000 }, + { 120, -5000 }, + { 122, 0 }, + { 124, 5000 }, + { 126, 10000 }, + { 128, 15000 }, + { 130, 20000 }, + { 132, 25000 }, + { 134, 30000 }, + { 136, 35000 }, + { 138, 40000 }, + { 140, 45000 }, + { 142, 50000 }, + { 144, 55000 }, + { 146, 60000 }, + { 148, 65000 }, + { 150, 70000 }, + { 152, 75000 }, + { 154, 80000 }, + { 156, 85000 }, + { 158, 90000 }, + { 160, 95000 }, + { 162, 100000 }, + { 163, 105000 }, + { 165, 110000 }, + { 167, 115000 }, + { 169, 120000 }, + { 171, 125000 }, + { TSADCV3_DATA_MASK, 125000 }, +}; + +static const struct rockchip_tsadc_chip rk3368_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv2_irq_ack, + .control = rk_tsadcv2_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3368_code_table, + .length = RT_ARRAY_SIZE(rk3368_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3399_code_table[] = +{ + { 0, -40000 }, + { 402, -40000 }, + { 410, -35000 }, + { 419, -30000 }, + { 427, -25000 }, + { 436, -20000 }, + { 444, -15000 }, + { 453, -10000 }, + { 461, -5000 }, + { 470, 0 }, + { 478, 5000 }, + { 487, 10000 }, + { 496, 15000 }, + { 504, 20000 }, + { 513, 25000 }, + { 521, 30000 }, + { 530, 35000 }, + { 538, 40000 }, + { 547, 45000 }, + { 555, 50000 }, + { 564, 55000 }, + { 573, 60000 }, + { 581, 65000 }, + { 590, 70000 }, + { 599, 75000 }, + { 607, 80000 }, + { 616, 85000 }, + { 624, 90000 }, + { 633, 95000 }, + { 642, 100000 }, + { 650, 105000 }, + { 659, 110000 }, + { 668, 115000 }, + { 677, 120000 }, + { 685, 125000 }, + { TSADCV3_DATA_MASK, 125000 }, +}; + +static const struct rockchip_tsadc_chip rk3399_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv3_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3399_code_table, + .length = RT_ARRAY_SIZE(rk3399_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3568_code_table[] = +{ + { 0, -40000 }, + { 1584, -40000 }, + { 1620, -35000 }, + { 1652, -30000 }, + { 1688, -25000 }, + { 1720, -20000 }, + { 1756, -15000 }, + { 1788, -10000 }, + { 1824, -5000 }, + { 1856, 0 }, + { 1892, 5000 }, + { 1924, 10000 }, + { 1956, 15000 }, + { 1992, 20000 }, + { 2024, 25000 }, + { 2060, 30000 }, + { 2092, 35000 }, + { 2128, 40000 }, + { 2160, 45000 }, + { 2196, 50000 }, + { 2228, 55000 }, + { 2264, 60000 }, + { 2300, 65000 }, + { 2332, 70000 }, + { 2368, 75000 }, + { 2400, 80000 }, + { 2436, 85000 }, + { 2468, 90000 }, + { 2500, 95000 }, + { 2536, 100000 }, + { 2572, 105000 }, + { 2604, 110000 }, + { 2636, 115000 }, + { 2672, 120000 }, + { 2704, 125000 }, + { TSADCV2_DATA_MASK, 125000 }, +}; + +static const struct rockchip_tsadc_chip rk3568_tsadc_data = +{ + /* cpu, gpu */ + .chn_offset = 0, + .chn_num = 2, /* two channels for tsadc */ + .chn_name = chn_name_common, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv7_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = + { + .id = rk3568_code_table, + .length = RT_ARRAY_SIZE(rk3568_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct tsadc_table rk3588_code_table[] = +{ + { 0, -40000 }, + { 215, -40000 }, + { 285, 25000 }, + { 350, 85000 }, + { 395, 125000 }, + { TSADCV4_DATA_MASK, 125000 }, +}; + +static const char * const chn_name_rk3588[] = +{ + "Top", "Big Core0", "Big Core1", "Little Core", "Center", "GPU", "NPU", +}; + +static const struct rockchip_tsadc_chip rk3588_tsadc_data = +{ + /* top, big_core0, big_core1, little_core, center, gpu, npu */ + .chn_offset = 0, + .chn_num = 7, /* seven channels for tsadc */ + .chn_name = chn_name_rk3588, + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + .initialize = rk_tsadcv8_initialize, + .irq_ack = rk_tsadcv4_irq_ack, + .control = rk_tsadcv4_control, + .get_temp = rk_tsadcv4_get_temp, + .set_alarm_temp = rk_tsadcv3_alarm_temp, + .set_tshut_temp = rk_tsadcv3_tshut_temp, + .set_tshut_mode = rk_tsadcv3_tshut_mode, + .table = + { + .id = rk3588_code_table, + .length = RT_ARRAY_SIZE(rk3588_code_table), + .data_mask = TSADCV4_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static rt_ssize_t rk_tsadc_sensor_fetch_data(rt_sensor_t sensor, + rt_sensor_data_t buf, rt_size_t len) +{ + struct rockchip_tsadc *rk_tsadc; + const struct rockchip_tsadc_chip *chip; + struct rockchip_tsadc_channel *chn = raw_to_rockchip_tsadc_channel(sensor); + + if (sensor->info.type == RT_SENSOR_TYPE_TEMP) + { + int temp; + + rk_tsadc = chn->rk_tsadc; + chip = rk_tsadc->chip; + + if (!chip->get_temp(&chip->table, chn->id, rk_tsadc->regs, &temp)) + { + buf->type = RT_SENSOR_TYPE_TEMP; + buf->data.temp = temp / TEMP_SCALE; + buf->timestamp = rt_sensor_get_ts(); + + return 1; + } + } + + return 0; +} + +static rt_err_t rk_tsadc_sensor_control(rt_sensor_t sensor, int cmd, void *arg) +{ + struct rockchip_tsadc_channel *chn = raw_to_rockchip_tsadc_channel(sensor); + + switch (cmd) + { + case RT_SENSOR_CTRL_GET_ID: + *(rt_uint32_t *)arg = chn->id; + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +const static struct rt_sensor_ops rk_tsadc_sensor_ops = +{ + .fetch_data = rk_tsadc_sensor_fetch_data, + .control = rk_tsadc_sensor_control +}; + +static void rk_tsadc_isr(int irqno, void *param) +{ + struct rockchip_tsadc *rk_tsadc = param; + const struct rockchip_tsadc_chip *chip = rk_tsadc->chip; + + chip->irq_ack(rk_tsadc->regs); + + for (int i = 0; i < chip->chn_num; ++i) + { + struct rockchip_tsadc_channel *chn = &rk_tsadc->channels[i]; + + if (chn->parent.irq_handle) + { + chn->parent.irq_handle(&chn->parent); + } + else if (DBG_LEVEL >= DBG_ERROR) + { + /* shutdown if read temperature fail */ + int temp = rk_tsadc->tshut_temp; + + chip->get_temp(&chip->table, chn->id, + rk_tsadc->regs, &temp); + + LOG_E("Channel[%d]<%s> temperature = %d%s", i, chip->chn_name[i], + temp / TEMP_SCALE, RT_SENSOR_UNIT_CELSIUS_STR); + + if (temp >= rk_tsadc->tshut_temp) + { + rt_hw_cpu_shutdown(); + } + } + } +} + +static rt_err_t rockchip_tsadc_parse_ofw(struct rt_device *dev, + struct rockchip_tsadc *rk_tsadc) +{ + struct rt_ofw_node *np = dev->ofw_node; + rt_uint32_t shut_temp, tshut_mode, tshut_polarity; + + if (rt_ofw_prop_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) + { + rk_tsadc->tshut_temp = rk_tsadc->chip->tshut_temp; + } + else + { + if (shut_temp > TEMP_INVALID) + { + LOG_E("Invalid tshut temperature specified: %d", shut_temp); + + return -RT_EINVAL; + } + + rk_tsadc->tshut_temp = shut_temp; + } + + if (rt_ofw_prop_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) + { + LOG_W("Missing tshut mode property, using default (%s)", + rk_tsadc->chip->tshut_mode == TSHUT_MODE_GPIO ? "gpio" : "cru"); + + rk_tsadc->tshut_mode = rk_tsadc->chip->tshut_mode; + } + else + { + rk_tsadc->tshut_mode = tshut_mode; + } + + if (rk_tsadc->tshut_mode > 1) + { + LOG_E("Invalid tshut mode specified: %d", rk_tsadc->tshut_mode); + + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "rockchip,hw-tshut-polarity", &tshut_polarity)) + { + LOG_W("Missing tshut-polarity property, using default (%s)", + rk_tsadc->chip->tshut_polarity == TSHUT_LOW_ACTIVE ? "low" : "high"); + + rk_tsadc->tshut_polarity = rk_tsadc->chip->tshut_polarity; + } + else + { + rk_tsadc->tshut_polarity = tshut_polarity; + } + + if (rk_tsadc->tshut_polarity > 1) + { + LOG_E("Invalid tshut-polarity specified: %d", rk_tsadc->tshut_polarity); + + return -RT_EINVAL; + } + + rk_tsadc->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + + if (!rk_tsadc->grf) + { + LOG_W("Missing %s property", "rockchip,grf"); + } + + return RT_EOK; +} + +static void rockchip_tsadc_reset_controller(struct rockchip_tsadc *rk_tsadc) +{ + rt_reset_control_assert(rk_tsadc->rstc); + rt_hw_us_delay(15); + rt_reset_control_deassert(rk_tsadc->rstc); +} + +static rt_err_t rockchip_tsadc_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + const char *dev_name; + const struct chip_tsadc_table *table; + struct rt_device *dev = &pdev->parent; + const struct rockchip_tsadc_chip *chip = pdev->id->data; + struct rockchip_tsadc *rk_tsadc = rt_calloc(1, sizeof(*rk_tsadc) + + sizeof(rk_tsadc->channels[0]) * chip->chn_num); + + if (!rk_tsadc) + { + return -RT_ENOMEM; + } + + rk_tsadc->chip = chip; + table = &rk_tsadc->chip->table; + rk_tsadc->irq = rt_dm_dev_get_irq(dev, 0); + + if (rk_tsadc->irq < 0) + { + err = rk_tsadc->irq; + + goto _fail; + } + + rk_tsadc->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_tsadc->regs) + { + err = -RT_EIO; + + goto _fail; + } + + rk_tsadc->rstc = rt_reset_control_get_array(dev); + + if (!rk_tsadc->rstc) + { + err = -RT_EIO; + + goto _fail; + } + + rockchip_tsadc_reset_controller(rk_tsadc); + + rk_tsadc->clk = rt_clk_get_by_name(dev, "tsadc"); + rk_tsadc->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!rk_tsadc->clk || !rk_tsadc->pclk || + rt_clk_enable(rk_tsadc->clk) || rt_clk_enable(rk_tsadc->pclk)) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rockchip_tsadc_parse_ofw(dev, rk_tsadc))) + { + goto _fail; + } + + rk_tsadc->chip->initialize(rk_tsadc->grf, rk_tsadc->regs, rk_tsadc->tshut_polarity); + + for (int i = 0; i < rk_tsadc->chip->chn_num; ++i) + { + struct rockchip_tsadc_channel *channel = &rk_tsadc->channels[i]; + struct rt_sensor_device *sensor = &channel->parent; + + channel->id = chip->chn_offset + i; + channel->rk_tsadc = rk_tsadc; + + chip->set_tshut_mode(channel->id, rk_tsadc->regs, rk_tsadc->tshut_mode); + chip->set_tshut_temp(table, channel->id, rk_tsadc->regs, rk_tsadc->tshut_temp); + + sensor->info.type = RT_SENSOR_TYPE_TEMP; + sensor->info.name = "rockchip-tsadc"; + sensor->info.unit = RT_SENSOR_UNIT_CELSIUS; + sensor->info.scale.range_max = table->id[0].temp / TEMP_SCALE; + sensor->info.scale.range_min = table->id[table->length - 1].temp / TEMP_SCALE; + sensor->info.acquire_min = 100; + + sensor->ops = &rk_tsadc_sensor_ops; + + rt_dm_dev_set_name_auto(&sensor->parent, "tsadc"); + dev_name = rt_dm_dev_get_name(&sensor->parent); + + rt_hw_sensor_register(sensor, dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL); + } + + rk_tsadc->chip->control(rk_tsadc->regs, RT_TRUE); + + for (int i = 0; i < rk_tsadc->chip->chn_num; ++i) + { + int tshut_temp = rk_tsadc->tshut_temp; + struct rockchip_tsadc_channel *channel = &rk_tsadc->channels[i]; + + tshut_temp -= tshut_temp / 4; + + if (!chip->set_alarm_temp(table, channel->id, rk_tsadc->regs, tshut_temp)) + { + LOG_I("Channel[%d]<%s> set trip alarm %d%s ~ %d%s", i, chip->chn_name[i], + tshut_temp / TEMP_SCALE, RT_SENSOR_UNIT_CELSIUS_STR, + rk_tsadc->tshut_temp / TEMP_SCALE, RT_SENSOR_UNIT_CELSIUS_STR); + } + } + + rt_dm_dev_bind_fwdata(dev, RT_NULL, &rk_tsadc->parent); + + rt_hw_interrupt_install(rk_tsadc->irq, rk_tsadc_isr, rk_tsadc, "tsadc"); + rt_hw_interrupt_umask(rk_tsadc->irq); + + return RT_EOK; + +_fail: + if (rk_tsadc->rstc) + { + rt_reset_control_assert(rk_tsadc->rstc); + rt_reset_control_put(rk_tsadc->rstc); + } + if (rk_tsadc->clk) + { + rt_clk_disable(rk_tsadc->clk); + rt_clk_put(rk_tsadc->clk); + } + if (rk_tsadc->pclk) + { + rt_clk_disable(rk_tsadc->pclk); + rt_clk_put(rk_tsadc->pclk); + } + rt_free(rk_tsadc); + + return err; +} + +static const struct rt_ofw_node_id rockchip_tsadc_ofw_ids[] = +{ + { .compatible = "rockchip,px30-tsadc", .data = &px30_tsadc_data, }, + { .compatible = "rockchip,rv1108-tsadc", .data = &rv1108_tsadc_data, }, + { .compatible = "rockchip,rk3228-tsadc", .data = &rk3228_tsadc_data, }, + { .compatible = "rockchip,rk3288-tsadc", .data = &rk3288_tsadc_data, }, + { .compatible = "rockchip,rk3308-tsadc", .data = &rk3308_tsadc_data, }, + { .compatible = "rockchip,rk3328-tsadc", .data = &rk3328_tsadc_data, }, + { .compatible = "rockchip,rk3366-tsadc", .data = &rk3366_tsadc_data, }, + { .compatible = "rockchip,rk3368-tsadc", .data = &rk3368_tsadc_data, }, + { .compatible = "rockchip,rk3399-tsadc", .data = &rk3399_tsadc_data, }, + { .compatible = "rockchip,rk3568-tsadc", .data = &rk3568_tsadc_data, }, + { .compatible = "rockchip,rk3588-tsadc", .data = &rk3588_tsadc_data, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_tsadc_driver = +{ + .name = "rockchip-tsadc", + .ids = rockchip_tsadc_ofw_ids, + + .probe = rockchip_tsadc_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_tsadc_driver); diff --git a/components/drivers/sensor/sensor.c b/components/drivers/sensor/sensor.c index e100cc27c341..bbe92b2a990b 100644 --- a/components/drivers/sensor/sensor.c +++ b/components/drivers/sensor/sensor.c @@ -358,7 +358,7 @@ static rt_err_t _sensor_control(rt_device_t dev, int cmd, void *args) break; case RT_SENSOR_CTRL_SET_ACCURACY_MODE: /* Configuration sensor power mode */ - mode = (rt_uint32_t)args & 0x000F; + mode = (rt_uint32_t)(rt_ubase_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_ACCURACY_HIGHEST || mode == RT_SENSOR_MODE_ACCURACY_HIGH ||\ mode == RT_SENSOR_MODE_ACCURACY_MEDIUM || mode == RT_SENSOR_MODE_ACCURACY_LOW ||\ mode == RT_SENSOR_MODE_ACCURACY_LOWEST || mode == RT_SENSOR_MODE_ACCURACY_NOTRUST)) @@ -375,7 +375,7 @@ static rt_err_t _sensor_control(rt_device_t dev, int cmd, void *args) break; case RT_SENSOR_CTRL_SET_POWER_MODE: /* Configuration sensor power mode */ - mode = (rt_uint32_t)args & 0x000F; + mode = (rt_uint32_t)(rt_ubase_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_POWER_HIGHEST || mode == RT_SENSOR_MODE_POWER_HIGH ||\ mode == RT_SENSOR_MODE_POWER_MEDIUM || mode == RT_SENSOR_MODE_POWER_LOW ||\ mode == RT_SENSOR_MODE_POWER_LOWEST || mode == RT_SENSOR_MODE_POWER_DOWN)) @@ -392,7 +392,7 @@ static rt_err_t _sensor_control(rt_device_t dev, int cmd, void *args) break; case RT_SENSOR_CTRL_SET_FETCH_MODE: /* Configuration sensor power mode */ - mode = (rt_uint32_t)args & 0x000F; + mode = (rt_uint32_t)(rt_ubase_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_FETCH_POLLING || mode == RT_SENSOR_MODE_FETCH_INT ||\ mode == RT_SENSOR_MODE_FETCH_FIFO)) { diff --git a/components/drivers/sensor/sensor_cmd.c b/components/drivers/sensor/sensor_cmd.c index 4b094fb18d93..88b4faf14d02 100644 --- a/components/drivers/sensor/sensor_cmd.c +++ b/components/drivers/sensor/sensor_cmd.c @@ -713,7 +713,7 @@ static void sensor(int argc, char **argv) else if (argc == 3) { mode = atoi(argv[2]); - if (rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER_MODE, (void *)mode) == RT_EOK) + if (rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER_MODE, (void *)(rt_ubase_t)mode) == RT_EOK) { rt_kprintf("set new power mode as: %s\n", sensor_get_power_mode_name(&sensor->info)); } @@ -745,7 +745,7 @@ static void sensor(int argc, char **argv) else if (argc == 3) { mode = atoi(argv[2]); - if (rt_device_control(dev, RT_SENSOR_CTRL_SET_ACCURACY_MODE, (void *)mode) == RT_EOK) + if (rt_device_control(dev, RT_SENSOR_CTRL_SET_ACCURACY_MODE, (void *)(rt_ubase_t)mode) == RT_EOK) { rt_kprintf("set new accuracy mode as: %s\n", sensor_get_accuracy_mode_name(&sensor->info)); } @@ -777,7 +777,7 @@ static void sensor(int argc, char **argv) else if (argc == 3) { mode = atoi(argv[2]); - if (rt_device_control(dev, RT_SENSOR_CTRL_SET_FETCH_MODE, (void *)mode) == RT_EOK) + if (rt_device_control(dev, RT_SENSOR_CTRL_SET_FETCH_MODE, (void *)(rt_ubase_t)mode) == RT_EOK) { rt_kprintf("set new fetch data mode as: %s\n", sensor_get_fetch_mode_name(&sensor->info)); } diff --git a/components/drivers/serial/8250/8250-bcm2835aux.c b/components/drivers/serial/8250/8250-bcm2835aux.c new file mode 100755 index 000000000000..bbed610a236b --- /dev/null +++ b/components/drivers/serial/8250/8250-bcm2835aux.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-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 (serial->clk) + { + rt_clk_disable_unprepare(serial->clk); + rt_clk_put(serial->clk); + } + + rt_free(bcm2835aux); +} + +static void bcm2835aux_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 (!serial->clk) + { + err = -RT_EIO; + goto _free_res; + } + + if ((err = rt_clk_enable(serial->clk))) + { + goto _free_res; + } + + serial->freq = rt_clk_get_rate(serial->clk); + + rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent); + + serial = &bcm2835aux->parent; + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->regshift = 2; + serial->iotype = PORT_MMIO; + serial->remove = &bcm2835aux_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 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, +}; + +static int bcm2835aux_drv_register(void) +{ + rt_platform_driver_register(&bcm2835aux_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(bcm2835aux_drv_register); diff --git a/components/drivers/serial/8250/8250_dw.c b/components/drivers/serial/8250/8250-dw.c similarity index 63% rename from components/drivers/serial/8250/8250_dw.c rename to components/drivers/serial/8250/8250-dw.c index 995769cdf95d..5cec9752de16 100755 --- a/components/drivers/serial/8250/8250_dw.c +++ b/components/drivers/serial/8250/8250-dw.c @@ -16,12 +16,7 @@ #include -#include - -#include -#include -#include -#include +#include "8250.h" /* Offsets for the DesignWare specific registers */ #define DW_UART_USR 0x1f /* UART Status Register */ @@ -60,6 +55,8 @@ struct dw8250 struct serial8250 parent; struct rt_spinlock spinlock; + struct rt_clk *pclk; + rt_bool_t uart_16550_compatible; struct dw8250_platform_data *platform_data; }; @@ -123,7 +120,10 @@ static rt_err_t dw8250_isr(struct serial8250 *serial, int irq) iir = serial8250_in(serial, UART_IIR); - /* If don't do this in non-DMA mode then the "RX TIMEOUT" interrupt will fire forever. */ + /* + * If don't do this in non-DMA mode then the "RX TIMEOUT" interrupt will + * fire forever. + */ if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { rt_base_t level = rt_spin_lock_irqsave(&dw8250->spinlock); @@ -152,66 +152,136 @@ static rt_err_t dw8250_isr(struct serial8250 *serial, int irq) return RT_EOK; } +static void dw8250_free_resource(struct dw8250 *dw8250) +{ + struct serial8250 *serial = &dw8250->parent; + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (serial->clk) + { + rt_clk_disable_unprepare(serial->clk); + rt_clk_put(serial->clk); + } + + if (dw8250->pclk) + { + rt_clk_disable_unprepare(dw8250->pclk); + rt_clk_put(dw8250->pclk); + } + + rt_free(dw8250); +} + static void dw8250_remove(struct serial8250 *serial) { - rt_free(rt_container_of(serial, struct dw8250, parent)); + struct dw8250 *dw8250 = to_dw8250(serial); + + dw8250_free_resource(dw8250); } -static rt_err_t dw8250_probe(struct rt_device_node *node, const struct rt_of_device_id *id) +static rt_err_t dw8250_probe(struct rt_platform_device *pdev) { - rt_err_t ret = RT_EOK; - struct serial8250 *serial = RT_NULL; + rt_err_t err; + rt_uint32_t val; + struct serial8250 *serial; + struct rt_device *dev = &pdev->parent; struct dw8250 *dw8250 = serial8250_alloc(dw8250); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!dw8250) + { + return -RT_ENOMEM; + } - if (dw8250) + serial = &dw8250->parent; + serial->base = rt_dm_dev_iomap(dev, 0); + + if (!serial->base) { - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + err = -RT_EIO; + + goto _free_res; + } - // TODO: remove - config.baud_rate = 1500000; - serial = &dw8250->parent; - serial->base = rt_of_iomap(node, 0); + serial->irq = rt_dm_dev_get_irq(dev, 0); - if (serial->base) + if (serial->irq < 0) + { + err = serial->irq; + + goto _free_res; + } + + serial->clk = rt_clk_get_by_name(dev, "baudclk"); + dw8250->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!serial->clk) + { + if ((err = rt_dm_dev_prop_read_u32(dev, "clock-frequency", &serial->freq))) { - rt_uint32_t val; - - serial->irq = rt_of_irq_get(node, 0); - - serial->parent.ops = &serial8250_uart_ops; - serial->parent.config = config; - // TODO "clock-frequency" - serial->freq = 24000000; - rt_of_property_read_u32(node, "reg-shift", &serial->regshift); - if (!rt_of_property_read_u32(node, "reg-io-width", &val) && val == 4) - { - serial->iotype = PORT_MMIO32; - serial->serial_in = &dw8250_serial_in32; - serial->serial_out = &dw8250_serial_out32; - } - serial->handle_irq = &dw8250_isr; - serial->remove = &dw8250_remove; - serial->data = dw8250; - - rt_spin_lock_init(&dw8250->spinlock); - dw8250->uart_16550_compatible = rt_of_property_read_bool(node, "snps,uart-16550-compatible"); - dw8250->platform_data = (struct dw8250_platform_data *)id->data; - rt_of_data(node) = &serial->parent; - - ret = serial8250_setup(serial); + goto _free_res; } - else + } + else + { + if ((err = rt_clk_prepare_enable(serial->clk))) { - rt_free(dw8250); - ret = -RT_ERROR; + goto _free_res; } + + serial->freq = rt_clk_get_rate(serial->clk); } - else + + if (!dw8250->pclk) + { + err = -RT_EIO; + + goto _free_res; + } + + if ((err = rt_clk_prepare_enable(dw8250->pclk))) + { + goto _free_res; + } + + rt_dm_dev_prop_read_u32(dev, "reg-shift", &serial->regshift); + + if (!rt_dm_dev_prop_read_u32(dev, "reg-io-width", &val) && val == 4) { - ret = -RT_ENOMEM; + serial->iotype = PORT_MMIO32; + serial->serial_in = &dw8250_serial_in32; + serial->serial_out = &dw8250_serial_out32; } - return ret; + dw8250->uart_16550_compatible = rt_dm_dev_prop_read_bool(dev, "snps,uart-16550-compatible"); + dw8250->platform_data = (struct dw8250_platform_data *)pdev->id->data; + + rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent); + + serial = &dw8250->parent; + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->handle_irq = &dw8250_isr; + serial->remove = &dw8250_remove; + serial->data = dw8250; + + rt_spin_lock_init(&dw8250->spinlock); + + if ((err = serial8250_setup(serial))) + { + goto _free_res; + } + + return RT_EOK; + +_free_res: + dw8250_free_resource(dw8250); + + return err; } static const struct dw8250_platform_data dw8250_dw_apb = @@ -244,7 +314,7 @@ static const struct dw8250_platform_data dw8250_starfive_jh7100_data = .quirks = DW_UART_QUIRK_SKIP_SET_RATE, }; -static const struct rt_of_device_id dw8250_of_match[] = +static const struct rt_ofw_node_id dw8250_ofw_ids[] = { { .type = "ttyS", .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb }, { .type = "ttyS", .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data }, @@ -253,4 +323,19 @@ static const struct rt_of_device_id dw8250_of_match[] = { .type = "ttyS", .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data }, { /* sentinel */ } }; -RT_OF_DECLARE_DEVICE(dw8250_of_match, dw8250_probe); + +static struct rt_platform_driver dw8250_driver = +{ + .name = "dw-apb-uart", + .ids = dw8250_ofw_ids, + + .probe = dw8250_probe, +}; + +static int dw8250_drv_register(void) +{ + rt_platform_driver_register(&dw8250_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(dw8250_drv_register); diff --git a/components/drivers/serial/8250/8250-ofw.c b/components/drivers/serial/8250/8250-ofw.c new file mode 100644 index 000000000000..ad36bdd162c3 --- /dev/null +++ b/components/drivers/serial/8250/8250-ofw.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-09 GuEe-GUI first version + */ + +#include + +#include "8250.h" + +struct ofw_platform_8250 +{ + struct serial8250 parent; + + struct rt_reset_control *rstc; +}; + +#define to_ofw_platform_8250(serial8250) rt_container_of(serial8250, struct ofw_platform_8250, parent) + +static void ofw_platform_8250_free_resource(struct ofw_platform_8250 *op8250) +{ + struct serial8250 *serial = &op8250->parent; + + if (serial->base) + { + rt_iounmap(serial->base); + } + + if (serial->clk) + { + rt_clk_disable_unprepare(serial->clk); + rt_clk_put(serial->clk); + } + + if (op8250->rstc) + { + rt_reset_control_put(op8250->rstc); + } + + rt_free(op8250); +} + +static void op8250_remove(struct serial8250 *serial) +{ + struct ofw_platform_8250 *op8250 = to_ofw_platform_8250(serial); + + ofw_platform_8250_free_resource(op8250); +} + +static rt_err_t ofw_platform_8250_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + struct serial8250 *serial; + struct ofw_platform_8250 *op8250; + struct rt_ofw_node *np = pdev->parent.ofw_node; + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (rt_ofw_prop_read_bool(np, "used-by-rtas")) + { + return -RT_EBUSY; + } + + op8250 = serial8250_alloc(op8250); + + if (!op8250) + { + return -RT_ENOMEM; + } + + serial = &op8250->parent; + serial->base = rt_ofw_iomap(np, 0); + + if (!serial->base) + { + err = -RT_EIO; + + goto _fail; + } + + serial->irq = rt_ofw_get_irq(np, 0); + + if (serial->irq < 0) + { + err = serial->irq; + + goto _fail; + } + + if (!rt_ofw_prop_read_u32(np, "clock-frequency", &val)) + { + serial->freq = val; + } + else + { + serial->clk = rt_ofw_get_clk(np, 0); + + if (serial->clk) + { + goto _fail; + } + + if ((err = rt_clk_prepare_enable(serial->clk))) + { + goto _fail; + } + + serial->freq = rt_clk_get_rate(serial->clk); + } + + if (!rt_ofw_prop_read_u32(np, "reg-shift", &val)) + { + serial->regshift = val; + } + + serial->iotype = PORT_MMIO; + if (!rt_ofw_prop_read_u32(np, "reg-io-width", &val)) + { + switch (val) + { + case 1: + serial->iotype = PORT_MMIO; + break; + + case 2: + serial->iotype = PORT_MMIO16; + break; + + case 4: + serial->iotype = rt_ofw_prop_read_bool(np, "big-endian") ? + PORT_MMIO32BE : PORT_MMIO32; + break; + } + } + + if (rt_ofw_prop_read_bool(np, "resets")) + { + op8250->rstc = rt_ofw_get_reset_control_by_index(np, 0); + + if (!op8250->rstc) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_reset_control_deassert(op8250->rstc))) + { + goto _fail; + } + } + + rt_dm_dev_bind_fwdata(&serial->parent.parent, pdev->parent.ofw_node, &serial->parent); + + serial = &op8250->parent; + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + serial->remove = &op8250_remove; + serial->data = op8250; + + return RT_EOK; + +_fail: + ofw_platform_8250_free_resource(op8250); + + return err; +} + +static const struct rt_ofw_node_id ofw_platform_8250_ofw_ids[] = +{ + { .type = "ttyS", .compatible = "ns16550a" }, + { .type = "ttyS", .compatible = "ns16550" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver ofw_platform_8250_driver = +{ + .name = "8250-ofw", + .ids = ofw_platform_8250_ofw_ids, + + .probe = ofw_platform_8250_probe, +}; + +static int ofw_platform_8250_drv_register(void) +{ + rt_platform_driver_register(&ofw_platform_8250_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(ofw_platform_8250_drv_register); \ No newline at end of file diff --git a/components/drivers/serial/8250/8250-pci.c b/components/drivers/serial/8250/8250-pci.c new file mode 100644 index 000000000000..ea51cdeecc21 --- /dev/null +++ b/components/drivers/serial/8250/8250-pci.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-09 GuEe-GUI first version + */ + +#include + +#include "8250.h" + +#define IO_PORT_BAR 0 + +#define DW_UART_USR 0x1f /* UART Status Register */ + +enum +{ + PCI_SERIAL = 0, + PCI_SERIAL2 = 2, + PCI_SERIAL4 = 4, +}; + +enum +{ + SERIAL_8250 = 0, + SERIAL_16450, + SERIAL_16550, + SERIAL_16650, + SERIAL_16750, + SERIAL_16850, + SERIAL_16950, +}; + +struct pci_serial +{ + struct serial8250 parent; + struct rt_spinlock spinlock; + + struct rt_pci_device *pci_dev; + + rt_uint8_t type; + rt_uint8_t compat; +}; + +#define to_pci_serial(raw) rt_container_of(raw, struct pci_serial, parent) + +static rt_err_t pci_serial_isr(struct serial8250 *serial, int irq) +{ + rt_uint32_t iir; + void *base = serial->base; + + iir = HWREG8(base) = UART_IIR; + + if (!(iir & UART_IIR_NO_INT)) + { + rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND); + } + + if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) + { + /* Clear the USR */ + HWREG8(base) = DW_UART_USR; + } + + return RT_EOK; +} + +static void pci_serial_free_resource(struct pci_serial *pci_serial) +{ + struct serial8250 *serial = &pci_serial->parent; + + if (serial->base) + { + rt_iounmap(serial->base); + } + + rt_free(pci_serial); +} + +static void pci_serial_remove(struct serial8250 *serial) +{ + struct pci_serial *pci_serial = to_pci_serial(serial); + + rt_pci_intx(pci_serial->pci_dev, RT_FALSE); + + pci_serial_free_resource(pci_serial); +} + +static rt_err_t pci_serial_probe(struct rt_pci_device *pdev) +{ + rt_err_t err; + struct serial8250 *serial; + struct pci_serial *pci_serial = serial8250_alloc(pci_serial); + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (!pci_serial) + { + return -RT_ENOMEM; + } + + serial = &pci_serial->parent; + serial->size = pdev->resource[IO_PORT_BAR].size; + serial->base = rt_pci_iomap(pdev, IO_PORT_BAR); + + if (!serial->base) + { + err = -RT_EIO; + + goto _free_res; + } + + serial->irq = pdev->irq; + + serial->parent.ops = &serial8250_uart_ops; + serial->parent.config = config; + // if (pdev->bus->cur_bus_speed == PCI_SPEED_UNKNOWN) + // { + serial->freq = 1843200; + // } + // else + // { + // /* TODO */ + // } + serial->handle_irq = &pci_serial_isr; + serial->iotype = PORT_MMIO; + serial->remove = &pci_serial_remove; + serial->data = pci_serial; + + pci_serial->pci_dev = pdev; + pci_serial->type = (rt_ubase_t)pdev->id->data; + rt_spin_lock_init(&pci_serial->spinlock); + rt_pci_read_config_u8(pdev, PCIR_PROGIF, &pci_serial->compat); + + if ((err = serial8250_setup(serial))) + { + goto _free_res; + } + + rt_pci_intx(pci_serial->pci_dev, RT_TRUE); + + return RT_EOK; + +_free_res: + pci_serial_free_resource(pci_serial); + + return err; +} + +static struct rt_pci_device_id pci_serial_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0002), .data = (void *)PCI_SERIAL, }, + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0003), .data = (void *)PCI_SERIAL2, }, + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0004), .data = (void *)PCI_SERIAL4, }, + { /* sentinel */ } +}; + +static struct rt_pci_driver pci_serial_driver = +{ + .name = "pci-serial", + + .ids = pci_serial_pci_ids, + .probe = pci_serial_probe, +}; +RT_PCI_DRIVER_EXPORT(pci_serial_driver); diff --git a/components/drivers/serial/8250/serial8250.h b/components/drivers/serial/8250/8250.h similarity index 83% rename from components/drivers/serial/8250/serial8250.h rename to components/drivers/serial/8250/8250.h index dfb4358369bd..8582d8429486 100755 --- a/components/drivers/serial/8250/serial8250.h +++ b/components/drivers/serial/8250/8250.h @@ -8,16 +8,17 @@ * 2022-11-16 GuEe-GUI first version */ -#ifndef __8250_SERIAL_H__ -#define __8250_SERIAL_H__ +#ifndef __SERIAL_8250_H__ +#define __SERIAL_8250_H__ #include #include #include -#include -#include -#include +#include + +#include "regs.h" +#include "../serial_dm.h" enum { @@ -31,7 +32,7 @@ enum struct serial8250 { struct rt_serial_device parent; - struct clk *clk; + struct rt_clk *clk; int irq; void *base; @@ -40,7 +41,7 @@ struct serial8250 rt_uint32_t regshift; /* reg offset shift */ rt_uint8_t iotype; /* io access style */ - rt_hw_spinlock_t spinlock; + struct rt_spinlock spinlock; rt_uint32_t (*serial_in)(struct serial8250 *, int offset); void (*serial_out)(struct serial8250 *, int offset, int value); @@ -56,6 +57,7 @@ struct serial8250 rt_err_t serial8250_config(struct serial8250 *serial, const char *options); rt_err_t serial8250_setup(struct serial8250 *serial); +rt_err_t serial8250_remove(struct serial8250 *serial); rt_uint32_t serial8250_in(struct serial8250 *serial, int offset); void serial8250_out(struct serial8250 *serial, int offset, int value); @@ -66,9 +68,9 @@ int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c); int serial8250_uart_getc(struct rt_serial_device *raw_serial); int serial8250_early_putc(struct rt_serial_device *raw_serial, char c); -rt_err_t serial8250_early_of_setup(struct serial8250 *serial, struct rt_of_earlycon_desc *desc, const char *options); +rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options); extern struct serial8250 early_serial8250; extern const struct rt_uart_ops serial8250_uart_ops; -#endif /* __8250_SERIAL_H__ */ +#endif /* __SERIAL_8250_H__ */ diff --git a/components/drivers/serial/8250/8250_bcm2835aux.c b/components/drivers/serial/8250/8250_bcm2835aux.c deleted file mode 100755 index 5ac34a825f35..000000000000 --- a/components/drivers/serial/8250/8250_bcm2835aux.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 - -#include -#include -#include -#include - -#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; -}; - -static void bcm2835aux_remove(struct serial8250 *serial) -{ - rt_free(rt_container_of(serial, struct bcm2835aux, parent)); -} - -static rt_err_t bcm2835aux_probe(struct rt_device_node *node, const struct rt_of_device_id *id) -{ - rt_err_t ret = RT_EOK; - struct serial8250 *serial = RT_NULL; - struct bcm2835aux *bcm2835aux = serial8250_alloc(bcm2835aux); - - if (bcm2835aux) - { - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - - serial = &bcm2835aux->parent; - serial->base = rt_of_iomap(node, 0); - - if (serial->base) - { - serial->clk = clk_of_get(node, 0); - clk_enable(serial->clk); - serial->freq = clk_get_rate(serial->clk); - - if (!serial->freq) - { - rt_iounmap(serial->base); - serial->base = RT_NULL; - } - } - - if (serial->base) - { - serial->irq = rt_of_irq_get(node, 0); - - serial->parent.ops = &serial8250_uart_ops; - serial->parent.config = config; - serial->regshift = 2; - serial->iotype = PORT_MMIO; - serial->remove = &bcm2835aux_remove; - serial->data = bcm2835aux; - - bcm2835aux->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN; - rt_of_data(node) = &serial->parent; - - ret = serial8250_setup(serial); - } - else - { - rt_free(bcm2835aux); - ret = -RT_ERROR; - } - } - else - { - ret = -RT_ENOMEM; - } - - return ret; -} - -static const struct rt_of_device_id bcm2835aux_of_match[] = -{ - { .type = "ttyS", .compatible = "brcm,bcm2835-aux-uart" }, - { /* sentinel */ } -}; -RT_OF_DECLARE_DEVICE(bcm2835aux_of_match, bcm2835aux_probe); diff --git a/components/drivers/serial/8250/8250_pci.c b/components/drivers/serial/8250/8250_pci.c deleted file mode 100755 index 909dec9e6f5e..000000000000 --- a/components/drivers/serial/8250/8250_pci.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-11-09 GuEe-GUI first version - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define IO_PORT_BAR 0 - -#define DW_UART_USR 0x1f /* UART Status Register */ - -enum -{ - PCI_SERIAL = 0, - PCI_SERIAL2 = 2, - PCI_SERIAL4 = 4, -}; - -enum -{ - SERIAL_8250 = 0, - SERIAL_16450, - SERIAL_16550, - SERIAL_16650, - SERIAL_16750, - SERIAL_16850, - SERIAL_16950, -}; - -struct pci_serial -{ - struct serial8250 parent; - struct rt_spinlock spinlock; - - struct pci_device *dev; - - rt_uint8_t type; - rt_uint8_t compat; -}; - -#define raw_to_pci_serial(raw) rt_container_of(raw, struct pci_serial, parent) - -static rt_err_t pci_serial_isr(struct serial8250 *serial, int irq) -{ - unsigned int iir; - void *base = serial->base; - - iir = HWREG8(base) = UART_IIR; - - if (!(iir & UART_IIR_NO_INT)) - { - rt_hw_serial_isr(&serial->parent, RT_SERIAL_EVENT_RX_IND); - } - - if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) - { - /* Clear the USR */ - HWREG8(base) = DW_UART_USR; - } - - return RT_EOK; -} - -static void pci_serial_8250_remove(struct serial8250 *serial) -{ - struct pci_serial *pci_serial = raw_to_pci_serial(serial); - - pci_serial->dev->dev = RT_NULL; - rt_free(pci_serial); -} - -static rt_err_t pci_serial_probe(struct pci_device *dev, const struct pci_device_id *id) -{ - rt_err_t ret = RT_EOK; - struct serial8250 *serial = RT_NULL; - struct pci_serial *pci_serial = serial8250_alloc(pci_serial); - - if (pci_serial) - { - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - - serial = &pci_serial->parent; - serial->size = dev->resource[IO_PORT_BAR].size; - serial->base = rt_ioremap((void *)dev->resource[IO_PORT_BAR].base, serial->size); - - if (serial->base) - { - serial->irq = dev->irq; - - serial->parent.ops = &serial8250_uart_ops; - serial->parent.config = config; - if (dev->bus->cur_bus_speed == PCI_SPEED_UNKNOWN) - { - serial->freq = 1843200; - } - else - { - /* TODO */ - } - serial->handle_irq = &pci_serial_isr; - serial->iotype = PORT_MMIO; - serial->remove = &pci_serial_8250_remove; - serial->data = pci_serial; - - pci_serial->dev = dev; - pci_serial->type = (rt_ubase_t)id->data; - rt_spin_lock_init(&pci_serial->spinlock); - dev->dev = (typeof(dev->dev))&pci_serial->parent; - pci_read_config_byte(dev, PCI_CLASS_PROG, &pci_serial->compat); - - ret = serial8250_setup(serial); - - if (!ret) - { - pci_intx(pci_serial->dev, RT_TRUE); - } - } - else - { - rt_free(pci_serial); - ret = -RT_EIO; - } - } - else - { - ret = -RT_ENOMEM; - } - - return ret; -} - -static void pci_serial_remove(struct pci_device *dev) -{ - pci_serial_8250_remove((struct serial8250 *)dev->dev); -} - -static struct pci_device_id pci_serial_pci_ids[] = -{ - { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, 0x0002), .data = (void *)PCI_SERIAL, }, - { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, 0x0003), .data = (void *)PCI_SERIAL2, }, - { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, 0x0004), .data = (void *)PCI_SERIAL4, }, - { /* sentinel */ } -}; - -static struct pci_driver pci_serial_drv = -{ - .name = "pci-serial", - .id_table = pci_serial_pci_ids, - .probe = pci_serial_probe, - .remove = pci_serial_remove, -}; -PCI_DECLARE(pci_serial, pci_serial_drv); diff --git a/components/drivers/serial/8250/Kconfig b/components/drivers/serial/8250/Kconfig new file mode 100644 index 000000000000..ed0205e519c8 --- /dev/null +++ b/components/drivers/serial/8250/Kconfig @@ -0,0 +1,26 @@ +menuconfig RT_SERIAL_8250 + bool "8250 Serila Family" + default n + +config RT_SERIAL_8250_BCM2835AUX + bool "BCM2835 auxiliar mini UART" + depends on RT_SERIAL_8250 + default n + +config RT_SERIAL_8250_DW + bool "Synopsys DesignWare 8250" + depends on RT_SERIAL_8250 + default n + +config RT_SERIAL_8250_OFW + bool "8250 Platform" + depends on RT_SERIAL_8250 + select RT_USING_OFW + select RT_USING_RESET + default n + +config RT_SERIAL_8250_PCI + bool "8250 PCI/2x/4x" + depends on RT_SERIAL_8250 + select RT_USING_PCI + default n diff --git a/components/drivers/serial/8250/SConscript b/components/drivers/serial/8250/SConscript index 6fdad029dc48..16ec680a3583 100755 --- a/components/drivers/serial/8250/SConscript +++ b/components/drivers/serial/8250/SConscript @@ -1,12 +1,26 @@ from building import * -cwd = GetCurrentDir() -src = [] -CPPPATH = [cwd + '/../../include'] group = [] -if not GetDepend(['RT_USING_SERIAL_8250']): +if not GetDepend(['RT_SERIAL_8250']): Return('group') +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = ['core.c', 'early.c'] + +if GetDepend(['RT_SERIAL_8250_BCM2835AUX']): + src += ['8250-bcm2835aux.c'] + +if GetDepend(['RT_SERIAL_8250_DW']): + src += ['8250-dw.c'] + +if GetDepend(['RT_SERIAL_8250_OFW']): + src += ['8250-ofw.c'] + +if GetDepend(['RT_SERIAL_8250_PCI']): + src += ['8250-pci.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/serial/8250/core.c b/components/drivers/serial/8250/core.c index 30d7fa336d00..8551e320eae7 100755 --- a/components/drivers/serial/8250/core.c +++ b/components/drivers/serial/8250/core.c @@ -8,11 +8,7 @@ * 2022-11-16 GuEe-GUI first version */ -#include - -#include -#include -#include +#include "8250.h" rt_err_t serial8250_config(struct serial8250 *serial, const char *options) { @@ -65,7 +61,7 @@ rt_err_t serial8250_config(struct serial8250 *serial, const char *options) serial->iotype = PORT_MMIO32; - for (int i = 0; i < rt_array_size(iotype_table); ++i) + for (int i = 0; i < RT_ARRAY_SIZE(iotype_table); ++i) { if (!rt_strcmp(arg, iotype_table[i].param)) { @@ -79,7 +75,6 @@ rt_err_t serial8250_config(struct serial8250 *serial, const char *options) } serial->parent.config = serial_cfg_from_args(arg); - break; } if (!serial->size) @@ -108,18 +103,22 @@ static void serial8250_isr(int irqno, void *param) rt_err_t serial8250_setup(struct serial8250 *serial) { rt_err_t ret = RT_EOK; + const char *uart_name; char dev_name[RT_NAME_MAX]; if (serial) { - rt_hw_spin_lock_init(&serial->spinlock); + rt_spin_lock_init(&serial->spinlock); + + serial->serial_in = serial->serial_in ? : &serial8250_in; + serial->serial_out = serial->serial_out ? : &serial8250_out; - serial->serial_in = serial->serial_in ? serial->serial_in : &serial8250_in; - serial->serial_out = serial->serial_out ? serial->serial_out : &serial8250_out; + serial_dev_set_name(&serial->parent); + uart_name = rt_dm_dev_get_name(&serial->parent.parent); - rt_sprintf(dev_name, "uart%d", serial_next_id()); + rt_hw_serial_register(&serial->parent, uart_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, serial->data); - rt_hw_serial_register(&serial->parent, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, serial->data); + rt_snprintf(dev_name, sizeof(dev_name), "%s-8250", uart_name); rt_hw_interrupt_install(serial->irq, serial8250_isr, serial, dev_name); } else @@ -130,6 +129,26 @@ rt_err_t serial8250_setup(struct serial8250 *serial) return ret; } +rt_err_t serial8250_remove(struct serial8250 *serial) +{ + rt_err_t err; + + rt_iounmap((void *)serial->base); + serial->base = RT_NULL; + + rt_hw_interrupt_mask(serial->irq); + rt_hw_interrupt_uninstall(serial->irq, serial8250_isr, serial); + + err = rt_device_unregister(&serial->parent.parent); + + if (!err && serial->remove) + { + serial->remove(serial); + } + + return err; +} + rt_uint32_t serial8250_in(struct serial8250 *serial, int offset) { rt_uint32_t ret = 0; @@ -191,78 +210,61 @@ void serial8250_out(struct serial8250 *serial, int offset, int value) rt_err_t serial8250_uart_configure(struct rt_serial_device *raw_serial, struct serial_configure *cfg) { - rt_err_t ret = RT_EOK; + rt_err_t err = RT_EOK; struct serial8250 *serial = raw_to_serial8250(raw_serial); + /* Disable interrupt */ serial->serial_out(serial, UART_IER, !UART_IER_RDI); /* Enable FIFO, Clear FIFO*/ serial->serial_out(serial, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - /* Disable interrupt */ - serial->serial_out(serial, UART_IER, 0); - /* DTR + RTS */ - serial->serial_out(serial, UART_MCR, 0x3); + serial->serial_out(serial, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + if (serial->freq) { - unsigned char lcr = serial8250_in(serial, UART_LCR); - rt_uint32_t wlen = cfg->data_bits + (UART_LCR_WLEN5 - DATA_BITS_5); - #if 0 + rt_uint32_t wlen = cfg->data_bits - DATA_BITS_5 + UART_LCR_WLEN5; rt_uint32_t divisor = serial->freq / 16 / cfg->baud_rate; /* Enable access DLL & DLH */ - serial->serial_out(serial, UART_LCR, lcr | UART_LCR_DLAB); + serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) | UART_LCR_DLAB); serial->serial_out(serial, UART_DLL, (divisor & 0xff)); serial->serial_out(serial, UART_DLM, (divisor >> 8) & 0xff); /* Clear DLAB bit */ - serial->serial_out(serial, UART_LCR, lcr & (~UART_LCR_DLAB)); - #endif + serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_DLAB)); - serial->serial_out(serial, UART_LCR, (lcr & (~wlen)) | wlen); - serial->serial_out(serial, UART_LCR, lcr & (~UART_LCR_STOP)); - serial->serial_out(serial, UART_LCR, lcr & (~UART_LCR_PARITY)); + serial->serial_out(serial, UART_LCR, (serial->serial_in(serial, UART_LCR) & (~wlen)) | wlen); + serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_STOP)); + serial->serial_out(serial, UART_LCR, serial->serial_in(serial, UART_LCR) & (~UART_LCR_PARITY)); } serial->serial_out(serial, UART_IER, UART_IER_RDI); - return ret; + return err; } rt_err_t serial8250_uart_control(struct rt_serial_device *raw_serial, int cmd, void *arg) { - rt_err_t ret = RT_EOK; + rt_err_t err = RT_EOK; struct serial8250 *serial = raw_to_serial8250(raw_serial); switch (cmd) { - case RT_DEVICE_CTRL_CLR_INT: - /* disable rx irq */ - serial->serial_out(serial, UART_IER, !UART_IER_RDI); - rt_hw_interrupt_mask(serial->irq); - break; - - case RT_DEVICE_CTRL_SET_INT: - /* enable rx irq */ - serial->serial_out(serial, UART_IER, UART_IER_RDI); - rt_hw_interrupt_umask(serial->irq); - break; - - case RT_DEVICE_CTRL_SHUTDOWN: - rt_iounmap((void *)serial->base); - rt_hw_interrupt_mask(serial->irq); - rt_hw_interrupt_uninstall(serial->irq, serial8250_isr, serial); - - rt_device_unregister(&serial->parent.parent); - - if (serial->remove) - { - serial->remove(serial); - } - break; + case RT_DEVICE_CTRL_CLR_INT: + /* disable rx irq */ + serial->serial_out(serial, UART_IER, !UART_IER_RDI); + rt_hw_interrupt_mask(serial->irq); + break; + + case RT_DEVICE_CTRL_SET_INT: + /* enable rx irq */ + serial->serial_out(serial, UART_IER, UART_IER_RDI); + rt_hw_interrupt_umask(serial->irq); + break; } - return ret; + return err; } int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c) @@ -271,6 +273,7 @@ int serial8250_uart_putc(struct rt_serial_device *raw_serial, char c) while (!(serial->serial_in(serial, UART_LSR) & 0x20)) { + rt_hw_cpu_relax(); } serial->serial_out(serial, UART_TX, c); @@ -293,8 +296,8 @@ int serial8250_uart_getc(struct rt_serial_device *raw_serial) const struct rt_uart_ops serial8250_uart_ops = { - serial8250_uart_configure, - serial8250_uart_control, - serial8250_uart_putc, - serial8250_uart_getc, + .configure = serial8250_uart_configure, + .control = serial8250_uart_control, + .putc = serial8250_uart_putc, + .getc = serial8250_uart_getc, }; diff --git a/components/drivers/serial/8250/early.c b/components/drivers/serial/8250/early.c index 047bf7fd447a..359243ab48f6 100755 --- a/components/drivers/serial/8250/early.c +++ b/components/drivers/serial/8250/early.c @@ -8,14 +8,7 @@ * 2022-11-16 GuEe-GUI first version */ -#include -#include - -#include -#include - -#include -#include +#include "8250.h" struct serial8250 early_serial8250 = { 0 }; @@ -70,26 +63,46 @@ static void init_serial(struct serial8250 *serial) } } -rt_err_t serial8250_early_of_setup(struct serial8250 *serial, struct rt_of_earlycon_desc *desc, const char *options) +static void serial8250_early_kick(struct rt_fdt_earlycon *con, int why) +{ + struct serial8250 *serial = raw_to_serial8250(con->data); + + switch (why) + { + case FDT_EARLYCON_KICK_UPDATE: + serial->base = rt_ioremap((void *)con->mmio, con->size); + break; + + case FDT_EARLYCON_KICK_COMPLETED: + rt_iounmap(serial->base); + break; + + default: + break; + } +} + +rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options) { rt_err_t ret = RT_EOK; - if (!serial->base && desc) + if (!serial->base && con) { serial8250_config(serial, options); - desc->mmio = (rt_ubase_t)serial->base; - desc->size = serial->size; + con->mmio = (rt_ubase_t)serial->base; + con->size = serial->size; } - if (serial->base && desc) + if (serial->base && con) { - serial->base = rt_ioremap((void *)serial->base, serial->size); + serial->base = rt_ioremap_early((void *)serial->base, serial->size); } - if (serial->base && desc) + if (serial->base && con) { - desc->console_putc = (typeof(desc->console_putc))&serial8250_early_putc; - desc->data = &serial->parent; + con->console_putc = (typeof(con->console_putc))&serial8250_early_putc; + con->console_kick = serial8250_early_kick; + con->data = &serial->parent; if (!serial->parent.config.baud_rate) { @@ -110,40 +123,40 @@ rt_err_t serial8250_early_of_setup(struct serial8250 *serial, struct rt_of_early return ret; } -static void common_init(struct serial8250 *serial, struct rt_of_earlycon_desc *desc) +static void common_init(struct serial8250 *serial, struct rt_fdt_earlycon *con) { - serial->base = (void *)desc->mmio; - serial->size = desc->size; + serial->base = (void *)con->mmio; + serial->size = con->size; serial->iotype = PORT_MMIO32; } -static rt_err_t common_early_setup(struct rt_of_earlycon_desc *desc, const char *options) +static rt_err_t common_early_setup(struct rt_fdt_earlycon *con, const char *options) { struct serial8250 *serial = &early_serial8250; - common_init(serial, desc); + common_init(serial, con); serial->regshift = 2; - fdt_getprop_u32(desc->fdt, desc->node_offset, "reg-shift", &serial->regshift, RT_NULL); + fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL); - return serial8250_early_of_setup(serial, desc, options); + return serial8250_early_fdt_setup(serial, con, options); } -RT_OF_EARLYCON_EXPORT(bcm2835aux, "uart8250", "brcm,bcm2835-aux-uart", common_early_setup); -RT_OF_EARLYCON_EXPORT(tegra20, "uart8250", "nvidia,tegra20-uart", common_early_setup); -RT_OF_EARLYCON_EXPORT(dw8250, "uart8250", "snps,dw-apb-uart", common_early_setup); -RT_OF_EARLYCON_EXPORT(ns16550a, "uart8250", "ns16550a", common_early_setup); -RT_OF_EARLYCON_EXPORT(ns16550, "uart8250", "ns16550", common_early_setup); +RT_FDT_EARLYCON_EXPORT(bcm2835aux, "uart8250", "brcm,bcm2835-aux-uart", common_early_setup); +RT_FDT_EARLYCON_EXPORT(tegra20, "uart8250", "nvidia,tegra20-uart", common_early_setup); +RT_FDT_EARLYCON_EXPORT(dw8250, "uart8250", "snps,dw-apb-uart", common_early_setup); +RT_FDT_EARLYCON_EXPORT(ns16550a, "uart8250", "ns16550a", common_early_setup); +RT_FDT_EARLYCON_EXPORT(ns16550, "uart8250", "ns16550", common_early_setup); #ifdef RT_USING_8250_OMAP -static rt_err_t omap8250_early_setup(struct rt_of_earlycon_desc *desc, const char *options) +static rt_err_t omap8250_early_setup(struct rt_fdt_earlycon *con, const char *options) { struct serial8250 *serial = &early_serial8250; - common_init(serial, desc); + common_init(serial, con); serial->regshift = 2; - return serial8250_early_of_setup(serial, desc, options); + return serial8250_early_fdt_setup(serial, con, options); } -OF_EARLYCON_DECLARE(omap8250, "uart8250", "ti,omap2-uart", omap8250_early_setup); -OF_EARLYCON_DECLARE(omap8250, "uart8250", "ti,omap3-uart", omap8250_early_setup); -OF_EARLYCON_DECLARE(omap8250, "uart8250", "ti,omap4-uart", omap8250_early_setup); +RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap2-uart", omap8250_early_setup); +RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap3-uart", omap8250_early_setup); +RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap4-uart", omap8250_early_setup); #endif /* RT_USING_8250_OMAP */ diff --git a/components/drivers/serial/serial_reg.h b/components/drivers/serial/8250/regs.h similarity index 99% rename from components/drivers/serial/serial_reg.h rename to components/drivers/serial/8250/regs.h index e47fbdf8fa92..6f05efe87ad5 100755 --- a/components/drivers/serial/serial_reg.h +++ b/components/drivers/serial/8250/regs.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __SERIAL_REG_H__ -#define __SERIAL_REG_H__ +#ifndef __SERIAL_8250_REGS_H__ +#define __SERIAL_8250_REGS_H__ /* * DLAB=0 @@ -103,8 +103,7 @@ #define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ /* - * Access to some registers depends on register access / configuration - * mode. + * Access to some registers depends on register access / configuration mode. */ #define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configutation mode A */ #define UART_LCR_CONF_MODE_B 0xBF /* Configutation mode B */ @@ -363,4 +362,4 @@ #define UART_ALTR_EN_TXFIFO_LW 0x01 /* Enable the TX FIFO Low Watermark */ #define UART_ALTR_TX_LOW 0x41 /* Tx FIFO Low Watermark */ -#endif /* __SERIAL_REG_H__ */ +#endif /* __SERIAL_8250_REGS_H__ */ diff --git a/components/drivers/serial/Kconfig b/components/drivers/serial/Kconfig index 70c9be1b00ca..40cff8c58573 100755 --- a/components/drivers/serial/Kconfig +++ b/components/drivers/serial/Kconfig @@ -28,3 +28,7 @@ config RT_SERIAL_PL011 depends on RT_USING_DM depends on RT_USING_SERIAL default n + +if RT_USING_DM && RT_USING_SERIAL +source "$RTT_DIR/components/drivers/serial/8250/Kconfig" +endif diff --git a/components/drivers/serial/SConscript b/components/drivers/serial/SConscript index 8f082642ffbd..3bce2afaa0fa 100644 --- a/components/drivers/serial/SConscript +++ b/components/drivers/serial/SConscript @@ -18,7 +18,7 @@ else: src += ['serial.c'] if GetDepend(['RT_USING_DM']): - src += ['serial_internal.c'] + src += ['serial_dm.c'] if GetDepend(['RT_SERIAL_PL011']): src += ['serial-pl011.c'] diff --git a/components/drivers/serial/serial-pl011.c b/components/drivers/serial/serial-pl011.c index 5220cd92d7df..4c0344405804 100755 --- a/components/drivers/serial/serial-pl011.c +++ b/components/drivers/serial/serial-pl011.c @@ -17,19 +17,19 @@ #include -#include "serial_internal.h" - -#define PL011_OEIM (1 << 10) /* overrun error interrupt mask */ -#define PL011_BEIM (1 << 9) /* break error interrupt mask */ -#define PL011_PEIM (1 << 8) /* parity error interrupt mask */ -#define PL011_FEIM (1 << 7) /* framing error interrupt mask */ -#define PL011_RTIM (1 << 6) /* receive timeout interrupt mask */ -#define PL011_TXIM (1 << 5) /* transmit interrupt mask */ -#define PL011_RXIM (1 << 4) /* receive interrupt mask */ -#define PL011_DSRMIM (1 << 3) /* DSR interrupt mask */ -#define PL011_DCDMIM (1 << 2) /* DCD interrupt mask */ -#define PL011_CTSMIM (1 << 1) /* CTS interrupt mask */ -#define PL011_RIMIM (1 << 0) /* RI interrupt mask */ +#include "serial_dm.h" + +#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 @@ -54,16 +54,16 @@ #define PL011_LCRH_WLEN(n) ((n - 5) << 5) -#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_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 { @@ -73,6 +73,7 @@ struct pl011 void *base; rt_ubase_t freq; struct rt_clk *clk; + struct rt_clk *pclk; struct rt_spinlock spinlock; }; @@ -202,7 +203,6 @@ static void pl011_early_kick(struct rt_fdt_earlycon *con, int why) switch (why) { case FDT_EARLYCON_KICK_UPDATE: - rt_iounmap_early(pl011->base, con->size); pl011->base = rt_ioremap((void *)con->mmio, con->size); break; @@ -220,11 +220,7 @@ static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *optio rt_err_t err = RT_EOK; static struct pl011 pl011 = { }; - if (!options && con->mmio) - { - con->size = 0x1000; - } - else + if (options && !con->mmio) { char *arg; @@ -249,6 +245,11 @@ static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *optio } } + if (!con->size) + { + con->size = 0x1000; + } + if (con->mmio) { pl011.base = rt_ioremap_early((void *)con->mmio, con->size); @@ -270,76 +271,100 @@ static rt_err_t pl011_early_setup(struct rt_fdt_earlycon *con, const char *optio } RT_FDT_EARLYCON_EXPORT(pl011, "pl011", "arm,pl011", pl011_early_setup); -static rt_err_t pl011_ofw_init(struct rt_platform_device *pdev, struct pl011 *pl011) +static rt_err_t pl011_probe(struct rt_platform_device *pdev) { - rt_err_t err = RT_EOK; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - pl011->base = rt_ofw_iomap(np, 0); + 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->base) + if (!pl011) { - pl011->clk = rt_ofw_get_clk(np, 0); - pl011->irq = rt_ofw_get_irq(np, 0); - - if (pl011->clk && pl011->irq >= 0) - { - rt_ofw_data(np) = &pl011->parent; - } - else - { - err = -RT_ERROR; - } + return -RT_ENOMEM; } - else + + pl011->base = rt_dm_dev_iomap(dev, 0); + + if (!pl011->base) { err = -RT_EIO; + + goto _fail; } - return err; -} + pl011->irq = rt_dm_dev_get_irq(dev, 0); -static rt_err_t pl011_probe(struct rt_platform_device *pdev) -{ - rt_err_t err = RT_EOK; - struct pl011 *pl011 = rt_calloc(1, sizeof(*pl011)); + if (pl011->irq < 0) + { + err = pl011->irq; - if (pl011) + goto _fail; + } + + pl011->clk = rt_clk_get_by_index(dev, 0); + + if (!pl011->clk) { - err = pl011_ofw_init(pdev, pl011); + err = -RT_EIO; + + goto _fail; } - else + + pl011->pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!pl011->pclk) { - err = -RT_ENOMEM; + err = -RT_EIO; + + goto _fail; } - if (!err) + if ((err = rt_clk_prepare_enable(pl011->pclk))) { - const char *name; - char isr_name[RT_NAME_MAX]; + goto _fail; + } + + rt_dm_dev_bind_fwdata(&pl011->parent.parent, dev->ofw_node, &pl011->parent); - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + rt_clk_enable(pl011->clk); + pl011->freq = rt_clk_get_rate(pl011->clk); - rt_clk_enable(pl011->clk); - pl011->freq = rt_clk_get_rate(pl011->clk); + pl011->parent.ops = &pl011_uart_ops; + pl011->parent.config = config; - pl011->parent.ops = &pl011_uart_ops; - pl011->parent.config = config; + rt_spin_lock_init(&pl011->spinlock); - rt_spin_lock_init(&pl011->spinlock); + serial_dev_set_name(&pl011->parent); + name = rt_dm_dev_get_name(&pl011->parent.parent); - serial_dev_set_name(&pl011->parent); - name = rt_dm_get_dev_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; - 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); +_fail: + if (pl011->base) + { + rt_iounmap(pl011->base); } - else + + if (pl011->clk) + { + rt_clk_disable(pl011->clk); + rt_clk_put(pl011->clk); + } + + if (pl011->pclk) { - rt_free(pl011); + rt_clk_disable_unprepare(pl011->pclk); + rt_clk_put(pl011->pclk); } + rt_free(pl011); + return err; } @@ -357,7 +382,7 @@ static struct rt_platform_driver pl011_driver = .probe = pl011_probe, }; -int pl011_drv_register(void) +static int pl011_drv_register(void) { rt_platform_driver_register(&pl011_driver); diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index 34d91f9a2156..8f70eb91fa92 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -635,6 +635,11 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) /* get open flags */ dev->open_flag = oflag & 0xff; +#ifdef RT_USING_PINCTRL + /* initialize iomux in DM */ + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); +#endif + /* initialize the Rx/Tx structure according to open flag */ if (serial->serial_rx == RT_NULL) { diff --git a/components/drivers/serial/serial_internal.c b/components/drivers/serial/serial_dm.c old mode 100755 new mode 100644 similarity index 92% rename from components/drivers/serial/serial_internal.c rename to components/drivers/serial/serial_dm.c index 1c7486ebc4c8..f5f344459393 --- a/components/drivers/serial/serial_internal.c +++ b/components/drivers/serial/serial_dm.c @@ -9,8 +9,7 @@ */ #include - -#include "serial_internal.h" +#include "serial_dm.h" int serial_dev_set_name(struct rt_serial_device *sdev) { @@ -21,7 +20,7 @@ int serial_dev_set_name(struct rt_serial_device *sdev) id = (int)rt_hw_atomic_add(&uid, 1); - return rt_dm_set_dev_name(&sdev->parent, "uart%u", id); + return rt_dm_dev_set_name(&sdev->parent, "uart%u", id); } void *serial_base_from_args(char *str) @@ -63,10 +62,6 @@ struct serial_configure serial_cfg_from_args(char *str) { rt_uint32_t baudrate = 0; - #ifdef RT_USING_OFW - *(str - 1) = RT_FDT_EARLYCON_OPTION_SIGNATURE; - #endif - /* BBBB is the speed */ while (*str && (*str >= '0' && *str <= '9')) { diff --git a/components/drivers/serial/serial_internal.h b/components/drivers/serial/serial_dm.h old mode 100755 new mode 100644 similarity index 66% rename from components/drivers/serial/serial_internal.h rename to components/drivers/serial/serial_dm.h index 9207604e83da..20792fc9eb3e --- a/components/drivers/serial/serial_internal.h +++ b/components/drivers/serial/serial_dm.h @@ -8,13 +8,12 @@ * 2022-11-16 GuEe-GUI first version */ -#ifndef __SERIAL_INTERNAL_H__ -#define __SERIAL_INTERNAL_H__ +#ifndef __SERIAL_DM_H__ +#define __SERIAL_DM_H__ #include #include - -#include "serial_reg.h" +#include int serial_dev_set_name(struct rt_serial_device *sdev); @@ -22,8 +21,9 @@ void *serial_base_from_args(char *str); struct serial_configure serial_cfg_from_args(char *str); #define serial_for_each_args(arg, args) \ - for (char *context = (arg = (typeof(arg))args, (void *)RT_NULL); \ - !!(arg = rt_strtok_r(arg, ",", &context)); \ - arg = (!*(arg - 1) ? (*(arg - 1) = ',') : RT_NULL, (typeof(arg))RT_NULL)) + for (char *context = (arg = (typeof(arg))args, (void *)RT_NULL), \ + *context_end = rt_strchrnul((char *)args, ' '); \ + (arg = strtok_r(arg, ",", &context)) && arg < context_end; \ + arg = RT_NULL) -#endif /* __SERIAL_INTERNAL_H__ */ +#endif /* __SERIAL_DM_H__ */ diff --git a/components/drivers/soc/Kconfig b/components/drivers/soc/Kconfig new file mode 100644 index 000000000000..c27fe6dfca3b --- /dev/null +++ b/components/drivers/soc/Kconfig @@ -0,0 +1,8 @@ +menuconfig RT_USING_SOC + bool "Using SOC (System On Chip) specific Drivers" + depends on RT_USING_DM + default n + +if RT_USING_SOC + source "$RTT_DIR/components/drivers/soc/rockchip/Kconfig" +endif diff --git a/components/drivers/soc/SConscript b/components/drivers/soc/SConscript new file mode 100644 index 000000000000..a9ea5eedfd90 --- /dev/null +++ b/components/drivers/soc/SConscript @@ -0,0 +1,23 @@ +from building import * + +group = [] +objs = [] + +if not GetDepend(['RT_USING_SOC']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = [] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + group + +Return('objs') diff --git a/components/drivers/soc/rockchip/Kconfig b/components/drivers/soc/rockchip/Kconfig new file mode 100644 index 000000000000..f3d77c76403d --- /dev/null +++ b/components/drivers/soc/rockchip/Kconfig @@ -0,0 +1,21 @@ +menuconfig RT_SOC_ROCKCHIP + bool "RockChip" + default n + +if RT_SOC_ROCKCHIP +config RT_SOC_ROCKCHIP_FIQ_DEBUGGER + bool "FIQ Debugger" + select RT_USING_OFW + default y + +config RT_SOC_ROCKCHIP_GRF + bool "Rockchip General Register Files support" + select RT_MFD_SYSCON + default y + +config RT_SOC_ROCKCHIP_IODOMAIN + bool "Rockchip IO domain support" + select RT_MFD_SYSCON + select RT_USING_REGULATOR + default y +endif diff --git a/components/drivers/soc/rockchip/SConscript b/components/drivers/soc/rockchip/SConscript new file mode 100644 index 000000000000..5935aeb5be62 --- /dev/null +++ b/components/drivers/soc/rockchip/SConscript @@ -0,0 +1,23 @@ +from building import * + +group = [] + +if not GetDepend(['RT_SOC_ROCKCHIP']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../include'] + +src = [] + +if GetDepend(['RT_SOC_ROCKCHIP_FIQ_DEBUGGER']): + src += ['fiq-debugger.c'] + +if GetDepend(['RT_SOC_ROCKCHIP_GRF']): + src += ['grf.c'] + +if GetDepend(['RT_SOC_ROCKCHIP_IODOMAIN']): + src += ['io-domain.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) +Return('group') diff --git a/components/drivers/soc/rockchip/fiq-debugger.c b/components/drivers/soc/rockchip/fiq-debugger.c new file mode 100644 index 000000000000..67ea174a9b8a --- /dev/null +++ b/components/drivers/soc/rockchip/fiq-debugger.c @@ -0,0 +1,370 @@ +/* + * 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 +#include + +#include "../../serial/8250/regs.h" +#include "../../serial/serial_dm.h" + +#define UART_USR 0x1f /* In: UART Status Register */ +#define UART_USR_RX_FIFO_FULL 0x10 /* Receive FIFO full */ +#define UART_USR_RX_FIFO_NOT_EMPTY 0x08 /* Receive FIFO not empty */ +#define UART_USR_TX_FIFO_EMPTY 0x04 /* Transmit FIFO empty */ +#define UART_USR_TX_FIFO_NOT_FULL 0x02 /* Transmit FIFO not full */ +#define UART_USR_BUSY 0x01 /* UART busy indicator */ +#define UART_SRR 0x22 /* software reset register */ + +#define FIQ_DEBUGGER_NO_CHAR -1 +#define FIQ_DEBUGGER_BREAK -2 + +struct rockchip_fiq_debugger +{ + struct rt_serial_device parent; + + int irq; + int baudrate; + void *debug_port_base; + rt_bool_t break_seen; +}; + +#define raw_to_fiq_debugger(raw) rt_container_of(raw, struct rockchip_fiq_debugger, parent) + +rt_inline void rockchip_fiq_write(struct rockchip_fiq_debugger *t, rt_uint32_t val, int off) +{ + HWREG32(t->debug_port_base + off * 4) = val; +} + +rt_inline rt_uint32_t rockchip_fiq_read(struct rockchip_fiq_debugger *t, int off) +{ + return HWREG32(t->debug_port_base + off * 4); +} + +rt_inline rt_uint32_t rockchip_fiq_read_lsr(struct rockchip_fiq_debugger *t) +{ + rt_uint32_t ret = rockchip_fiq_read(t, UART_LSR); + + if (ret & UART_LSR_BI) + { + t->break_seen = true; + } + + return ret; +} + +static void fiq_debugger_isr(int irqno, void *param) +{ + rt_uint32_t usr; + struct rt_serial_device *serial = (struct rt_serial_device*)param; + struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial); + + usr = rockchip_fiq_read(t, UART_USR); + + if ((usr & UART_USR_RX_FIFO_NOT_EMPTY) == UART_USR_RX_FIFO_NOT_EMPTY) + { + rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); + } + + if ((usr & UART_USR_BUSY) == UART_USR_BUSY) + { + /* Clear the USR */ + (void)rockchip_fiq_read(t, UART_USR); + } +} + +static rt_err_t fiq_debugger_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) +{ + int dll = 0, dlm = 0; + struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial); + + if (rockchip_fiq_read(t, UART_LSR) & UART_LSR_DR) + { + (void)rockchip_fiq_read(t, UART_RX); + } + + switch (t->baudrate) + { + case 1500000: + dll = 0x1; + break; + case 115200: + default: + dll = 0xd; + break; + } + /* reset uart */ + rockchip_fiq_write(t, (1 << 1) | (1 << 2), UART_SRR); + rt_hw_us_delay(10); + /* set uart to loop back mode */ + rockchip_fiq_write(t, 0x10, UART_MCR); + + rockchip_fiq_write(t, 0x83, UART_LCR); + /* set baud rate */ + rockchip_fiq_write(t, dll, UART_DLL); + rockchip_fiq_write(t, dlm, UART_DLM); + rockchip_fiq_write(t, 0x03, UART_LCR); + + /* enable rx interrupt */ + rockchip_fiq_write(t, UART_IER_RDI, UART_IER); + + /* + * interrupt on every character when received, but we can enable fifo for TX + * I found that if we enable the RX fifo, some problem may vanish such as + * when you continuously input characters in the command line the uart irq + * may be disable because of the uart irq is served when CPU is at IRQ + * exception, but it is found unregistered, so it is disable. + */ + rockchip_fiq_write(t, 0x01, UART_FCR); + + /* disbale loop back mode */ + rockchip_fiq_write(t, 0x0, UART_MCR); + + return RT_EOK; +} + +static rt_err_t fiq_debugger_uart_control(struct rt_serial_device *serial, int cmd, void *arg) +{ + struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + rt_hw_interrupt_mask(t->irq); + break; + + case RT_DEVICE_CTRL_SET_INT: + rt_hw_interrupt_umask(t->irq); + break; + } + + return RT_EOK; +} + +static int fiq_debugger_uart_putc(struct rt_serial_device *serial, char c) +{ + struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial); + rt_uint32_t count = 10000; + + while (!(rockchip_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && count--) + { + rt_hw_cpu_relax(); + } + + rockchip_fiq_write(t, c, UART_TX); + + return 1; +} + +static int fiq_debugger_uart_getc(struct rt_serial_device *serial) +{ + int ch = FIQ_DEBUGGER_NO_CHAR; + rt_uint32_t lsr, temp; + static rt_uint32_t n = 0; + static char buf[32] = {}; + struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial); + + /* Clear uart interrupt status */ + rockchip_fiq_read(t, UART_USR); + lsr = rockchip_fiq_read_lsr(t); + + if (lsr & UART_LSR_DR) + { + temp = rockchip_fiq_read(t, UART_RX); + buf[n & 0x1f] = temp; + n++; + + if (temp == 'q' && n > 2) + { + if ((buf[(n - 2) & 0x1f] == 'i') && (buf[(n - 3) & 0x1f] == 'f')) + { + ch = FIQ_DEBUGGER_BREAK; + } + else + { + ch = temp; + } + } + else + { + ch = temp; + } + } + + return ch; +} + +static const struct rt_uart_ops fiq_debugger_uart_ops = +{ + .configure = fiq_debugger_uart_configure, + .control = fiq_debugger_uart_control, + .putc = fiq_debugger_uart_putc, + .getc = fiq_debugger_uart_getc, +}; + +struct rockchip_fiq_debugger *rk_serial_debug_init(void *base, rt_ubase_t paddr, + int irq, int signal_irq, int wakeup_irq, rt_uint32_t baudrate) +{ + struct rockchip_fiq_debugger *t = rt_calloc(1, sizeof(*t)); + + if (t) + { + const char *name; + + t->parent.ops = &fiq_debugger_uart_ops; + t->parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT; + t->parent.config.baud_rate = baudrate; + t->irq = irq; + t->baudrate = baudrate; + t->debug_port_base = base; + t->break_seen = RT_FALSE; + + serial_dev_set_name(&t->parent); + name = rt_dm_dev_get_name(&t->parent.parent); + + rt_hw_serial_register(&t->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, t); + rt_hw_interrupt_install(t->irq, fiq_debugger_isr, &t->parent, name); + } + + return t; +} + +static rt_err_t rockchip_fiq_debugger_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + void *base; + rt_uint64_t regs[2]; + struct rt_clk *clk, *pclk; + rt_bool_t found = RT_FALSE; + char dev_name[RT_NAME_MAX]; + int irq, signal_irq = -1; + rt_uint32_t serial_id, baudrate = 0, irq_mode = 0, wake_irq = -1; + struct rt_ofw_node *np = pdev->parent.ofw_node; + + if (rt_ofw_prop_read_u32(np, "rockchip,serial-id", &serial_id) || serial_id == -1) + { + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "rockchip,irq-mode-enable", &irq_mode)) + { + irq_mode = -1; + } + + if (irq_mode == 1) + { + signal_irq = -1; + } + else if (!(signal_irq = rt_ofw_get_irq(np, 0))) + { + return -RT_EINVAL; + } + + if (rt_ofw_prop_read_u32(np, "rockchip,wake-irq", &wake_irq)) + { + wake_irq = -1; + } + + if (rt_ofw_prop_read_u32(np, "rockchip,baudrate", &baudrate)) + { + baudrate = 1500000; + } + + rt_snprintf(dev_name, RT_NAME_MAX, "serial%d", serial_id); + + np = RT_NULL; + + do { + np = rt_ofw_find_node_by_tag(np, "serial"); + + if (np && rt_ofw_get_alias_id(np, "serial") == serial_id) + { + found = RT_TRUE; + break; + } + } while(np); + + if (!found) + { + return -RT_EINVAL; + } + + rt_memset(regs, 0, sizeof(regs)); + rt_ofw_get_address_array(np, 1, regs); + + pclk = rt_ofw_get_clk_by_name(np, "apb_pclk"); + clk = rt_ofw_get_clk_by_name(np, "baudclk"); + + if (!pclk || !clk) + { + err = -RT_ERROR; + goto _fail; + } + + rt_clk_enable(clk); + rt_clk_enable(pclk); + + if ((irq = rt_ofw_get_irq(np, 0)) < 0) + { + err = -RT_ERROR; + goto _fail; + } + + if ((base = rt_ioremap((void *)regs[0], regs[1]))) + { + struct rockchip_fiq_debugger *t = rk_serial_debug_init(base, + (rt_ubase_t)regs[0], irq, signal_irq, wake_irq, baudrate); + + if (t) + { + rt_dm_dev_bind_fwdata(&t->parent.parent, pdev->parent.ofw_node, &t->parent); + } + } + + return err; + +_fail: + if (clk) + { + rt_clk_put(clk); + } + + if (pclk) + { + rt_clk_put(pclk); + } + + return err; +} + +static const struct rt_ofw_node_id rockchip_fiq_debugger_ofw_ids[] = +{ + { .type = "ttyFIQ", .compatible = "rockchip,fiq-debugger" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_fiq_debugger_driver = +{ + .name = "rockchip-fiq-debugger", + .ids = rockchip_fiq_debugger_ofw_ids, + + .probe = rockchip_fiq_debugger_probe, +}; + +static int rockchip_fiq_debugger_drv_register(void) +{ + rt_platform_driver_register(&rockchip_fiq_debugger_driver); + + return 0; +} +INIT_DRIVER_EARLY_EXPORT(rockchip_fiq_debugger_drv_register); diff --git a/components/drivers/soc/rockchip/grf.c b/components/drivers/soc/rockchip/grf.c new file mode 100644 index 000000000000..f8c0c62b06e6 --- /dev/null +++ b/components/drivers/soc/rockchip/grf.c @@ -0,0 +1,217 @@ +/* + * 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 "soc.rockchip.grf" +#define DBG_LVL DBG_INFO +#include + +#include "rockchip.h" + +struct rockchip_grf_value +{ + const char *desc; + rt_uint32_t reg; + rt_uint32_t val; +}; + +struct rockchip_grf_info +{ + const struct rockchip_grf_value *values; + int values_nr; +}; + +#define RK3036_GRF_SOC_CON0 0x140 + +static const struct rockchip_grf_value rk3036_defaults[] = +{ + /* + * Disable auto jtag/sdmmc switching that causes issues with the + * clock-framework and the mmc controllers making them unreliable. + */ + { "jtag switching", RK3036_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 11) }, +}; + +static const struct rockchip_grf_info rk3036_grf = +{ + .values = rk3036_defaults, + .values_nr = RT_ARRAY_SIZE(rk3036_defaults), +}; + +#define RK3128_GRF_SOC_CON0 0x140 + +static const struct rockchip_grf_value rk3128_defaults[] = +{ + { "jtag switching", RK3128_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 8) }, +}; + +static const struct rockchip_grf_info rk3128_grf = +{ + .values = rk3128_defaults, + .values_nr = RT_ARRAY_SIZE(rk3128_defaults), +}; + +#define RK3228_GRF_SOC_CON6 0x418 + +static const struct rockchip_grf_value rk3228_defaults[] = +{ + { "jtag switching", RK3228_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 8) }, +}; + +static const struct rockchip_grf_info rk3228_grf = +{ + .values = rk3228_defaults, + .values_nr = RT_ARRAY_SIZE(rk3228_defaults), +}; + +#define RK3288_GRF_SOC_CON0 0x244 +#define RK3288_GRF_SOC_CON2 0x24c + +static const struct rockchip_grf_value rk3288_defaults[] = +{ + { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) }, + { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) }, +}; + +static const struct rockchip_grf_info rk3288_grf = +{ + .values = rk3288_defaults, + .values_nr = RT_ARRAY_SIZE(rk3288_defaults), +}; + +#define RK3328_GRF_SOC_CON4 0x410 + +static const struct rockchip_grf_value rk3328_defaults[] = +{ + { "jtag switching", RK3328_GRF_SOC_CON4, HIWORD_UPDATE(0, 1, 12) }, +}; + +static const struct rockchip_grf_info rk3328_grf = +{ + .values = rk3328_defaults, + .values_nr = RT_ARRAY_SIZE(rk3328_defaults), +}; + +#define RK3368_GRF_SOC_CON15 0x43c + +static const struct rockchip_grf_value rk3368_defaults[] = +{ + { "jtag switching", RK3368_GRF_SOC_CON15, HIWORD_UPDATE(0, 1, 13) }, +}; + +static const struct rockchip_grf_info rk3368_grf = +{ + .values = rk3368_defaults, + .values_nr = RT_ARRAY_SIZE(rk3368_defaults), +}; + +#define RK3399_GRF_SOC_CON7 0xe21c + +static const struct rockchip_grf_value rk3399_defaults[] = +{ + { "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) }, +}; + +static const struct rockchip_grf_info rk3399_grf = +{ + .values = rk3399_defaults, + .values_nr = RT_ARRAY_SIZE(rk3399_defaults), +}; + +#define RK3566_GRF_USB3OTG0_CON1 0x0104 + +static const struct rockchip_grf_value rk3566_defaults[] = +{ + { "usb3otg port switch", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(0, 1, 12) }, + { "usb3otg clock switch", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(1, 1, 7) }, + { "usb3otg disable usb3", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(1, 1, 0) }, +}; + +static const struct rockchip_grf_info rk3566_pipegrf = +{ + .values = rk3566_defaults, + .values_nr = RT_ARRAY_SIZE(rk3566_defaults), +}; + +#define RK3588_GRF_SOC_CON6 0x0318 + +static const struct rockchip_grf_value rk3588_defaults[] = +{ + { "jtag switching", RK3588_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 14) }, +}; + +static const struct rockchip_grf_info rk3588_sysgrf = +{ + .values = rk3588_defaults, + .values_nr = RT_ARRAY_SIZE(rk3588_defaults), +}; + +static rt_err_t rockchip_grf_probe(struct rt_platform_device *pdev) +{ + struct rt_syscon *grf; + struct rt_ofw_node *np = pdev->parent.ofw_node; + const struct rockchip_grf_info *grf_info = pdev->id->data; + + grf = rt_syscon_find_by_ofw_node(np); + + if (!grf) + { + return -RT_EINVAL; + } + + for (int i = 0; i < grf_info->values_nr; ++i) + { + rt_err_t err; + const struct rockchip_grf_value *val = &grf_info->values[i]; + + err = rt_syscon_write(grf, val->reg, val->val); + LOG_D("%s: adjusting %6x to %10x", val->desc, val->reg, val->val); + + if (err) + { + LOG_E("%s: write %6x to %10x fail", val->desc, val->reg, val->val); + } + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id rockchip_grf_ofw_ids[] = +{ + { .compatible = "rockchip,rk3036-grf", .data = &rk3036_grf, }, + { .compatible = "rockchip,rk3128-grf", .data = &rk3128_grf, }, + { .compatible = "rockchip,rk3228-grf", .data = &rk3228_grf, }, + { .compatible = "rockchip,rk3288-grf", .data = &rk3288_grf, }, + { .compatible = "rockchip,rk3328-grf", .data = &rk3328_grf, }, + { .compatible = "rockchip,rk3368-grf", .data = &rk3368_grf, }, + { .compatible = "rockchip,rk3399-grf", .data = &rk3399_grf, }, + { .compatible = "rockchip,rk3566-pipe-grf", .data = &rk3566_pipegrf, }, + { .compatible = "rockchip,rk3588-sys-grf", .data = &rk3588_sysgrf, }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_grf_driver = +{ + .name = "rockchip-grf", + .ids = rockchip_grf_ofw_ids, + + .probe = rockchip_grf_probe, +}; + +static int rockchip_grf_drv_register(void) +{ + rt_platform_driver_register(&rockchip_grf_driver); + + return 0; +} +INIT_FRAMEWORK_EXPORT(rockchip_grf_drv_register); diff --git a/components/drivers/soc/rockchip/io-domain.c b/components/drivers/soc/rockchip/io-domain.c new file mode 100644 index 000000000000..93b8246b0b96 --- /dev/null +++ b/components/drivers/soc/rockchip/io-domain.c @@ -0,0 +1,677 @@ +/* + * 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 "soc.rockchip.io-domain" +#define DBG_LVL DBG_INFO +#include + +#define MAX_SUPPLIES 16 + +/* + * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under + * "Recommended Operating Conditions" for "Digital GPIO". When the typical + * is 3.3V the max is 3.6V. When the typical is 1.8V the max is 1.98V. + * + * They are used like this: + * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the + * SoC we're at 3.3. + * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider + * that to be an error. + */ +#define MAX_VOLTAGE_1_8 1980000 +#define MAX_VOLTAGE_3_3 3600000 + +struct rockchip_iodomain; + +struct rockchip_iodomain_supply +{ + struct rockchip_iodomain *domain; + struct rt_regulator *reg; + struct rt_regulator_notifier notifier; + int idx; +}; + +struct rockchip_iodomain_soc_data +{ + int grf_offset; + const char *supply_names[MAX_SUPPLIES]; + void (*init)(struct rockchip_iodomain *domain); + rt_err_t (*write)(struct rockchip_iodomain_supply *supply, int uvolt); +}; + +struct rockchip_iodomain +{ + struct rt_device *dev; + struct rt_syscon *grf; + const struct rockchip_iodomain_soc_data *soc_data; + struct rockchip_iodomain_supply supplies[MAX_SUPPLIES]; + + rt_err_t (*write)(struct rockchip_iodomain_supply *supply, int uvolt); +}; + +#define PX30_IO_VSEL 0x180 +#define PX30_IO_VSEL_VCCIO6_SRC RT_BIT(0) +#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1 + +static void px30_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no VCCIO6 supply we should leave things alone */ + if (!domain->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg) + { + return; + } + + /* set vccio6 iodomain to also use this framework instead of a special gpio. */ + val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16); + + if (rt_syscon_write(domain->grf, PX30_IO_VSEL, val) < 0) + { + LOG_W("Couldn't update %s ctrl", "vccio6"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_px30 = +{ + .grf_offset = 0x180, + .supply_names = + { + [1] = + "vccio6", + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + "vccio-oscgpi", + }, + .init = px30_iodomain_init, +}; + +static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = +{ + .grf_offset = 0x100, + .supply_names = + { + [14] = + "pmuio1", + "pmuio2", + }, +}; + +/* + * On the rk3188 the io-domains are handled by a shared register with the lower + * 8 bits being still being continuing drive-strength settings. + */ +static const struct rockchip_iodomain_soc_data soc_data_rk3188 = +{ + .grf_offset = 0x104, + .supply_names = + { + [8] = + "ap0", + "ap1", + "cif", + "flash", + "vccio0", + "vccio1", + "lcdc0", + "lcdc1", + }, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3228 = +{ + .grf_offset = 0x418, + .supply_names = + { + "vccio1", + "vccio2", + "vccio3", + "vccio4", + }, +}; + +#define RK3288_SOC_CON2 0x24c +#define RK3288_SOC_CON2_FLASH0 RT_BIT(7) +#define RK3288_SOC_FLASH_SUPPLY_NUM 2 + +static void rk3288_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no flash supply we should leave things alone */ + if (!domain->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg) + { + return; + } + + /* set flash0 iodomain to also use this framework instead of a special gpio. */ + val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16); + + if (rt_syscon_write(domain->grf, RK3288_SOC_CON2, val) < 0) + { + LOG_W("Couldn't update %s ctrl", "flash0"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3288 = +{ + .grf_offset = 0x380, + .supply_names = + { + "lcdc", /* LCDC_VDD */ + "dvp", /* DVPIO_VDD */ + "flash0", /* FLASH0_VDD (emmc) */ + "flash1", /* FLASH1_VDD (sdio1) */ + "wifi", /* APIO3_VDD (sdio0) */ + "bb", /* APIO5_VDD */ + "audio", /* APIO4_VDD */ + "sdcard", /* SDMMC0_VDD (sdmmc) */ + "gpio30", /* APIO1_VDD */ + "gpio1830", /* APIO2_VDD */ + }, + .init = rk3288_iodomain_init, +}; + +#define RK3308_SOC_CON0 0x300 +#define RK3308_SOC_CON0_VCCIO3 RT_BIT(8) +#define RK3308_SOC_VCCIO3_SUPPLY_NUM 3 + +static void rk3308_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no vccio3 supply we should leave things alone */ + if (!domain->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg) + { + return; + } + + /* set vccio3 iodomain to also use this framework instead of a special gpio. */ + val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16); + + if (rt_syscon_write(domain->grf, RK3308_SOC_CON0, val) < 0) + { + LOG_W("Couldn't update %s ctrl", "vccio3"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3308 = +{ + .grf_offset = 0x300, + .supply_names = + { + "vccio0", + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + }, + .init = rk3308_iodomain_init, +}; + +#define RK3328_SOC_CON4 0x410 +#define RK3328_SOC_CON4_VCCIO2 RT_BIT(7) +#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1 + +static void rk3328_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no vccio2 supply we should leave things alone */ + if (!domain->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg) + { + return; + } + + /* set vccio2 iodomain to also use this framework instead of a special gpio. */ + val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16); + + if (rt_syscon_write(domain->grf, RK3328_SOC_CON4, val) < 0) + { + LOG_W("Couldn't update %s ctrl", "vccio2 vsel"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3328 = +{ + .grf_offset = 0x410, + .supply_names = + { + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + "vccio6", + "pmuio", + }, + .init = rk3328_iodomain_init, +}; + +#define RK3368_SOC_CON15 0x43c +#define RK3368_SOC_CON15_FLASH0 RT_BIT(14) +#define RK3368_SOC_FLASH_SUPPLY_NUM 2 + +static void rk3368_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no flash supply we should leave things alone */ + if (!domain->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg) + { + return; + } + + /* set flash0 iodomain to also use this framework instead of a special gpio. */ + val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16); + + if (rt_syscon_write(domain->grf, RK3368_SOC_CON15, val) < 0) + { + LOG_W("Couldn't update %s ctrl", "flash0"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3368 = +{ + .grf_offset = 0x900, + .supply_names = + { + RT_NULL, /* Reserved */ + "dvp", /* DVPIO_VDD */ + "flash0", /* FLASH0_VDD (emmc) */ + "wifi", /* APIO2_VDD (sdio0) */ + RT_NULL, + "audio", /* APIO3_VDD */ + "sdcard", /* SDMMC0_VDD (sdmmc) */ + "gpio30", /* APIO1_VDD */ + "gpio1830", /* APIO4_VDD (gpujtag) */ + }, + .init = rk3368_iodomain_init, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = +{ + .grf_offset = 0x100, + .supply_names = + { + [4] = + "pmu", /* PMU IO domain*/ + "vop", /* LCDC IO domain*/ + }, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3399 = +{ + .grf_offset = 0xe640, + .supply_names = + { + "bt656", /* APIO2_VDD */ + "audio", /* APIO5_VDD */ + "sdmmc", /* SDMMC0_VDD */ + "gpio1830", /* APIO4_VDD */ + }, +}; + +#define RK3399_PMUGRF_CON0 0x180 +#define RK3399_PMUGRF_CON0_VSEL RT_BIT(8) +#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9 + +static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *domain) +{ + rt_uint32_t val; + + /* if no pmu io supply we should leave things alone */ + if (!domain->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg) + { + return; + } + + /* set pmu io iodomain to also use this framework instead of a special gpio. */ + val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16); + + if (rt_syscon_write(domain->grf, RK3399_PMUGRF_CON0, val) < 0) + { + LOG_W("couldn't update %s ctrl", "pmu io iodomain"); + } +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = +{ + .grf_offset = 0x180, + .supply_names = + { + [9] = + "pmu1830", /* PMUIO2_VDD */ + }, + .init = rk3399_pmu_iodomain_init, +}; + +#define RK3568_PMU_GRF_IO_VSEL0 0x0140 +#define RK3568_PMU_GRF_IO_VSEL1 0x0144 +#define RK3568_PMU_GRF_IO_VSEL2 0x0148 + +static rt_err_t rk3568_iodomain_write(struct rockchip_iodomain_supply *supply, int uvolt) +{ + rt_uint32_t bit, is_3v3 = uvolt > MAX_VOLTAGE_1_8, val0, val1; + struct rockchip_iodomain *domain = supply->domain; + + switch (supply->idx) + { + case 0: /* pmuio1 */ + break; + + case 1: /* pmuio2 */ + bit = supply->idx; + val0 = RT_BIT(16 + bit) | (is_3v3 ? 0 : RT_BIT(bit)); + bit = supply->idx + 4; + val1 = RT_BIT(16 + bit) | (is_3v3 ? RT_BIT(bit) : 0); + + rt_syscon_write(domain->grf, RK3568_PMU_GRF_IO_VSEL2, val0); + rt_syscon_write(domain->grf, RK3568_PMU_GRF_IO_VSEL2, val1); + break; + + case 3: /* vccio2 */ + break; + + case 2: /* vccio1 */ + case 4: /* vccio3 */ + case 5: /* vccio4 */ + case 6: /* vccio5 */ + case 7: /* vccio6 */ + case 8: /* vccio7 */ + bit = supply->idx - 1; + val0 = RT_BIT(16 + bit) | (is_3v3 ? 0 : RT_BIT(bit)); + val1 = RT_BIT(16 + bit) | (is_3v3 ? RT_BIT(bit) : 0); + + rt_syscon_write(domain->grf, RK3568_PMU_GRF_IO_VSEL0, val0); + rt_syscon_write(domain->grf, RK3568_PMU_GRF_IO_VSEL1, val1); + break; + + default: + return -RT_EINVAL; + } + + return 0; +} + +static const struct rockchip_iodomain_soc_data soc_data_rk3568_pmu = +{ + .grf_offset = 0x140, + .supply_names = + { + "pmuio1", + "pmuio2", + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + "vccio6", + "vccio7", + }, + .write = rk3568_iodomain_write, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rv1108 = +{ + .grf_offset = 0x404, + .supply_names = + { + [11] = + "vccio1", + "vccio2", + "vccio3", + "vccio5", + "vccio6", + }, + +}; + +static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = +{ + .grf_offset = 0x104, + .supply_names = + { + "pmu", + }, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rv1126_pmu = +{ + .grf_offset = 0x140, + .supply_names = + { + [1] = + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + "vccio6", + "vccio7", + "pmuio0", + "pmuio1", + }, +}; + +static rt_err_t rockchip_iodomain_write(struct rockchip_iodomain_supply *supply, int uvolt) +{ + rt_err_t err; + rt_uint32_t val; + struct rockchip_iodomain *domain = supply->domain; + + /* set value bit */ + val = (uvolt > MAX_VOLTAGE_1_8) ? 0 : 1; + val <<= supply->idx; + /* apply hiword-mask */ + val |= (RT_BIT(supply->idx) << 16); + + if ((err = rt_syscon_write(domain->grf, domain->soc_data->grf_offset, val))) + { + LOG_E("Couldn't write to GRF"); + } + + return err; +} + +static rt_err_t rockchip_iodomain_notify(struct rt_regulator_notifier *notifier, + rt_ubase_t msg, void *data) +{ + int uvolt; + rt_err_t err; + struct rockchip_iodomain_supply *supply; + + supply = rt_container_of(notifier, struct rockchip_iodomain_supply, notifier); + + if (msg == RT_REGULATOR_MSG_VOLTAGE_CHANGE) + { + union rt_regulator_notifier_args *args = data; + + uvolt = rt_max(args->old_uvolt, args->max_uvolt); + } + else if (msg == RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR) + { + uvolt = (int)(rt_base_t)data; + } + + if (uvolt > MAX_VOLTAGE_3_3) + { + LOG_E("Voltage too high: %d", uvolt); + + if (msg == RT_REGULATOR_MSG_VOLTAGE_CHANGE) + { + return -RT_EIO; + } + } + + err = supply->domain->write(supply, uvolt); + + if (err && msg == RT_REGULATOR_MSG_VOLTAGE_CHANGE) + { + return -RT_EIO; + } + + LOG_D("Setting to %d done", uvolt); + + return err; +} + +static rt_err_t rockchip_iodomain_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + struct rt_ofw_node *np, *grf_np; + struct rockchip_iodomain *domain = rt_calloc(1, sizeof(*domain)); + + if (!domain) + { + return -RT_ENOMEM; + } + + domain->dev = &pdev->parent; + domain->soc_data = pdev->id->data; + domain->write = domain->soc_data->write ? : rockchip_iodomain_write; + + np = pdev->parent.ofw_node; + + if ((grf_np = rt_ofw_get_parent(np))) + { + domain->grf = rt_syscon_find_by_ofw_node(grf_np); + rt_ofw_node_put(grf_np); + } + else + { + domain->grf = rt_syscon_find_by_ofw_phandle(np, "rockchip,grf"); + } + + if (!domain->grf) + { + err = -RT_EIO; + + goto _fail; + } + + for (int i = 0; i < MAX_SUPPLIES; ++i) + { + int uvolt; + struct rt_regulator *reg; + struct rockchip_iodomain_supply *supply; + const char *supply_name = domain->soc_data->supply_names[i]; + + if (!supply_name) + { + continue; + } + + supply = &domain->supplies[i]; + reg = rt_regulator_get_optional(domain->dev, supply_name); + + if (!reg) + { + continue; + } + + uvolt = rt_regulator_get_voltage(reg); + + if (uvolt < 0) + { + LOG_E("Can't determine voltage: %s", supply_name); + + goto _fail; + } + + if (uvolt > MAX_VOLTAGE_3_3) + { + LOG_E("Voltage too high: %d", uvolt); + + goto _fail; + } + + supply->idx = i; + supply->domain = domain; + supply->reg = reg; + supply->notifier.callback = rockchip_iodomain_notify; + + if (domain->write(supply, uvolt)) + { + rt_regulator_put(supply->reg); + supply->reg = RT_NULL; + + goto _fail; + } + + if ((err = rt_regulator_notifier_register(supply->reg, &supply->notifier))) + { + rt_regulator_put(supply->reg); + supply->reg = RT_NULL; + + goto _fail; + } + } + + if (domain->soc_data->init) + { + domain->soc_data->init(domain); + } + + return RT_EOK; + +_fail: + for (int i = MAX_SUPPLIES - 1; i >= 0; --i) + { + struct rockchip_iodomain_supply *supply = &domain->supplies[i]; + + if (supply->reg) + { + rt_regulator_notifier_unregister(supply->reg, &supply->notifier); + rt_regulator_put(supply->reg); + } + } + + rt_free(domain); + + return err; +} + +static const struct rt_ofw_node_id rockchip_iodomain_ofw_ids[] = +{ + { .compatible = "rockchip,px30-io-voltage-domain", .data = &soc_data_px30 }, + { .compatible = "rockchip,px30-pmu-io-voltage-domain", .data = &soc_data_px30_pmu }, + { .compatible = "rockchip,rk3188-io-voltage-domain", .data = &soc_data_rk3188 }, + { .compatible = "rockchip,rk3228-io-voltage-domain", .data = &soc_data_rk3228 }, + { .compatible = "rockchip,rk3288-io-voltage-domain", .data = &soc_data_rk3288 }, + { .compatible = "rockchip,rk3308-io-voltage-domain", .data = &soc_data_rk3308 }, + { .compatible = "rockchip,rk3328-io-voltage-domain", .data = &soc_data_rk3328 }, + { .compatible = "rockchip,rk3368-io-voltage-domain", .data = &soc_data_rk3368 }, + { .compatible = "rockchip,rk3368-pmu-io-voltage-domain", .data = &soc_data_rk3368_pmu }, + { .compatible = "rockchip,rk3399-io-voltage-domain", .data = &soc_data_rk3399 }, + { .compatible = "rockchip,rk3399-pmu-io-voltage-domain", .data = &soc_data_rk3399_pmu }, + { .compatible = "rockchip,rk3568-pmu-io-voltage-domain", .data = &soc_data_rk3568_pmu }, + { .compatible = "rockchip,rv1108-io-voltage-domain", .data = &soc_data_rv1108 }, + { .compatible = "rockchip,rv1108-pmu-io-voltage-domain", .data = &soc_data_rv1108_pmu }, + { .compatible = "rockchip,rv1126-pmu-io-voltage-domain", .data = &soc_data_rv1126_pmu }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_iodomain_driver = +{ + .name = "rockchip-iodomain", + .ids = rockchip_iodomain_ofw_ids, + + .probe = rockchip_iodomain_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_iodomain_driver); diff --git a/components/drivers/soc/rockchip/rockchip.h b/components/drivers/soc/rockchip/rockchip.h new file mode 100644 index 000000000000..c9a61dbf60dd --- /dev/null +++ b/components/drivers/soc/rockchip/rockchip.h @@ -0,0 +1,22 @@ +/* + * 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 + */ + +#ifndef __ROCKCHIP_H__ +#define __ROCKCHIP_H__ + +#include + +#define rk_clrsetreg(addr, clr, set) HWREG32(addr) = (((clr) | (set)) << 16 | (set)) +#define rk_clrreg(addr, clr) HWREG32(addr) = ((clr) << 16) +#define rk_setreg(addr, set) HWREG32(addr) = ((set) << 16 | (set)) + +#define HIWORD_UPDATE(val, mask, shift) ((val) << (shift) | (mask) << ((shift) + 16)) + +#endif /* __ROCKCHIP_H__ */ \ No newline at end of file diff --git a/components/drivers/spi/Kconfig b/components/drivers/spi/Kconfig new file mode 100755 index 000000000000..08746004cc3f --- /dev/null +++ b/components/drivers/spi/Kconfig @@ -0,0 +1,75 @@ +menuconfig RT_USING_SPI + bool "Using SPI Bus/Device device drivers" + default n + + if RT_USING_SPI + config RT_USING_SPI_BITOPS + select RT_USING_PIN + bool "Use GPIO to simulate SPI" + default n + + if RT_USING_SPI_BITOPS + config RT_SPI_BITOPS_DEBUG + bool "Use simulate SPI debug message" + default n + endif + + config RT_USING_QSPI + bool "Enable QSPI mode" + default n + + config RT_USING_SPI_MSD + bool "Using SD/TF card driver with spi" + select RT_USING_DFS + default n + + config RT_USING_SFUD + bool "Using Serial Flash Universal Driver" + default n + help + An using JEDEC's SFDP standard serial (SPI) flash universal driver library + + if RT_USING_SFUD + config RT_SFUD_USING_SFDP + bool "Using auto probe flash JEDEC SFDP parameter" + default y + + config RT_SFUD_USING_FLASH_INFO_TABLE + bool "Using defined supported flash chip information table" + default y + + config RT_SFUD_USING_QSPI + bool "Using QSPI mode support" + select RT_USING_QSPI + default n + + config RT_SFUD_SPI_MAX_HZ + int "Default spi maximum speed(HZ)" + range 0 50000000 + default 50000000 + help + Read the JEDEC SFDP command must run at 50 MHz or less,and you also can use rt_spi_configure(); to config spi speed. + + config RT_DEBUG_SFUD + bool "Show more SFUD debug information" + default n + endif + + config RT_USING_ENC28J60 + bool "Using ENC28J60 SPI Ethernet network interface" + select RT_USING_LWIP + default n + + config RT_USING_SPI_WIFI + bool "Using RW009/007 SPI Wi-Fi wireless interface" + select RT_USING_LWIP + default n + endif + +config RT_SPI_ROCKCHIP + bool "Rockchip SPI controller driver" + depends on RT_USING_DM + depends on RT_USING_SPI + select RT_USING_PIN + select RT_USING_PINCTRL + default n diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index 27b7a8dd71fe..431c9ee0cb04 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -34,6 +34,12 @@ if GetDepend('RT_USING_SFUD'): elif rtconfig.PLATFORM in ['armcc']: LOCAL_CFLAGS += ' --c99' +if GetDepend('RT_USING_DM'): + src += ['spi_dm.c', 'spi_bus.c'] + + if GetDepend('RT_SPI_ROCKCHIP'): + src += ['spi-rockchip.c'] + src += src_device group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH, LOCAL_CFLAGS = LOCAL_CFLAGS) diff --git a/components/drivers/spi/spi-rockchip.c b/components/drivers/spi/spi-rockchip.c new file mode 100644 index 000000000000..e6f08339a38e --- /dev/null +++ b/components/drivers/spi/spi-rockchip.c @@ -0,0 +1,945 @@ +/* + * 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 "spi_dm.h" + +#define DBG_TAG "spi.rockchip" +#define DBG_LVL DBG_INFO +#include + +#include + +#define ROCKCHIP_SPI_CLR_BITS(reg, bits) HWREG32(reg) = HWREG32(reg) & ~(bits) +#define ROCKCHIP_SPI_SET_BITS(reg, bits) HWREG32(reg) = HWREG32(reg) | (bits) + +/* SPI register offsets */ +#define ROCKCHIP_SPI_CTRLR0 0x0000 +#define ROCKCHIP_SPI_CTRLR1 0x0004 +#define ROCKCHIP_SPI_SSIENR 0x0008 +#define ROCKCHIP_SPI_SER 0x000c +#define ROCKCHIP_SPI_BAUDR 0x0010 +#define ROCKCHIP_SPI_TXFTLR 0x0014 +#define ROCKCHIP_SPI_RXFTLR 0x0018 +#define ROCKCHIP_SPI_TXFLR 0x001c +#define ROCKCHIP_SPI_RXFLR 0x0020 +#define ROCKCHIP_SPI_SR 0x0024 +#define ROCKCHIP_SPI_IPR 0x0028 +#define ROCKCHIP_SPI_IMR 0x002c +#define ROCKCHIP_SPI_ISR 0x0030 +#define ROCKCHIP_SPI_RISR 0x0034 +#define ROCKCHIP_SPI_ICR 0x0038 +#define ROCKCHIP_SPI_DMACR 0x003c +#define ROCKCHIP_SPI_DMATDLR 0x0040 +#define ROCKCHIP_SPI_DMARDLR 0x0044 +#define ROCKCHIP_SPI_VERSION 0x0048 +#define ROCKCHIP_SPI_TXDR 0x0400 +#define ROCKCHIP_SPI_RXDR 0x0800 + +/* Bit fields in CTRLR0 */ +#define CR0_DFS_OFFSET 0 +#define CR0_DFS_4BIT 0x0 +#define CR0_DFS_8BIT 0x1 +#define CR0_DFS_16BIT 0x2 + +#define CR0_CFS_OFFSET 2 + +#define CR0_SCPH_OFFSET 6 + +#define CR0_SCPOL_OFFSET 7 + +#define CR0_CSM_OFFSET 8 +#define CR0_CSM_KEEP 0x0 +/* ss_n be high for half sclk_out cycles */ +#define CR0_CSM_HALF 0X1 +/* ss_n be high for one sclk_out cycle */ +#define CR0_CSM_ONE 0x2 + +/* ss_n to sclk_out delay */ +#define CR0_SSD_OFFSET 10 +/* + * The period between ss_n active and + * sclk_out active is half sclk_out cycles + */ +#define CR0_SSD_HALF 0x0 +/* + * The period between ss_n active and + * sclk_out active is one sclk_out cycle + */ +#define CR0_SSD_ONE 0x1 + +#define CR0_EM_OFFSET 11 +#define CR0_EM_LITTLE 0x0 +#define CR0_EM_BIG 0x1 + +#define CR0_FBM_OFFSET 12 +#define CR0_FBM_MSB 0x0 +#define CR0_FBM_LSB 0x1 + +#define CR0_BHT_OFFSET 13 +#define CR0_BHT_16BIT 0x0 +#define CR0_BHT_8BIT 0x1 + +#define CR0_RSD_OFFSET 14 +#define CR0_RSD_MAX 0x3 + +#define CR0_FRF_OFFSET 16 +#define CR0_FRF_SPI 0x0 +#define CR0_FRF_SSP 0x1 +#define CR0_FRF_MICROWIRE 0x2 + +#define CR0_XFM_OFFSET 18 +#define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET) +#define CR0_XFM_TR 0x0 +#define CR0_XFM_TO 0x1 +#define CR0_XFM_RO 0x2 + +#define CR0_OPM_OFFSET 20 +#define CR0_OPM_MASTER 0x0 +#define CR0_OPM_SLAVE 0x1 + +#define CR0_SOI_OFFSET 23 + +#define CR0_MTM_OFFSET 0x21 + +/* Bit fields in SER, 2bit */ +#define SER_MASK 0x3 + +/* Bit fields in BAUDR */ +#define BAUDR_SCKDV_MIN 2 +#define BAUDR_SCKDV_MAX 65534 + +/* Bit fields in SR, 6bit */ +#define SR_MASK 0x3f +#define SR_BUSY (1 << 0) +#define SR_TF_FULL (1 << 1) +#define SR_TF_EMPTY (1 << 2) +#define SR_RF_EMPTY (1 << 3) +#define SR_RF_FULL (1 << 4) +#define SR_SLAVE_TX_BUSY (1 << 5) + +/* Bit fields in ISR, IMR, ISR, RISR, 5bit */ +#define INT_MASK 0x1f +#define INT_TF_EMPTY (1 << 0) +#define INT_TF_OVERFLOW (1 << 1) +#define INT_RF_UNDERFLOW (1 << 2) +#define INT_RF_OVERFLOW (1 << 3) +#define INT_RF_FULL (1 << 4) +#define INT_CS_INACTIVE (1 << 6) + +/* Bit fields in ICR, 4bit */ +#define ICR_MASK 0x0f +#define ICR_ALL (1 << 0) +#define ICR_RF_UNDERFLOW (1 << 1) +#define ICR_RF_OVERFLOW (1 << 2) +#define ICR_TF_OVERFLOW (1 << 3) + +/* Bit fields in DMACR */ +#define RF_DMA_EN (1 << 0) +#define TF_DMA_EN (1 << 1) + +/* Driver state flags */ +#define RXDMA (1 << 0) +#define TXDMA (1 << 1) + +/* sclk_out: spi master internal logic in rk3x can support 50Mhz */ +#define MAX_SCLK_OUT 50000000U + +/* + * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However, + * the controller seems to hang when given 0x10000, so stick with this for now. + */ +#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff + +/* 2 for native cs, 2 for cs-gpio */ +#define ROCKCHIP_SPI_MAX_CS_NUM 4 +#define ROCKCHIP_SPI_VER2_TYPE1 0x05ec0002 +#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 + +#define ROCKCHIP_AUTOSUSPEND_TIMEOUT 2000 +#define ROCKCHIP_SPI_TX_IDLE_TIMEOUT 20 + +struct rockchip_spi +{ + struct rt_spi_bus parent; + + struct rt_clk *spiclk; + struct rt_clk *apb_pclk; + + int irq; + void *regs; + void *dma_addr_rx; + void *dma_addr_tx; + + const void *tx; + void *rx; + rt_uint32_t tx_left; + rt_uint32_t rx_left; + + /* DMA state */ + rt_atomic_t state; + + /* depth of the FIFO buffer */ + rt_uint32_t fifo_len; + /* frequency of spiclk */ + rt_uint32_t freq; + + rt_uint8_t n_bytes; + rt_uint8_t rsd; + + rt_bool_t cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; + + rt_bool_t slave_abort; + rt_bool_t cs_inactive; /* spi slave tansmition stop when cs inactive */ + rt_bool_t cs_high_supported; /* native CS supports active-high polarity */ + + struct rt_spi_message *xfer; + + struct rt_completion done; +}; + +#define raw_to_rockchip_spi(raw) rt_container_of(raw, struct rockchip_spi, parent) + +rt_inline rt_uint32_t rockchip_spi_readl(struct rockchip_spi *rk_spi, int offset) +{ + return HWREG32(rk_spi->regs + offset); +} + +rt_inline void rockchip_spi_writel(struct rockchip_spi *rk_spi, int offset, rt_uint32_t value) +{ + HWREG32(rk_spi->regs + offset) = value; +} + +rt_inline void spi_enable_chip(struct rockchip_spi *rk_spi, rt_bool_t enable) +{ + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_SSIENR, !!enable); +} + +rt_inline void wait_for_tx_idle(struct rockchip_spi *rk_spi, rt_bool_t slave_mode) +{ + rt_tick_t timeout = rt_tick_get() + ROCKCHIP_SPI_TX_IDLE_TIMEOUT; + + do { + if (slave_mode) + { + if (!(rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) && + !((rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_SR) & SR_BUSY))) + { + return; + } + } + else + { + if (!(rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_SR) & SR_BUSY)) + { + return; + } + } + } while (timeout > rt_tick_get()); + + LOG_W("Wait TX timeout"); +} + +static rt_uint32_t get_fifo_len(struct rockchip_spi *rk_spi) +{ + rt_uint32_t ver = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_VERSION); + + switch (ver) + { + case ROCKCHIP_SPI_VER2_TYPE1: + case ROCKCHIP_SPI_VER2_TYPE2: + return 64; + + default: + return 32; + } +} + +static void rockchip_spi_set_cs(struct rt_spi_device *spi_dev, rt_bool_t enable) +{ + struct rt_spi_bus *spi_bus = spi_dev->bus; + struct rockchip_spi *rk_spi = raw_to_rockchip_spi(spi_bus); + rt_bool_t cs_asserted = spi_dev->config.mode & RT_SPI_CS_HIGH ? enable : !enable; + + /* Return immediately for no-op */ + if (cs_asserted == rk_spi->cs_asserted[spi_dev->chip_select]) + { + return; + } + + if (cs_asserted) + { + if (spi_dev->cs_pin != PIN_NONE) + { + ROCKCHIP_SPI_SET_BITS(rk_spi->regs + ROCKCHIP_SPI_SER, 1); + } + else + { + ROCKCHIP_SPI_SET_BITS(rk_spi->regs + ROCKCHIP_SPI_SER, + RT_BIT(spi_dev->chip_select)); + } + } + else + { + if (spi_dev->cs_pin != PIN_NONE) + { + ROCKCHIP_SPI_CLR_BITS(rk_spi->regs + ROCKCHIP_SPI_SER, 1); + } + else + { + ROCKCHIP_SPI_CLR_BITS(rk_spi->regs + ROCKCHIP_SPI_SER, + RT_BIT(spi_dev->chip_select)); + } + } + + rk_spi->cs_asserted[spi_dev->chip_select] = cs_asserted; +} + +static void rockchip_spi_pio_writer(struct rockchip_spi *rk_spi) +{ + rt_uint32_t tx_free, words; + + tx_free = rk_spi->fifo_len - rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_TXFLR); + words = rt_min(rk_spi->tx_left, tx_free); + + rk_spi->tx_left -= words; + + for (; words; --words) + { + rt_uint32_t txw; + + if (rk_spi->n_bytes == 1) + { + txw = *(rt_uint8_t *)rk_spi->tx; + } + else + { + txw = *(rt_uint16_t *)rk_spi->tx; + } + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_TXDR, txw); + rk_spi->tx += rk_spi->n_bytes; + } +} + +static void rockchip_spi_slave_abort(struct rockchip_spi *rk_spi) +{ + rt_uint32_t rx_fifo_left; + + if (rk_spi->rx) + { + rx_fifo_left = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_RXFLR); + + for (; rx_fifo_left; --rx_fifo_left) + { + rt_uint32_t rxw = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_RXDR); + + if (rk_spi->n_bytes == 1) + { + *(rt_uint8_t *)rk_spi->rx = (rt_uint8_t)rxw; + } + else + { + *(rt_uint16_t *)rk_spi->rx = (rt_uint16_t)rxw; + } + + rk_spi->rx += rk_spi->n_bytes; + } + + rk_spi->xfer->length = (rt_uint32_t)(rk_spi->rx - rk_spi->xfer->recv_buf); + } +} + +static void rockchip_spi_pio_reader(struct rockchip_spi *rk_spi) +{ + rt_uint32_t words, rx_left; + + words = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_RXFLR); + rx_left = (rk_spi->rx_left > words) ? rk_spi->rx_left - words : 0; + + /* + * the hardware doesn't allow us to change fifo threshold + * level while spi is enabled, so instead make sure to leave + * enough words in the rx fifo to get the last interrupt + * exactly when all words have been received + */ + if (rx_left) + { + rt_uint32_t ftl = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_RXFTLR) + 1; + + if (rx_left < ftl) + { + rx_left = ftl; + words = rk_spi->rx_left - rx_left; + } + } + + rk_spi->rx_left = rx_left; + + for (; words; --words) + { + rt_uint32_t rxw = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_RXDR); + + if (!rk_spi->rx) + { + continue; + } + + if (rk_spi->n_bytes == 1) + { + *(rt_uint8_t *)rk_spi->rx = (rt_uint8_t)rxw; + } + else + { + *(rt_uint16_t *)rk_spi->rx = (rt_uint16_t)rxw; + } + + rk_spi->rx += rk_spi->n_bytes; + } +} + +static rt_ssize_t rockchip_spi_prepare_irq(struct rockchip_spi *rk_spi, + struct rt_spi_message *xfer) +{ + int cs_flags = 0; + + rk_spi->tx = xfer->send_buf; + rk_spi->rx = xfer->recv_buf; + rk_spi->tx_left = rk_spi->tx ? xfer->length / rk_spi->n_bytes : 0; + rk_spi->rx_left = xfer->length / rk_spi->n_bytes; + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_ICR, 0xffffffff); + + spi_enable_chip(rk_spi, true); + + if (rk_spi->tx_left) + { + rockchip_spi_pio_writer(rk_spi); + } + + if (rk_spi->cs_inactive) + { + cs_flags |= INT_CS_INACTIVE; + } + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_IMR, INT_RF_FULL | cs_flags); + + /* 1 means the transfer is in progress */ + return xfer->length; +} + +static rt_uint32_t rockchip_spi_calc_burst_size(rt_uint32_t data_len) +{ + rt_uint32_t i; + + /* burst size: 1, 2, 4, 8 */ + for (i = 1; i < 8; i <<= 1) + { + if (data_len & i) + { + break; + } + } + + return i; +} + +static int rockchip_spi_xfer_bits_per_word(struct rt_spi_device *spi_dev, + struct rt_spi_message *xfer) +{ + int tx_bits_per_word, rx_bits_per_word; + struct rt_spi_configuration *conf = &spi_dev->config; + + tx_bits_per_word = rx_bits_per_word = (int)(RT_UINT32_MAX >> 1); + + if (xfer->send_buf) + { + if (conf->data_width_tx <= 8) + { + tx_bits_per_word = 8; + } + else if (conf->data_width_tx <= 16) + { + tx_bits_per_word = 16; + } + } + if (xfer->recv_buf) + { + if (conf->data_width_rx <= 8) + { + rx_bits_per_word = 8; + } + else if (conf->data_width_rx <= 16) + { + rx_bits_per_word = 16; + } + } + + return rt_min(tx_bits_per_word, rx_bits_per_word); +} + +static int rockchip_spi_config(struct rockchip_spi *rk_spi, + struct rt_spi_device *spi_dev, struct rt_spi_message *xfer, + rt_bool_t use_dma, rt_bool_t slave_mode) +{ + rt_uint32_t cr0, cr1, dmacr = 0, rxftlr; + struct rt_spi_configuration *conf = &spi_dev->config; + + cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET | CR0_BHT_8BIT << CR0_BHT_OFFSET + | CR0_SSD_ONE << CR0_SSD_OFFSET | CR0_EM_BIG << CR0_EM_OFFSET; + + if (slave_mode) + { + cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET; + } + + cr0 |= rk_spi->rsd << CR0_RSD_OFFSET; + cr0 |= (conf->mode & RT_SPI_MODE_MASK) << CR0_SCPH_OFFSET; + if (conf->mode & RT_SPI_MSB) + { + cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; + } + if (conf->mode & RT_SPI_CS_HIGH) + { + cr0 |= RT_BIT(spi_dev->chip_select) << CR0_SOI_OFFSET; + } + + if (xfer->recv_buf && xfer->send_buf) + { + cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET; + } + else if (xfer->recv_buf) + { + cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET; + } + else if (use_dma) + { + cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET; + } + + switch (rockchip_spi_xfer_bits_per_word(spi_dev, xfer)) + { + case 4: + cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET; + cr1 = xfer->length - 1; + break; + + case 8: + cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET; + cr1 = xfer->length - 1; + break; + + case 16: + cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET; + cr1 = xfer->length / 2 - 1; + break; + + default: + return -RT_EINVAL; + } + + if (use_dma) + { + if (xfer->send_buf) + { + dmacr |= TF_DMA_EN; + } + if (xfer->recv_buf) + { + dmacr |= RF_DMA_EN; + } + } + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_CTRLR0, cr0); + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_CTRLR1, cr1); + + /* + * unfortunately setting the fifo threshold level to generate an + * interrupt exactly when the fifo is full doesn't seem to work, + * so we need the strict inequality here + */ + if ((xfer->length / rk_spi->n_bytes) < rk_spi->fifo_len) + { + rxftlr = xfer->length / rk_spi->n_bytes - 1; + } + else + { + rxftlr = rk_spi->fifo_len / 2 - 1; + } + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_RXFTLR, rxftlr); + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_DMATDLR, rk_spi->fifo_len / 2 - 1); + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_DMARDLR, + rockchip_spi_calc_burst_size(xfer->length / rk_spi->n_bytes) - 1); + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_DMACR, dmacr); + + /* + * the hardware only supports an even clock divisor, so + * round divisor = spiclk / speed up to nearest even number + * so that the resulting speed is <= the requested speed + */ + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_BAUDR, + 2 * RT_DIV_ROUND_UP(rk_spi->freq, 2 * conf->max_hz)); + + return 0; +} + +static rt_err_t rockchip_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *conf) +{ + rt_uint32_t cr0; + rt_uint8_t chip_select = device->chip_select; + struct rockchip_spi *rk_spi = raw_to_rockchip_spi(device->bus); + + if (!conf->max_hz || + (!rk_spi->parent.pins && (conf->mode & RT_SPI_CS_HIGH) && rk_spi->cs_high_supported)) + { + return -RT_EINVAL; + } + + cr0 = rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_CTRLR0); + cr0 &= ~(0x3 << CR0_SCPH_OFFSET); + cr0 |= ((conf->mode & 0x3) << CR0_SCPH_OFFSET); + + if (conf->mode & RT_SPI_CS_HIGH && chip_select <= 1) + { + cr0 |= RT_BIT(chip_select) << CR0_SOI_OFFSET; + } + else if (chip_select <= 1) + { + cr0 &= ~(RT_BIT(chip_select) << CR0_SOI_OFFSET); + } + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_CTRLR0, cr0); + + return RT_EOK; +} + +static rt_ssize_t rockchip_spi_xfer(struct rt_spi_device *device, + struct rt_spi_message *xfer) +{ + rt_err_t err; + rt_ssize_t res; + rt_bool_t use_dma = RT_FALSE; + struct rt_spi_bus *spi_bus = device->bus; + struct rockchip_spi *rk_spi = raw_to_rockchip_spi(spi_bus); + + if (!xfer->length) + { + rt_completion_done(&rk_spi->done); + + return rk_spi->xfer ? rk_spi->xfer->length : 1; + } + + if (!xfer->send_buf && !xfer->recv_buf) + { + if (xfer->cs_take) + { + rockchip_spi_set_cs(device, RT_TRUE); + } + + if (xfer->cs_release) + { + rockchip_spi_set_cs(device, RT_FALSE); + } + + return RT_EOK; + } + + if (xfer->length > ROCKCHIP_SPI_MAX_TRANLEN) + { + LOG_E("Transfer is too long = %u", xfer->length); + + return -RT_EINVAL; + } + + rk_spi->n_bytes = rockchip_spi_xfer_bits_per_word(device, xfer) <= 8 ? 1 : 2; + rk_spi->xfer = xfer; + + err = rockchip_spi_config(rk_spi, device, xfer, use_dma, spi_bus->slave); + if (err) + { + return err; + } + + res = rockchip_spi_prepare_irq(rk_spi, xfer); + + if (!spi_bus->slave) + { + rt_uint32_t timeout, div; + + if (xfer->cs_take) + { + rockchip_spi_set_cs(device, RT_TRUE); + } + + div = RT_DIV_ROUND_UP(rk_spi->freq, device->config.max_hz); + div = (div + 1) & 0xfffe; + timeout = xfer->length * 8 * 1000 / (rk_spi->freq / div) + 100; + + err = rt_completion_wait(&rk_spi->done, rt_tick_from_millisecond(timeout)); + + if (err) + { + res = err; + } + + if (xfer->cs_release) + { + rockchip_spi_set_cs(device, RT_FALSE); + } + + if (xfer->send_buf && !err) + { + wait_for_tx_idle(rk_spi, spi_bus->slave); + } + } + else + { + rt_completion_wait(&rk_spi->done, RT_WAITING_FOREVER); + + if (xfer->send_buf) + { + wait_for_tx_idle(rk_spi, spi_bus->slave); + } + } + + return res; +} + +static struct rt_spi_ops rockchip_spi_ops = +{ + .configure = rockchip_spi_configure, + .xfer = rockchip_spi_xfer, +}; + +static void rockchip_spi_isr(int irqno, void *param) +{ + struct rockchip_spi *rk_spi = param; + + /* When int_cs_inactive comes, spi slave abort */ + if (rk_spi->cs_inactive && + rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + { + rockchip_spi_slave_abort(rk_spi); + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_IMR, 0); + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_ICR, 0xffffffff); + + return; + } + + if (rk_spi->tx_left) + { + rockchip_spi_pio_writer(rk_spi); + } + + rockchip_spi_pio_reader(rk_spi); + + if (!rk_spi->rx_left) + { + spi_enable_chip(rk_spi, RT_FALSE); + + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_IMR, 0); + rockchip_spi_writel(rk_spi, ROCKCHIP_SPI_ICR, 0xffffffff); + + rt_completion_done(&rk_spi->done); + } +} + +static rt_err_t rockchip_spi_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t nsecs; + rt_bool_t slave_mode; + const char *bus_name; + struct rt_device *dev = &pdev->parent; + struct rockchip_spi *rk_spi = rt_calloc(1, sizeof(*rk_spi)); + + if (!rk_spi) + { + return -RT_ENOMEM; + } + + rk_spi->regs = rt_dm_dev_iomap(dev, 0); + + if (!rk_spi->regs) + { + err = -RT_EIO; + + goto _fail; + } + + rk_spi->irq = rt_dm_dev_get_irq(dev, 0); + + if (rk_spi->irq < 0) + { + err = rk_spi->irq; + + goto _fail; + } + + rk_spi->apb_pclk = rt_clk_get_by_name(dev, "apb_pclk"); + + if (!rk_spi->apb_pclk) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rk_spi->apb_pclk))) + { + goto _fail; + } + + rk_spi->spiclk = rt_clk_get_by_name(dev, "spiclk"); + + if (!rk_spi->spiclk) + { + err = -RT_EIO; + + goto _fail; + } + + if ((err = rt_clk_prepare_enable(rk_spi->spiclk))) + { + goto _fail; + } + + rk_spi->freq = rt_clk_get_rate(rk_spi->spiclk); + + spi_enable_chip(rk_spi, RT_FALSE); + + slave_mode = rt_dm_dev_prop_read_bool(dev, "spi-slave"); + + if (!rt_dm_dev_prop_read_u32(dev, "rx-sample-delay-ns", &nsecs)) + { + /* rx sample delay is expressed in parent clock cycles (max 3) */ + rt_uint32_t rsd = RT_DIV_ROUND_CLOSEST(nsecs * (rk_spi->freq >> 8), + 1000000000 >> 8); + + if (!rsd) + { + LOG_W("%u Hz are too slow to express %u ns delay", rk_spi->freq, nsecs); + } + else if (rsd > CR0_RSD_MAX) + { + rsd = CR0_RSD_MAX; + LOG_W("%u Hz are too fast to express %u ns delay, clamping at %u ns", + rk_spi->freq, nsecs, CR0_RSD_MAX * 1000000000U / rk_spi->freq); + } + + rk_spi->rsd = rsd; + } + + rk_spi->fifo_len = get_fifo_len(rk_spi); + + if (!rk_spi->fifo_len) + { + LOG_E("Failed to get fifo length"); + err = -RT_EINVAL; + + goto _fail; + } + + + if (!slave_mode) + { + rt_uint32_t num_cs = 1; + + rt_dm_dev_prop_read_u32(dev, "num-cs", &num_cs); + + rk_spi->parent.num_chipselect = num_cs; + } + + /* DMA configure */ + { + void *spi_regs_phy = rt_kmem_v2p(rk_spi->regs); + + rk_spi->dma_addr_rx = spi_regs_phy + ROCKCHIP_SPI_TXDR; + rk_spi->dma_addr_tx = spi_regs_phy + ROCKCHIP_SPI_RXDR; + } + + switch (rockchip_spi_readl(rk_spi, ROCKCHIP_SPI_VERSION)) + { + case ROCKCHIP_SPI_VER2_TYPE2: + rk_spi->cs_high_supported = RT_TRUE; + rk_spi->parent.mode |= RT_SPI_CS_HIGH; + /* If support DMA and slave_mode, it will TRUE */ + rk_spi->cs_inactive = RT_FALSE; + break; + + default: + rk_spi->cs_inactive = RT_FALSE; + break; + } + + rt_pin_ctrl_confs_apply_by_name(dev, RT_NULL); + + rk_spi->parent.parent.ofw_node = dev->ofw_node; + + rt_dm_dev_set_name_auto(&rk_spi->parent.parent, "spi"); + bus_name = rt_dm_dev_get_name(&rk_spi->parent.parent); + + rt_hw_interrupt_install(rk_spi->irq, rockchip_spi_isr, rk_spi, bus_name); + rt_hw_interrupt_umask(rk_spi->irq); + + if ((err = rt_spi_bus_register(&rk_spi->parent, bus_name, &rockchip_spi_ops))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rk_spi->regs) + { + rt_iounmap(rk_spi->regs); + } + if (rk_spi->apb_pclk) + { + rt_clk_disable_unprepare(rk_spi->apb_pclk); + rt_clk_put(rk_spi->apb_pclk); + } + if (rk_spi->spiclk) + { + rt_clk_disable_unprepare(rk_spi->spiclk); + rt_clk_put(rk_spi->spiclk); + } + rt_free(rk_spi); + + return err; +} + +static const struct rt_ofw_node_id rockchip_spi_ofw_ids[] = +{ + { .compatible = "rockchip,px30-spi", }, + { .compatible = "rockchip,rk3036-spi", }, + { .compatible = "rockchip,rk3066-spi", }, + { .compatible = "rockchip,rk3188-spi", }, + { .compatible = "rockchip,rk3228-spi", }, + { .compatible = "rockchip,rk3288-spi", }, + { .compatible = "rockchip,rk3308-spi", }, + { .compatible = "rockchip,rk3328-spi", }, + { .compatible = "rockchip,rk3368-spi", }, + { .compatible = "rockchip,rk3399-spi", }, + { .compatible = "rockchip,rv1108-spi", }, + { .compatible = "rockchip,rv1126-spi", }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rockchip_spi_driver = +{ + .name = "rockchip-spi", + .ids = rockchip_spi_ofw_ids, + + .probe = rockchip_spi_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(rockchip_spi_driver); diff --git a/components/drivers/spi/spi_bus.c b/components/drivers/spi/spi_bus.c new file mode 100644 index 000000000000..327b45f4a964 --- /dev/null +++ b/components/drivers/spi/spi_bus.c @@ -0,0 +1,161 @@ +/* + * 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 "spi_dm.h" + +#define DBG_TAG "spi.bus" +#define DBG_LVL DBG_INFO +#include + +static struct rt_bus spi_bus; + +void spi_bus_scan_devices(struct rt_spi_bus *bus) +{ +#ifdef RT_USING_OFW + if (bus->parent.ofw_node) + { + struct rt_ofw_node *np = bus->parent.ofw_node, *spi_dev_np; + + rt_ofw_foreach_available_child_node(np, spi_dev_np) + { + rt_uint64_t reg_offset; + struct rt_spi_device *spi_dev; + + if (!rt_ofw_prop_read_bool(spi_dev_np, "compatible")) + { + continue; + } + + spi_dev = rt_calloc(1, sizeof(*spi_dev)); + + if (!spi_dev) + { + LOG_E("Not memory to create spi device: %s", + rt_ofw_node_full_name(spi_dev_np)); + + return; + } + + rt_ofw_get_address(spi_dev_np, 0, ®_offset, RT_NULL); + + spi_dev->parent.ofw_node = spi_dev_np; + spi_dev->name = rt_ofw_node_name(spi_dev_np); + spi_dev->bus = bus; + + if (spi_device_ofw_parse(spi_dev)) + { + continue; + } + + rt_spi_device_register(spi_dev); + } + } +#endif /* RT_USING_OFW */ +} + +rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver) +{ + RT_ASSERT(driver != RT_NULL); + + driver->parent.bus = &spi_bus; + + return rt_driver_register(&driver->parent); +} + +rt_err_t rt_spi_device_register(struct rt_spi_device *device) +{ + RT_ASSERT(device != RT_NULL); + + return rt_bus_add_device(&spi_bus, &device->parent); +} + +static rt_bool_t spi_match(rt_driver_t drv, rt_device_t dev) +{ + const struct rt_spi_device_id *id; + struct rt_spi_driver *driver = rt_container_of(drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if ((id = driver->ids)) + { + for (; id->name[0]; ++id) + { + if (!rt_strcmp(id->name, device->name)) + { + device->id = id; + device->ofw_id = RT_NULL; + + return RT_TRUE; + } + } + } + +#ifdef RT_USING_OFW + device->ofw_id = rt_ofw_node_match(device->parent.ofw_node, driver->ofw_ids); + + if (device->ofw_id) + { + device->id = RT_NULL; + + return RT_TRUE; + } +#endif + + return RT_FALSE; +} + +static rt_err_t spi_probe(rt_device_t dev) +{ + rt_err_t err; + struct rt_spi_bus *bus; + struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if (!device->bus) + { + return -RT_EINVAL; + } + + err = driver->probe(device); + + if (err) + { + return err; + } + + bus = device->bus; + + if (bus->pins) + { + device->cs_pin = bus->pins[device->chip_select]; + + rt_pin_mode(device->cs_pin, PIN_MODE_OUTPUT); + } + else + { + device->cs_pin = PIN_NONE; + } + + return err; +} + +static struct rt_bus spi_bus = +{ + .name = "spi", + .match = spi_match, + .probe = spi_probe, +}; + +static int spi_bus_init(void) +{ + rt_bus_register(&spi_bus); + + return 0; +} +INIT_CORE_EXPORT(spi_bus_init); diff --git a/components/drivers/spi/spi_core.c b/components/drivers/spi/spi_core.c index 9cff697b321f..9e3a2f215b21 100644 --- a/components/drivers/spi/spi_core.c +++ b/components/drivers/spi/spi_core.c @@ -19,6 +19,10 @@ #define DBG_LVL DBG_INFO #include +#ifdef RT_USING_DM +#include "spi_dm.h" +#endif + extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name); extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name); @@ -41,6 +45,40 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, /* set bus mode */ bus->mode = RT_SPI_BUS_MODE_SPI; +#ifdef RT_USING_DM + if (!bus->slave) + { + int pin_count = rt_pin_get_named_pin_count(&bus->parent, "cs"); + + if (pin_count >= 0) + { + pin_count = rt_max_t(int, pin_count, bus->num_chipselect); + bus->pins = rt_malloc(sizeof(bus->pins[0]) * pin_count); + + if (!bus->pins) + { + return -RT_ENOMEM; + } + + for (int i = 0; i < pin_count; ++i) + { + bus->pins[i] = rt_pin_get_named_pin(&bus->parent, "cs", i, + RT_NULL, RT_NULL); + } + } + else + { + result = pin_count; + + LOG_E("CS PIN find error = %s", rt_strerror(result)); + + return result; + } + } + + spi_bus_scan_devices(bus); +#endif + return RT_EOK; } diff --git a/components/drivers/spi/spi_dm.c b/components/drivers/spi/spi_dm.c new file mode 100644 index 000000000000..0a54082d0315 --- /dev/null +++ b/components/drivers/spi/spi_dm.c @@ -0,0 +1,106 @@ +/* + * 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 "spi_dm.h" + +#define DBG_TAG "spi.dm" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_OFW +static void ofw_parse_delay(struct rt_ofw_node *np, struct rt_spi_delay *delay, + const char *prop) +{ + rt_uint32_t value; + + if (!rt_ofw_prop_read_u32(np, prop, &value)) + { + if (value > RT_UINT16_MAX) + { + delay->value = RT_DIV_ROUND_UP(value, 1000); + delay->unit = RT_SPI_DELAY_UNIT_USECS; + } + else + { + delay->value = value; + delay->unit = RT_SPI_DELAY_UNIT_NSECS; + } + } +} + +rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev) +{ + rt_err_t err; + rt_uint32_t value; + struct rt_spi_bus *spi_bus = spi_dev->bus; + struct rt_ofw_node *np = spi_dev->parent.ofw_node; + struct rt_spi_configuration *conf = &spi_dev->config; + + if (rt_ofw_prop_read_bool(np, "spi-cpha")) + { + conf->mode |= RT_SPI_CPHA; + } + if (rt_ofw_prop_read_bool(np, "spi-cpol")) + { + conf->mode |= RT_SPI_CPOL; + } + if (rt_ofw_prop_read_bool(np, "spi-3wire")) + { + conf->mode |= RT_SPI_3WIRE; + } + if (rt_ofw_prop_read_bool(np, "spi-lsb-first")) + { + conf->mode |= RT_SPI_LSB; + } + if (rt_ofw_prop_read_bool(np, "spi-cs-high")) + { + conf->mode |= RT_SPI_CS_HIGH; + } + + value = 1; + rt_ofw_prop_read_u32(np, "spi-tx-bus-width", &value); + conf->data_width_tx = value; + + value = 1; + rt_ofw_prop_read_u32(np, "spi-rx-bus-width", &value); + conf->data_width_rx = value; + + if (spi_bus->slave) + { + if (!rt_ofw_node_tag_equ(np, "slave")) + { + LOG_E("Invalid SPI device = %s", rt_ofw_node_full_name(np)); + + return -RT_EINVAL; + } + + return RT_EOK; + } + + if ((err = rt_ofw_prop_read_u32(np, "reg", &value))) + { + LOG_E("Find 'reg' failed"); + + return err; + } + spi_dev->chip_select = value; + + if (!rt_ofw_prop_read_u32(np, "spi-max-frequency", &value)) + { + conf->max_hz = value; + } + + ofw_parse_delay(np, &spi_dev->cs_setup, "spi-cs-setup-delay-ns"); + ofw_parse_delay(np, &spi_dev->cs_hold, "spi-cs-hold-delay-ns"); + ofw_parse_delay(np, &spi_dev->cs_inactive, "spi-cs-inactive-delay-ns"); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/spi/spi_dm.h b/components/drivers/spi/spi_dm.h new file mode 100644 index 000000000000..61a007ec9e36 --- /dev/null +++ b/components/drivers/spi/spi_dm.h @@ -0,0 +1,29 @@ +/* + * 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 __SPI_DM_H__ +#define __SPI_DM_H__ + +#include +#include +#include + +#ifdef RT_USING_OFW +rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev); +#else +rt_inline rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +void spi_bus_scan_devices(struct rt_spi_bus *bus); + +#endif /* __SPI_DM_H__ */ diff --git a/components/drivers/virtio/Kconfig b/components/drivers/virtio/Kconfig index 0f7d0ad5ea0d..9466bd577866 100755 --- a/components/drivers/virtio/Kconfig +++ b/components/drivers/virtio/Kconfig @@ -3,10 +3,22 @@ menuconfig RT_USING_VIRTIO depends on RT_USING_DM default n +config RT_VIRTIO_TRANSPORT_MMIO + bool "Using VirtIO MMIO transport" + depends on RT_USING_VIRTIO + select RT_USING_OFW + default y + +config RT_VIRTIO_TRANSPORT_PCI + bool "Using VirtIO PCI transport" + depends on RT_USING_VIRTIO + select RT_USING_PCI + default y + config RT_VIRTIO_NET bool "VirtIO Net" - select RT_USING_LWIP depends on RT_USING_VIRTIO + select RT_USING_LWIP default y config RT_VIRTIO_BLK @@ -21,9 +33,9 @@ config RT_VIRTIO_CONSOLE config RT_VIRTIO_RNG bool "VirtIO RNG" + depends on RT_USING_VIRTIO select RT_USING_HWCRYPTO select RT_HWCRYPTO_USING_RNG - depends on RT_USING_VIRTIO default y config RT_VIRTIO_GPU diff --git a/components/drivers/virtio/SConscript b/components/drivers/virtio/SConscript index 18ea6d0b5ecc..ba8ed321ec2e 100644 --- a/components/drivers/virtio/SConscript +++ b/components/drivers/virtio/SConscript @@ -10,9 +10,12 @@ CPPPATH = [cwd + '/../include'] src = ['virtio.c', 'virtio_queue.c'] -if GetDepend(['RT_USING_OFW']): +if GetDepend(['RT_VIRTIO_TRANSPORT_MMIO']): src += ['virtio_mmio.c'] +if GetDepend(['RT_VIRTIO_TRANSPORT_PCI']): + src += ['virtio_pci.c', 'virtio_pci_legacy.c', 'virtio_pci_modern.c'] + if GetDepend(['RT_VIRTIO_NET']): src += ['virtio-net.c'] diff --git a/components/drivers/virtio/virtio-blk.c b/components/drivers/virtio/virtio-blk.c index f484f60144bb..02dcfaa3f56c 100644 --- a/components/drivers/virtio/virtio-blk.c +++ b/components/drivers/virtio/virtio-blk.c @@ -213,7 +213,7 @@ static rt_err_t virtio_blk_vq_init(struct virtio_blk *vblk) { vqs_nr = 1; - LOG_W("%s-%s not support %s", rt_dm_get_dev_name(&vblk->vdev->parent), "blk", "VIRTIO_BLK_F_MQ"); + LOG_W("%s-%s not support %s", rt_dm_dev_get_name(&vblk->vdev->parent), "blk", "VIRTIO_BLK_F_MQ"); } vblk->virtq_nr = rt_min(RT_CPUS_NR, 1024) * VIRTIO_BLK_REQUEST_SPLIT_NR; @@ -275,12 +275,12 @@ static rt_err_t virtio_blk_probe(struct rt_virtio_device *vdev) goto _fail; } - if ((err = rt_dm_set_dev_name_auto(&vblk->parent, "block")) < 0) + if ((err = rt_dm_dev_set_name_auto(&vblk->parent, "block")) < 0) { goto _fail; } - if ((err = rt_device_register(&vblk->parent, rt_dm_get_dev_name(&vblk->parent), RT_DEVICE_FLAG_RDWR))) + if ((err = rt_device_register(&vblk->parent, rt_dm_dev_get_name(&vblk->parent), RT_DEVICE_FLAG_RDWR))) { goto _fail; } diff --git a/components/drivers/virtio/virtio-console.c b/components/drivers/virtio/virtio-console.c index f65c4dd98f1f..756cea9efd25 100644 --- a/components/drivers/virtio/virtio-console.c +++ b/components/drivers/virtio/virtio-console.c @@ -180,16 +180,16 @@ static rt_err_t virtio_console_probe(struct rt_virtio_device *vdev) rt_list_init(&vconsole->port_nodes); - if ((err = rt_dm_set_dev_name_auto(&vport->parent, "vport")) < 0) + if ((err = rt_dm_dev_set_name_auto(&vport->parent, "vport")) < 0) { goto _fail; } - vconsole->uid = rt_dm_get_dev_name_id(&vport->parent); + vconsole->uid = rt_dm_dev_get_name_id(&vport->parent); - rt_dm_set_dev_name(&vport->parent, "%s%dp%d", "vport", vconsole->uid, 0); + rt_dm_dev_set_name(&vport->parent, "%s%dp%d", "vport", vconsole->uid, 0); - if ((err = rt_device_register(&vport->parent, rt_dm_get_dev_name(&vport->parent), + if ((err = rt_device_register(&vport->parent, rt_dm_dev_get_name(&vport->parent), RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_REMOVABLE))) { goto _fail; diff --git a/components/drivers/virtio/virtio-input.c b/components/drivers/virtio/virtio-input.c index 64f8c692d18e..7860d4cd1f29 100644 --- a/components/drivers/virtio/virtio-input.c +++ b/components/drivers/virtio/virtio-input.c @@ -326,12 +326,12 @@ static rt_err_t virtio_input_probe(struct rt_virtio_device *vdev) goto _fail; } - if ((err = rt_dm_set_dev_name_auto(&vinput->parent, "input-event")) < 0) + if ((err = rt_dm_dev_set_name_auto(&vinput->parent, "input-event")) < 0) { goto _fail; } - dev_name = rt_dm_get_dev_name(&vinput->parent); + dev_name = rt_dm_dev_get_name(&vinput->parent); if ((err = rt_device_register(&vinput->parent, dev_name, RT_DEVICE_FLAG_STANDALONE | RT_DEVICE_FLAG_INT_RX))) { diff --git a/components/drivers/virtio/virtio-net.c b/components/drivers/virtio/virtio-net.c index d25f5d17585c..f88c2d56f307 100644 --- a/components/drivers/virtio/virtio-net.c +++ b/components/drivers/virtio/virtio-net.c @@ -164,7 +164,7 @@ static struct pbuf *virtio_net_rx(rt_device_t dev) if (size > sizeof(request->rx.mss)) { LOG_W("%s receive buffer's size = %u > %u is overflow", - rt_dm_get_dev_name(&vnet->parent.parent), size, sizeof(request->rx.mss)); + rt_dm_dev_get_name(&vnet->parent.parent), size, sizeof(request->rx.mss)); size = sizeof(request->rx.mss); } @@ -276,7 +276,7 @@ static void virtio_net_config_changed(struct rt_virtio_device *vdev) link_up = !!((vnet->status = status) & VIRTIO_NET_S_LINK_UP); - LOG_D("%s linkchange to %s", rt_dm_get_dev_name(&vdev->parent), link_up ? "up" : "down"); + LOG_D("%s linkchange to %s", rt_dm_dev_get_name(&vdev->parent), link_up ? "up" : "down"); eth_device_linkchange(&vnet->parent, link_up); } @@ -379,12 +379,12 @@ static rt_err_t virtio_net_probe(struct rt_virtio_device *vdev) goto _fail; } - if ((err = rt_dm_set_dev_name_auto(&vnet->parent.parent, "e")) < 0) + if ((err = rt_dm_dev_set_name_auto(&vnet->parent.parent, "e")) < 0) { goto _fail; } - if ((err = eth_device_init(&vnet->parent, rt_dm_get_dev_name(&vnet->parent.parent)))) + if ((err = eth_device_init(&vnet->parent, rt_dm_dev_get_name(&vnet->parent.parent)))) { goto _fail; } diff --git a/components/drivers/virtio/virtio.c b/components/drivers/virtio/virtio.c index 152e2ce9d9aa..ff87907f6bc6 100644 --- a/components/drivers/virtio/virtio.c +++ b/components/drivers/virtio/virtio.c @@ -183,9 +183,18 @@ static struct rt_bus virtio_bus; rt_err_t rt_virtio_driver_register(struct rt_virtio_driver *vdrv) { + const struct rt_virtio_device_id *id; + RT_ASSERT(vdrv != RT_NULL); + id = vdrv->ids; + while ((id + 1)->device) + { + ++id; + } + vdrv->parent.bus = &virtio_bus; + vdrv->parent.name = virtio_device_id_name[id->device]; return rt_driver_register(&vdrv->parent); } @@ -199,7 +208,7 @@ rt_err_t rt_virtio_device_register(struct rt_virtio_device *vdev) vdev->idx = (int)rt_hw_atomic_add(&uid, 1); - rt_dm_set_dev_name(&vdev->parent, "virtio%u", vdev->idx); + rt_dm_dev_set_name(&vdev->parent, "virtio%u", vdev->idx); rt_list_init(&vdev->vq_node); @@ -273,7 +282,7 @@ static rt_err_t virtio_probe(rt_device_t dev) if (!(status & VIRTIO_STATUS_FEATURES_OK)) { - LOG_E("%s device refuses features: %x", rt_dm_get_dev_name(dev), status); + LOG_E("%s device refuses features: %x", rt_dm_dev_get_name(dev), status); err = -RT_EIO; goto _err; diff --git a/components/drivers/virtio/virtio_ids.h b/components/drivers/virtio/virtio_ids.h new file mode 100644 index 000000000000..f995f95dbfb6 --- /dev/null +++ b/components/drivers/virtio/virtio_ids.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __VIRTIO_IDS_H__ +#define __VIRTIO_IDS_H__ + +enum +{ + /* virtio 1.0 */ + VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */ + VIRTIO_DEVICE_ID_NET = 1, /* Net */ + VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */ + VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */ + VIRTIO_DEVICE_ID_RNG = 4, /* Rng */ + VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */ + VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */ + VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */ + VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */ + VIRTIO_DEVICE_ID_9P = 9, /* 9p console */ + VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */ + VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */ + VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */ + VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */ + VIRTIO_DEVICE_ID_GPU = 16, /* GPU */ + VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */ + VIRTIO_DEVICE_ID_INPUT = 18, /* Input */ + /* virtio 1.1 */ + VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */ + VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */ + VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */ + VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */ + VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */ + VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */ + /* virtio 1.2 */ + VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */ + VIRTIO_DEVICE_ID_FS = 26, /* File system device */ + VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */ + VIRTIO_DEVICE_ID_RPMB = 28, /* RPMB device */ + VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */ + VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */ + VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */ + VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */ + VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */ + VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */ + VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */ + VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */ + VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */ + VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */ + VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */ + VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */ + VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */ + VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */ + + VIRTIO_DEVICE_ID_MAX +}; + +enum +{ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_NET = 0x1000, /* Network card */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BLOCK = 0x1001, /* Block device */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BALLOON = 0x1002, /* Memory ballooning (traditional) */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_CONSOLE = 0x1003, /* Console */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_SCSI = 0x1004, /* SCSI host */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_RNG = 0x1005, /* Entropy source */ + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_9P = 0x1009, /* 9P transport */ + + VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_MAX +}; + +#endif /* __VIRTIO_IDS_H__ */ diff --git a/components/drivers/virtio/virtio_internal.h b/components/drivers/virtio/virtio_internal.h index 4fc1eb21176d..cf8dff2f9056 100644 --- a/components/drivers/virtio/virtio_internal.h +++ b/components/drivers/virtio/virtio_internal.h @@ -30,20 +30,20 @@ rt_inline rt_bool_t virtio_is_little_endian(struct rt_virtio_device *vdev) } #ifdef __CHECKER__ -#define __force __attribute__((force)) +#define FORCE __attribute__((force)) #else -#define __force +#define FORCE #endif rt_inline rt_uint16_t virtio16_to_cpu(struct rt_virtio_device *vdev, rt_uint16_t val) { if (virtio_is_little_endian(vdev)) { - return rt_le16_to_cpu((__force rt_le16_t)val); + return rt_le16_to_cpu((FORCE rt_le16_t)val); } else { - return rt_be16_to_cpu((__force rt_be16_t)val); + return rt_be16_to_cpu((FORCE rt_be16_t)val); } } @@ -51,11 +51,11 @@ rt_inline rt_uint16_t cpu_to_virtio16(struct rt_virtio_device *vdev, rt_uint16_t { if (virtio_is_little_endian(vdev)) { - return (__force rt_le16_t)rt_cpu_to_le16(val); + return (FORCE rt_le16_t)rt_cpu_to_le16(val); } else { - return (__force rt_be16_t)rt_cpu_to_be16(val); + return (FORCE rt_be16_t)rt_cpu_to_be16(val); } } @@ -63,11 +63,11 @@ rt_inline rt_uint32_t virtio32_to_cpu(struct rt_virtio_device *vdev, rt_uint32_t { if (virtio_is_little_endian(vdev)) { - return rt_le32_to_cpu((__force rt_le32_t)val); + return rt_le32_to_cpu((FORCE rt_le32_t)val); } else { - return rt_be32_to_cpu((__force rt_be32_t)val); + return rt_be32_to_cpu((FORCE rt_be32_t)val); } } @@ -75,11 +75,11 @@ rt_inline rt_uint32_t cpu_to_virtio32(struct rt_virtio_device *vdev, rt_uint32_t { if (virtio_is_little_endian(vdev)) { - return (__force rt_le32_t)rt_cpu_to_le32(val); + return (FORCE rt_le32_t)rt_cpu_to_le32(val); } else { - return (__force rt_be32_t)rt_cpu_to_be32(val); + return (FORCE rt_be32_t)rt_cpu_to_be32(val); } } @@ -87,11 +87,11 @@ rt_inline rt_uint64_t virtio64_to_cpu(struct rt_virtio_device *vdev, rt_uint64_t { if (virtio_is_little_endian(vdev)) { - return rt_le64_to_cpu((__force rt_le64_t)val); + return rt_le64_to_cpu((FORCE rt_le64_t)val); } else { - return rt_be64_to_cpu((__force rt_be64_t)val); + return rt_be64_to_cpu((FORCE rt_be64_t)val); } } @@ -99,14 +99,14 @@ rt_inline rt_uint64_t cpu_to_virtio64(struct rt_virtio_device *vdev, rt_uint64_t { if (virtio_is_little_endian(vdev)) { - return (__force rt_le64_t)rt_cpu_to_le64(val); + return (FORCE rt_le64_t)rt_cpu_to_le64(val); } else { - return (__force rt_be64_t)rt_cpu_to_be64(val); + return (FORCE rt_be64_t)rt_cpu_to_be64(val); } } -#undef __force +#undef FORCE #endif /* __VIRTIO_INTERNAL_H__ */ diff --git a/components/drivers/virtio/virtio_mmio.c b/components/drivers/virtio/virtio_mmio.c index 9c1404a85fd8..e51f6f01fda6 100644 --- a/components/drivers/virtio/virtio_mmio.c +++ b/components/drivers/virtio/virtio_mmio.c @@ -16,10 +16,9 @@ #include +#include #include #include -#include -#include #include #define VIRTIO_MMIO_MAGIC 0x000 /* Magic value */ @@ -66,7 +65,6 @@ struct virtio_mmio { struct rt_virtio_device parent; - struct rt_platform_device *pdev; void *base; int irq; @@ -217,7 +215,7 @@ static rt_err_t virtio_mmio_set_features(struct rt_virtio_device *vdev) if (vio->version == 2 && !(vdev->features & RT_BIT(VIRTIO_F_VERSION_1))) { LOG_E("%s (virtio-mmio) devices (version 2) must provide VIRTIO_F_VERSION_1 feature", - rt_dm_get_dev_name(&vdev->parent)); + rt_dm_dev_get_name(&vdev->parent)); return -RT_EINVAL; } @@ -323,7 +321,7 @@ static struct rt_virtqueue *virtio_mmio_install_vq(struct rt_virtio_device *vdev if (num_max == 0) { - LOG_E("%s.virtqueue[%s] num_max is zero", rt_dm_get_dev_name(&vdev->parent), name); + LOG_E("%s.virtqueue[%s] num_max is zero", rt_dm_dev_get_name(&vdev->parent), name); return RT_NULL; } @@ -331,7 +329,7 @@ static struct rt_virtqueue *virtio_mmio_install_vq(struct rt_virtio_device *vdev if (virtq_nr && virtq_nr > num_max) { LOG_E("%s.virtqueue[%s] queue_num(%d) > num_max(%d)", - rt_dm_get_dev_name(&vdev->parent), name, virtq_nr, num_max); + rt_dm_dev_get_name(&vdev->parent), name, virtq_nr, num_max); return RT_NULL; } @@ -438,7 +436,7 @@ static rt_err_t virtio_mmio_release_vqs(struct rt_virtio_device *vdev) if (!status) { LOG_W("%s.virtqueue[%s] VIRTIO_MMIO_QUEUE_READY = %d", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, status); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, status); } } @@ -523,117 +521,100 @@ static const struct rt_virtio_transport virtio_mmio_trans = .reset = virtio_mmio_reset, }; -static rt_err_t virtio_mmio_ofw_init(struct rt_platform_device *pdev, struct virtio_mmio *vio) +static rt_err_t virtio_mmio_probe(struct rt_platform_device *pdev) { rt_err_t err = RT_EOK; - struct rt_ofw_node *np = pdev->parent.ofw_node; - - vio->base = rt_ofw_iomap(np, 0); + rt_uint32_t magic; + struct rt_virtio_device *vdev; + struct rt_device *dev = &pdev->parent; + struct virtio_mmio *vio = rt_calloc(1, sizeof(*vio)); - if (vio->base) + if (!vio) { - vio->irq = rt_ofw_get_irq(np, 0); - - if (vio->irq >= 0) - { - vio->pdev = pdev; - rt_ofw_data(np) = &vio->parent.parent; - } - else - { - err = -RT_ERROR; - } + return -RT_ENOMEM; } - else + + vio->base = rt_dm_dev_iomap(dev, 0); + + if (!vio->base) { err = -RT_EIO; - } - return err; -} + goto _fail; + } -static rt_err_t virtio_mmio_probe(struct rt_platform_device *pdev) -{ - rt_err_t err = RT_EOK; - struct rt_virtio_device *vdev; - struct virtio_mmio *vio = rt_calloc(1, sizeof(*vio)); + vio->irq = rt_dm_dev_get_irq(dev, 0); - do { - rt_uint32_t magic; + if (vio->irq < 0) + { + err = vio->irq; - if (!vio) - { - err = -RT_ENOMEM; - break; - } + goto _fail; + } - err = virtio_mmio_ofw_init(pdev, vio); + rt_dm_dev_bind_fwdata(dev, RT_NULL, &vio->parent.parent); - if (err) - { - break; - } + magic = virtio_mmio_read32(vio, VIRTIO_MMIO_MAGIC); - magic = virtio_mmio_read32(vio, VIRTIO_MMIO_MAGIC); - - /* 0x74726976 (a Little Endian equivalent of the "virt" string). */ - if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) - { - err = -RT_EINVAL; + /* 0x74726976 (a Little Endian equivalent of the "virt" string). */ + if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) + { + err = -RT_EINVAL; - LOG_E("invalid magic: %x", magic); + LOG_E("invalid magic: %x", magic); - break; - } + goto _fail; + } - vio->version = virtio_mmio_read32(vio, VIRTIO_MMIO_VERSION); + vio->version = virtio_mmio_read32(vio, VIRTIO_MMIO_VERSION); - /* Only support version 1~2 */ - if (vio->version < 1 || vio->version > 2) - { - err = -RT_ENOSYS; + /* Only support version 1~2 */ + if (vio->version < 1 || vio->version > 2) + { + err = -RT_ENOSYS; - LOG_E("not support version: %d", vio->version); + LOG_E("not support version: %d", vio->version); - break; - } + goto _fail; + } - vdev = &vio->parent; + vdev = &vio->parent; - vdev->id.device = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_ID); + vdev->id.device = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_ID); - if (vdev->id.device == VIRTIO_DEVICE_ID_INVALID) - { - err = -RT_EEMPTY; - break; - } + if (vdev->id.device == VIRTIO_DEVICE_ID_INVALID) + { + err = -RT_EEMPTY; + goto _fail; + } - vdev->id.vendor = virtio_mmio_read32(vio, VIRTIO_MMIO_VENDOR_ID); + vdev->id.vendor = virtio_mmio_read32(vio, VIRTIO_MMIO_VENDOR_ID); - if (vio->version == 1) - { - virtio_mmio_write32(vio, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_VIRTQ_PAGE_SZIE); - } + if (vio->version == 1) + { + virtio_mmio_write32(vio, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_VIRTQ_PAGE_SZIE); + } - rt_spin_lock_init(&vio->spinlock); + rt_spin_lock_init(&vio->spinlock); - vdev->trans = &virtio_mmio_trans; + vdev->trans = &virtio_mmio_trans; - err = rt_virtio_device_register(vdev); + if (!(err = rt_virtio_device_register(vdev))) + { + char name[RT_NAME_MAX]; - if (!err) - { - char name[RT_NAME_MAX]; + rt_sprintf(name, "%s-%s", rt_dm_dev_get_name(&vdev->parent), rt_virtio_device_id_name(vdev)); + rt_hw_interrupt_install(vio->irq, virtio_mmio_isr, vio, name); + } - rt_sprintf(name, "%s-%s", rt_dm_get_dev_name(&vdev->parent), rt_virtio_device_id_name(vdev)); - rt_hw_interrupt_install(vio->irq, virtio_mmio_isr, vio, name); - } - } while (0); + return RT_EOK; - if (err) +_fail: + if (vio->base) { - rt_free(vio); + rt_iounmap(vio->base); } + rt_free(vio); return err; } diff --git a/bsp/rockchip/rk3568/driver/drv_uart.h b/components/drivers/virtio/virtio_pci.c old mode 100644 new mode 100755 similarity index 51% rename from bsp/rockchip/rk3568/driver/drv_uart.h rename to components/drivers/virtio/virtio_pci.c index acc6ac0ea4b9..8f0f3228d30f --- a/bsp/rockchip/rk3568/driver/drv_uart.h +++ b/components/drivers/virtio/virtio_pci.c @@ -5,12 +5,5 @@ * * Change Logs: * Date Author Notes - * 2022-3-08 GuEe-GUI the first version + * 2022-11-07 GuEe-GUI first version */ - -#ifndef __DRV_UART_H__ -#define __DRV_UART_H__ - -int rt_hw_uart_init(void); - -#endif /* __DRV_UART_H__ */ diff --git a/components/drivers/virtio/virtio_pci.h b/components/drivers/virtio/virtio_pci.h new file mode 100755 index 000000000000..fec8e0ec7bb1 --- /dev/null +++ b/components/drivers/virtio/virtio_pci.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#ifndef __VIRTIO_PCI_H__ +#define __VIRTIO_PCI_H__ + +#include + +#define VIRTIO_PCI_CAP_COMMON_CFG 1 /* Common configuration */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /* Notifications */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 /* ISR Status */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 /* Device specific configuration */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 /* PCI configuration access */ +#define VIRTIO_PCI_CAP_SHARED_MEMORY_CFG 8 /* Shared memory region */ +#define VIRTIO_PCI_CAP_VENDOR_CFG 9 /* Vendor-specific data */ + +struct virtio_pci_cap +{ + rt_uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + rt_uint8_t cap_next; /* Generic PCI field: next ptr. */ + rt_uint8_t cap_len; /* Generic PCI field: capability length */ + rt_uint8_t cfg_type; /* Identifies the structure. */ + rt_uint8_t bar; /* Where to find it. */ + rt_uint8_t id; /* Multiple capabilities of the same type */ + rt_uint8_t padding[2]; /* Pad to full dword. */ + rt_uint32_t offset; /* Offset within bar. */ + rt_uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_cap64 +{ + struct virtio_pci_cap cap; + rt_uint32_t offset_hi; + rt_uint32_t length_hi; +}; + +struct virtio_pci_common_cfg +{ + /* About the whole device. */ + rt_uint32_t device_feature_select; /* Read-write */ + rt_uint32_t device_feature; /* Read-only for driver */ + rt_uint32_t driver_feature_select; /* Read-write */ + rt_uint32_t driver_feature; /* Read-write */ + rt_uint16_t config_msix_vector; /* Read-write */ + rt_uint16_t num_queues; /* Read-only for driver */ + rt_uint8_t device_status; /* Read-write */ + rt_uint8_t config_generation; /* Read-only for driver */ + + /* About a specific virtqueue. */ + rt_uint16_t queue_select; /* Read-write */ + rt_uint16_t queue_size; /* Read-write */ + rt_uint16_t queue_msix_vector; /* Read-write */ + rt_uint16_t queue_enable; /* Read-write */ + rt_uint16_t queue_notify_off; /* Read-only for driver */ + rt_uint64_t queue_desc; /* Read-write */ + rt_uint64_t queue_driver; /* Read-write */ + rt_uint64_t queue_device; /* Read-write */ + rt_uint16_t queue_notify_data; /* Read-only for driver */ + rt_uint16_t queue_reset; /* Read-write */ +}; + +struct virtio_pci_notify_cap +{ + struct virtio_pci_cap cap; + rt_uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +struct virtio_pci_vndr_data +{ + rt_uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + rt_uint8_t cap_next; /* Generic PCI field: next ptr. */ + rt_uint8_t cap_len; /* Generic PCI field: capability length */ + rt_uint8_t cfg_type; /* Identifies the structure. */ + rt_uint16_t vendor_id; /* Identifies the vendor-specific format. */ + /* For Vendor Definition */ + /* Pads structure to a multiple of 4 bytes */ + /* Reads must not have side effects */ +}; + +struct virtio_pci_cfg_cap +{ + struct virtio_pci_cap cap; + rt_uint8_t pci_cfg_data[4]; /* Data for BAR access. */ +}; + +struct virtio_pci_config +{ + rt_uint32_t device_features; /* [0x00] Flags representing features the device supports */ + rt_uint32_t driver_features; /* [0x04] Device features understood and activated by the driver */ + rt_uint32_t queue_pfn; /* [0x08] Guest physical page number of the virtual queue */ + rt_uint16_t queue_num; /* [0x0c] Virtual queue size */ + rt_uint16_t queue_sel; /* [0x0e] Virtual queue index */ + rt_uint16_t queue_notify; /* [0x10] Queue notifier */ + rt_uint8_t status; /* [0x12] Device status */ + rt_uint8_t interrupt_status; /* [0x13] Interrupt status */ + +/* + * According to the compiler's optimization ways, we should force compiler not + * to optimization here, but it will cause some compilers generate memory access + * instructions fail. So we allow user to choose a toggle of optimize here. + */ +#ifdef RT_USING_VIRTIO_MMIO_ALIGN +} __attribute__((packed)); +#else +}; +#endif + +#endif /* __VIRTIO_PCI_H__ */ diff --git a/components/drivers/virtio/virtio_pci_legacy.c b/components/drivers/virtio/virtio_pci_legacy.c new file mode 100755 index 000000000000..7d39eff3d8d5 --- /dev/null +++ b/components/drivers/virtio/virtio_pci_legacy.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#include "virtio_pci_legacy.h" + +static rt_err_t virtio_pci_legacy_probe(struct rt_pci_device *pdev) +{ + rt_err_t err = RT_EOK; + + return err; +} + +static struct rt_pci_device_id virtio_pci_legacy_ids[VIRTIO_PCI_DEVICE_END - VIRTIO_PCI_DEVICE_START] = +{ +}; + +static struct rt_pci_driver virtio_pci_legacy_driver = +{ + .name = "virtio-pci-legacy", + + .ids = virtio_pci_legacy_ids, + .probe = virtio_pci_legacy_probe, +}; + +static int virtio_pci_legacy_driver_register(void) +{ + rt_uint16_t id = VIRTIO_PCI_DEVICE_START; + + for (int i = 0; i < RT_ARRAY_SIZE(virtio_pci_legacy_ids); ++i, ++id) + { + virtio_pci_legacy_ids[i] = (struct rt_pci_device_id) + { + RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT_QUMRANET, id) + }; + } + + rt_pci_driver_register(&virtio_pci_legacy_driver); + + return 0; +} +INIT_DEVICE_EXPORT(virtio_pci_legacy_driver_register); diff --git a/components/drivers/virtio/virtio_pci_legacy.h b/components/drivers/virtio/virtio_pci_legacy.h new file mode 100755 index 000000000000..c5ad82f7ddbc --- /dev/null +++ b/components/drivers/virtio/virtio_pci_legacy.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#ifndef __VIRTIO_PCI_LEGACY_H__ +#define __VIRTIO_PCI_LEGACY_H__ + +#include "virtio_pci.h" + +/* PCI device ID in the range 0x1000 to 0x103f */ +#define VIRTIO_PCI_DEVICE_START 0x1000 +#define VIRTIO_PCI_DEVICE_END 0x103f + +#endif /* __VIRTIO_PCI_LEGACY_H__ */ diff --git a/components/drivers/virtio/virtio_pci_modern.c b/components/drivers/virtio/virtio_pci_modern.c new file mode 100755 index 000000000000..726b535d4033 --- /dev/null +++ b/components/drivers/virtio/virtio_pci_modern.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#include "virtio_pci_modern.h" + +static rt_err_t virtio_pci_modern_probe(struct rt_pci_device *pdev) +{ + rt_err_t err = RT_EOK; + + return err; +} + +static struct rt_pci_device_id virtio_pci_modern_ids[VIRTIO_PCI_DEVICE_END - VIRTIO_PCI_DEVICE_START] = +{ +}; + +static struct rt_pci_driver virtio_pci_modern_driver = +{ + .name = "virtio-pci-modern", + + .ids = virtio_pci_modern_ids, + .probe = virtio_pci_modern_probe, +}; + +static int virtio_pci_modern_driver_register(void) +{ + rt_uint16_t id = VIRTIO_PCI_DEVICE_START; + + for (int i = 0; i < RT_ARRAY_SIZE(virtio_pci_modern_ids); ++i, ++id) + { + virtio_pci_modern_ids[i] = (struct rt_pci_device_id) + { + RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT_QUMRANET, id), + }; + } + + rt_pci_driver_register(&virtio_pci_modern_driver); + + return 0; +} +INIT_DEVICE_EXPORT(virtio_pci_modern_driver_register); diff --git a/components/drivers/virtio/virtio_pci_modern.h b/components/drivers/virtio/virtio_pci_modern.h new file mode 100755 index 000000000000..4db65df38554 --- /dev/null +++ b/components/drivers/virtio/virtio_pci_modern.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-07 GuEe-GUI first version + */ + +#ifndef __VIRTIO_PCI_MODERN_H__ +#define __VIRTIO_PCI_MODERN_H__ + +#include "virtio_pci.h" + +/* PCI device ID in the range 0x1040 to 0x107f */ +#define VIRTIO_PCI_DEVICE_START 0x1040 +#define VIRTIO_PCI_DEVICE_END 0x107f + +#endif /* __VIRTIO_PCI_MODERN_H__ */ diff --git a/components/drivers/virtio/virtio_queue.c b/components/drivers/virtio/virtio_queue.c index c9035457ce2e..2a749bd107e9 100755 --- a/components/drivers/virtio/virtio_queue.c +++ b/components/drivers/virtio/virtio_queue.c @@ -151,7 +151,7 @@ static rt_err_t vq_split_add_buf(struct rt_virtqueue *vq, void *dma_buf, rt_size if (!vq->num_free) { LOG_D("%s.virtqueue[%s(%d)] add buffer.len = %d fail", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index); /* Recvice buffer NOW! */ if (is_out) @@ -190,7 +190,7 @@ static rt_err_t vq_split_add_buf(struct rt_virtqueue *vq, void *dma_buf, rt_size vq->num_free--; LOG_D("%s.virtqueue[%s(%d)] add buffer(%p, size = %d) head = %d", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index, dma_buf, size, head); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, dma_buf, size, head); if (vq->num_added == RT_UINT16_MAX) { @@ -211,7 +211,7 @@ static rt_bool_t vq_split_submit(struct rt_virtqueue *vq) head = (head - vq->num_added) % virtq_num; LOG_D("%s.virtqueue[%s(%d)] submit head = %d, num_added = %d, idx = %d", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index, head, vq->num_added, virtq->avail->idx + 1); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, head, vq->num_added, virtq->avail->idx + 1); /* Reset list info */ vq->num_added = 0; @@ -292,7 +292,7 @@ static void *vq_split_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len) if (!vq_split_pending(vq)) { LOG_D("%s.virtqueue[%s(%d)] read buffer empty", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index); return RT_NULL; } @@ -307,7 +307,7 @@ static void *vq_split_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len) buf = vq->buffer_hash[idx]; LOG_D("%s.virtqueue[%s(%d)] read head = %d, buffer(%p, size = %d)", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index, idx, buf, *out_len); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, idx, buf, *out_len); do { idx = next; @@ -507,7 +507,7 @@ void rt_virtqueue_isr(int irq, struct rt_virtqueue *vq) if (!virtqueue_pending(vq)) { LOG_D("%s.virtqueue[%s(%d)] no buffer pending in %s", - rt_dm_get_dev_name(&vq->vdev->parent), vq->name, vq->index, "isr"); + rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, "isr"); return; } diff --git a/components/drivers/watchdog/Kconfig b/components/drivers/watchdog/Kconfig new file mode 100644 index 000000000000..a8cd0bcda5bf --- /dev/null +++ b/components/drivers/watchdog/Kconfig @@ -0,0 +1,15 @@ +menuconfig RT_USING_WDT + bool "Using Watch Dog device drivers" + default n + +config RT_WDT_BCM2835 + bool "Broadcom BCM2835 hardware watchdog" + depends on RT_USING_DM + depends on RT_USING_WDT + default n + +config RT_WDT_DW + bool "Synopsys DesignWare watchdog" + depends on RT_USING_DM + depends on RT_USING_WDT + default n diff --git a/components/drivers/watchdog/SConscript b/components/drivers/watchdog/SConscript index 38934d3c4175..2e8f835fbd0a 100644 --- a/components/drivers/watchdog/SConscript +++ b/components/drivers/watchdog/SConscript @@ -1,8 +1,21 @@ from building import * -cwd = GetCurrentDir() -src = Glob('*.c') +group = [] + +if not GetDepend(['RT_USING_WDT']): + Return('group') + +cwd = GetCurrentDir() CPPPATH = [cwd + '/../include'] -group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_WDT'], CPPPATH = CPPPATH) + +src = ['watchdog.c'] + +if GetDepend(['RT_WDT_BCM2835']): + src += ['watchdog-bcm2835.c'] + +if GetDepend(['RT_WDT_DW']): + src += ['watchdog-dw.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/watchdog/watchdog-bcm2835.c b/components/drivers/watchdog/watchdog-bcm2835.c new file mode 100644 index 000000000000..d4a5d28dcad9 --- /dev/null +++ b/components/drivers/watchdog/watchdog-bcm2835.c @@ -0,0 +1,213 @@ +/* + * 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 "../pm/pm-bcm2835.h" + +#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; + } + + rt_spin_lock_init(&bcm2835_wdt->lock); + + bcm2835_power_off_wdt = bcm2835_wdt; + +#ifdef RT_USING_OFW + if (rt_ofw_prop_read_bool(np, "system-power-controller")) + { + if (!rt_pm_machine_shutdown) + { + rt_pm_machine_shutdown = bcm2835_wdt_power_off; + } + } +#endif /* RT_USING_OFW */ + + if (!rt_pm_machine_reset) + { + rt_pm_machine_reset = bcm2835_wdt_power_reboot; + } + + 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 struct rt_platform_driver bcm2835_wdt_driver = +{ + .name = "bcm2835-wdt", + .probe = bcm2835_wdt_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(bcm2835_wdt_driver); diff --git a/components/drivers/watchdog/watchdog-dw.c b/components/drivers/watchdog/watchdog-dw.c new file mode 100644 index 000000000000..280f47b5730a --- /dev/null +++ b/components/drivers/watchdog/watchdog-dw.c @@ -0,0 +1,569 @@ +/* + * 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 WDOG_CONTROL_REG_OFFSET 0x00 +#define WDOG_CONTROL_REG_WDT_EN_MASK 0x01 +#define WDOG_CONTROL_REG_RESP_MODE_MASK 0x02 +#define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04 +#define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4 +#define WDOG_CURRENT_COUNT_REG_OFFSET 0x08 +#define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c +#define WDOG_COUNTER_RESTART_KICK_VALUE 0x76 +#define WDOG_INTERRUPT_STATUS_REG_OFFSET 0x10 +#define WDOG_INTERRUPT_CLEAR_REG_OFFSET 0x14 +#define WDOG_COMP_PARAMS_5_REG_OFFSET 0xe4 +#define WDOG_COMP_PARAMS_4_REG_OFFSET 0xe8 +#define WDOG_COMP_PARAMS_3_REG_OFFSET 0xec +#define WDOG_COMP_PARAMS_2_REG_OFFSET 0xf0 +#define WDOG_COMP_PARAMS_1_REG_OFFSET 0xf4 +#define WDOG_COMP_PARAMS_1_USE_FIX_TOP (1 << 6) +#define WDOG_COMP_VERSION_REG_OFFSET 0xf8 +#define WDOG_COMP_TYPE_REG_OFFSET 0xfc + +/* There are sixteen TOPs (timeout periods) that can be set in the watchdog. */ +#define DW_WDT_NUM_TOPS 16 +#define DW_WDT_FIX_TOP(idx) (1U << (16 + idx)) +#define DW_WDT_DEFAULT_SECONDS 30 + +#define MSEC_PER_SEC 1000L + +enum dw_wdt_rmod +{ + DW_WDT_RMOD_RESET = 1, + DW_WDT_RMOD_IRQ +}; + +struct dw_wdt_timeout +{ + rt_uint32_t top_val; + rt_uint32_t sec; + rt_uint32_t msec; +}; + +struct dw_wdt +{ + rt_watchdog_t parent; + + void *base; + int irq; + struct rt_clk *clk; + + rt_ubase_t rate; + enum dw_wdt_rmod rmod; + struct dw_wdt_timeout timeouts[DW_WDT_NUM_TOPS]; + /* Save/Restore */ + rt_uint32_t user; + rt_uint32_t timeout; + rt_uint32_t pretimeout; + rt_uint32_t max_hw_heartbeat_ms; + + struct rt_event event; +}; + +#define raw_to_dw_wdt(raw) rt_container_of(raw, struct dw_wdt, parent) + +static const rt_uint32_t dw_wdt_fix_tops[DW_WDT_NUM_TOPS] = +{ + DW_WDT_FIX_TOP(0), DW_WDT_FIX_TOP(1), DW_WDT_FIX_TOP(2), DW_WDT_FIX_TOP(3), + DW_WDT_FIX_TOP(4), DW_WDT_FIX_TOP(5), DW_WDT_FIX_TOP(6), DW_WDT_FIX_TOP(7), + DW_WDT_FIX_TOP(8), DW_WDT_FIX_TOP(9), DW_WDT_FIX_TOP(10), DW_WDT_FIX_TOP(11), + DW_WDT_FIX_TOP(12), DW_WDT_FIX_TOP(13), DW_WDT_FIX_TOP(14), DW_WDT_FIX_TOP(15) +}; + +rt_inline int dw_wdt_is_enabled(struct dw_wdt *dw_wdt) +{ + return HWREG32(dw_wdt->base + WDOG_CONTROL_REG_OFFSET) & WDOG_CONTROL_REG_WDT_EN_MASK; +} + +static void dw_wdt_update_mode(struct dw_wdt *dw_wdt, enum dw_wdt_rmod rmod) +{ + rt_uint32_t val = HWREG32(dw_wdt->base + WDOG_CONTROL_REG_OFFSET); + + if (rmod == DW_WDT_RMOD_IRQ) + { + val |= WDOG_CONTROL_REG_RESP_MODE_MASK; + } + else + { + val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK; + } + + HWREG32(dw_wdt->base + WDOG_CONTROL_REG_OFFSET) = val; + + dw_wdt->rmod = rmod; +} + +static rt_uint32_t dw_wdt_find_best_top(struct dw_wdt *dw_wdt, rt_uint32_t timeout, rt_uint32_t *top_val) +{ + int idx; + + /* + * Find a TOP with timeout greater or equal to the requested number. Note + * we'll select a TOP with maximum timeout if the requested timeout couldn't + * be reached. + */ + for (idx = 0; idx < DW_WDT_NUM_TOPS; ++idx) + { + if (dw_wdt->timeouts[idx].sec >= timeout) + { + break; + } + } + + if (idx == DW_WDT_NUM_TOPS) + { + --idx; + } + + *top_val = dw_wdt->timeouts[idx].top_val; + + return dw_wdt->timeouts[idx].sec; +} + +static rt_uint32_t dw_wdt_get_max_timeout_ms(struct dw_wdt *dw_wdt) +{ + rt_uint64_t msec; + struct dw_wdt_timeout *timeout = &dw_wdt->timeouts[DW_WDT_NUM_TOPS - 1]; + + msec = (rt_uint64_t)timeout->sec * MSEC_PER_SEC + timeout->msec; + + return msec < RT_UINT32_MAX ? msec : RT_UINT32_MAX; +} + +static rt_uint32_t dw_wdt_get_timeout(struct dw_wdt *dw_wdt) +{ + int idx; + int top_val = HWREG32(dw_wdt->base + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF; + + for (idx = 0; idx < DW_WDT_NUM_TOPS; ++idx) + { + if (dw_wdt->timeouts[idx].top_val == top_val) + { + break; + } + } + + /* + * In IRQ mode due to the two stages counter, the actual timeout is twice + * greater than the TOP setting. + */ + return dw_wdt->timeouts[idx].sec * dw_wdt->rmod; +} + +static int dw_wdt_keep_alive(struct dw_wdt *dw_wdt) +{ + HWREG32(dw_wdt->base + WDOG_COUNTER_RESTART_REG_OFFSET) = WDOG_COUNTER_RESTART_KICK_VALUE; + + return 0; +} + +static void dw_wdt_set_timeout(struct dw_wdt *dw_wdt, rt_uint32_t top_s) +{ + rt_uint32_t top_val; + rt_uint32_t timeout; + + /* + * Note IRQ mode being enabled means having a non-zero pre-timeout setup. + * In this case we try to find a TOP as close to the half of the requested + * timeout as possible since DW Watchdog IRQ mode is designed in two stages + * way - first timeout rises the pre-timeout interrupt, second timeout + * performs the system reset. So basically the effective watchdog-caused + * reset happens after two watchdog TOPs elapsed. + */ + timeout = dw_wdt_find_best_top(dw_wdt, RT_DIV_ROUND_UP(top_s, dw_wdt->rmod), &top_val); + + if (dw_wdt->rmod == DW_WDT_RMOD_IRQ) + { + dw_wdt->pretimeout = timeout; + } + else + { + dw_wdt->pretimeout = 0; + } + + /* + * Set the new value in the watchdog. Some versions of dw_wdt have have + * TOPINIT in the TIMEOUT_RANGE register (as per CP_WDT_DUAL_TOP in + * WDT_COMP_PARAMS_1). On those we effectively get a pat of the watchdog + * right here. + */ + HWREG32(dw_wdt->base + WDOG_TIMEOUT_RANGE_REG_OFFSET) = top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT; + + dw_wdt_keep_alive(dw_wdt); + + /* + * In case users set bigger timeout value than HW can support, + * kernel(watchdog_dev.c) helps to feed watchdog before wdd->max_hw_heartbeat_ms + */ + if (top_s * 1000 <= dw_wdt->max_hw_heartbeat_ms) + { + dw_wdt->timeout = timeout * dw_wdt->rmod; + } + else + { + dw_wdt->timeout = top_s; + } +} + +static void dw_wdt_set_pretimeout(struct dw_wdt *dw_wdt, rt_uint32_t req) +{ + /* + * We ignore actual value of the timeout passed from user-space using it as + * a flag whether the pretimeout functionality is intended to be activated. + */ + dw_wdt_update_mode(dw_wdt, req ? DW_WDT_RMOD_IRQ : DW_WDT_RMOD_RESET); + dw_wdt_set_timeout(dw_wdt, dw_wdt->timeout); +} + +static void dw_wdt_arm_system_reset(struct dw_wdt *dw_wdt) +{ + rt_uint32_t val = HWREG32(dw_wdt->base + WDOG_CONTROL_REG_OFFSET); + + /* Disable/enable interrupt mode depending on the RMOD flag. */ + if (dw_wdt->rmod == DW_WDT_RMOD_IRQ) + { + val |= WDOG_CONTROL_REG_RESP_MODE_MASK; + } + else + { + val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK; + } + + /* Enable watchdog. */ + HWREG32(dw_wdt->base + WDOG_CONTROL_REG_OFFSET) = val | WDOG_CONTROL_REG_WDT_EN_MASK; +} + +static int dw_wdt_start(struct dw_wdt *dw_wdt) +{ + rt_clk_enable(dw_wdt->clk); + + dw_wdt_set_timeout(dw_wdt, dw_wdt->timeout); + dw_wdt_keep_alive(dw_wdt); + dw_wdt_arm_system_reset(dw_wdt); + + return 0; +} + +static int dw_wdt_stop(struct dw_wdt *dw_wdt) +{ + /* + * The DesignWare watchdog cannot be stopped once it has been started so we + * do not implement a stop function. The watchdog core will continue to send + * heartbeat requests after the watchdog device has been closed. + */ + rt_clk_disable(dw_wdt->clk); + + return 0; +} + +static rt_uint32_t dw_wdt_get_timeleft(struct dw_wdt *dw_wdt) +{ + rt_uint32_t val, sec; + + val = HWREG32(dw_wdt->base + WDOG_CURRENT_COUNT_REG_OFFSET); + sec = val / dw_wdt->rate; + + if (dw_wdt->rmod == DW_WDT_RMOD_IRQ) + { + val = HWREG32(dw_wdt->base + WDOG_INTERRUPT_STATUS_REG_OFFSET); + + if (!val) + { + sec += dw_wdt->pretimeout; + } + } + + return sec; +} + +static rt_err_t dw_wdt_init_timeouts(struct dw_wdt *dw_wdt) +{ + int val, tidx; + rt_uint64_t msec; + struct dw_wdt_timeout tout, *dst; + const rt_uint32_t *tops = dw_wdt_fix_tops; + + /* + * Convert the specified TOPs into an array of watchdog timeouts. We walk + * over the passed TOPs array and calculate corresponding timeouts in + * seconds and milliseconds. The milliseconds granularity is needed to + * distinguish the TOPs with very close timeouts and to set the watchdog max + * heartbeat setting further. + */ + for (val = 0; val < DW_WDT_NUM_TOPS; ++val) + { + tout.top_val = val; + tout.sec = tops[val] / dw_wdt->rate; + msec = (rt_uint64_t)tops[val] * MSEC_PER_SEC; + rt_do_div(msec, dw_wdt->rate); + tout.msec = msec - ((rt_uint64_t)tout.sec * MSEC_PER_SEC); + + /* + * Find a suitable place for the current TOP in the timeouts array so + * that the list is remained in the ascending order. + */ + for (tidx = 0; tidx < val; ++tidx) + { + dst = &dw_wdt->timeouts[tidx]; + + if (tout.sec > dst->sec || (tout.sec == dst->sec && tout.msec >= dst->msec)) + { + continue; + } + else + { + struct dw_wdt_timeout tmp = *dst; + + *dst = tout; + tout = tmp; + } + } + + dw_wdt->timeouts[val] = tout; + } + + if (!dw_wdt->timeouts[DW_WDT_NUM_TOPS - 1].sec) + { + return -RT_ENOSYS; + } + + return RT_EOK; +} + +static rt_err_t dw_wdt_init(rt_watchdog_t *wdt) +{ + rt_err_t status = RT_EOK; + struct dw_wdt *dw_wdt = raw_to_dw_wdt(wdt); + + /* Enable normal reset without pre-timeout by default. */ + dw_wdt_update_mode(dw_wdt, DW_WDT_RMOD_RESET); + + if (dw_wdt_init_timeouts(dw_wdt)) + { + return -RT_ERROR; + } + + dw_wdt->max_hw_heartbeat_ms = dw_wdt_get_max_timeout_ms(dw_wdt); + + /* + * If the watchdog is already running, use its already configured timeout. + * Otherwise use the default or the value provided through devicetree. + */ + if (dw_wdt_is_enabled(dw_wdt)) + { + dw_wdt->timeout = dw_wdt_get_timeout(dw_wdt); + } + else + { + dw_wdt->timeout = DW_WDT_DEFAULT_SECONDS; + } + + return status; +} + +static rt_err_t dw_wdt_control(rt_watchdog_t *wdt, int cmd, void *args) +{ + rt_err_t status = RT_EOK; + struct dw_wdt *dw_wdt = raw_to_dw_wdt(wdt); + + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: + *(rt_uint32_t *)args = dw_wdt_get_timeout(dw_wdt); + break; + + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + dw_wdt_set_timeout(dw_wdt, *(rt_uint32_t *)args); + break; + + case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: + *(rt_uint32_t *)args = dw_wdt_get_timeleft(dw_wdt); + break; + + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + dw_wdt_set_pretimeout(dw_wdt, dw_wdt->pretimeout); + dw_wdt_keep_alive(dw_wdt); + break; + + case RT_DEVICE_CTRL_WDT_START: + dw_wdt_start(dw_wdt); + dw_wdt->user++; + break; + + case RT_DEVICE_CTRL_WDT_STOP: + dw_wdt_stop(dw_wdt); + dw_wdt->user--; + break; + + default: + status = -RT_EINVAL; + } + + return status; +} + +static const struct rt_watchdog_ops dw_wdt_ops = +{ + .init = dw_wdt_init, + .control = dw_wdt_control, +}; + +#ifdef RT_USING_PM +static int dw_wdt_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct dw_wdt *dw_wdt = raw_to_dw_wdt(wdt); + + dw_wdt->timeout = dw_wdt_get_timeleft(dw_wdt) / dw_wdt->rate; + dw_wdt_stop(dw_wdt); + + return RT_EOK; +} + +static void dw_wdt_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_watchdog_t *wdt = rt_container_of(device, rt_watchdog_t, parent); + struct dw_wdt *dw_wdt = raw_to_dw_wdt(wdt); + + if (!dw_wdt->user) + { + return; + } + + if (!dw_wdt_init(wdt)) + { + dw_wdt_start(dw_wdt); + } +} + +static const struct rt_device_pm_ops dw_wdt_pm_ops = +{ + .suspend = dw_wdt_pm_suspend, + .resume = dw_wdt_pm_resume, +}; +#endif /* RT_USING_PM */ + +static void dw_wdt_isr(int irqno, void *param) +{ + struct dw_wdt *wdt = (struct dw_wdt *)param; + + if (!HWREG32(wdt->base + WDOG_INTERRUPT_STATUS_REG_OFFSET)) + { + return; + } + + /* Clear the IRQ status (EOI) */ + rt_event_send(&wdt->event, HWREG32(wdt->base + WDOG_INTERRUPT_CLEAR_REG_OFFSET)); +} + +static void dw_wdt_free(struct dw_wdt *dw_wdt) +{ + if (dw_wdt->base) + { + rt_iounmap(dw_wdt->base); + } + + if (dw_wdt->clk) + { + rt_clk_disable(dw_wdt->clk); + } + + rt_free(dw_wdt); +} + +static rt_err_t dw_wdt_probe(struct rt_platform_device *pdev) +{ + rt_err_t err = RT_EOK; + const char *dev_name; + struct rt_device *dev = &pdev->parent; + struct dw_wdt *dw_wdt = rt_calloc(1, sizeof(*dw_wdt)); + + if (!dw_wdt) + { + return -RT_ENOMEM; + } + + dw_wdt->base = rt_dm_dev_iomap(dev, 0); + + if (!dw_wdt->base) + { + err = -RT_EIO; + goto _free_res; + } + + dw_wdt->irq = rt_dm_dev_get_irq(dev, 0); + + if (dw_wdt->irq < 0) + { + err = dw_wdt->irq; + goto _free_res; + } + + dw_wdt->clk = rt_clk_get_by_name(dev, "pclk"); + + if (!dw_wdt->clk) + { + dw_wdt->clk = rt_clk_get_by_index(dev, 0); + + if (!dw_wdt->clk) + { + err = -RT_EIO; + goto _free_res; + } + } + + if (err) + { + goto _free_res; + } + + dw_wdt->rate = rt_clk_get_rate(dw_wdt->clk); + dw_wdt->parent.ops = &dw_wdt_ops; + + rt_dm_dev_set_name_auto(&dw_wdt->parent.parent, "wdt"); + dev_name = rt_dm_dev_get_name(&dw_wdt->parent.parent); + + rt_event_init(&dw_wdt->event, dev_name, RT_IPC_FLAG_PRIO); + + rt_hw_interrupt_install(dw_wdt->irq, dw_wdt_isr, dw_wdt, dev_name); + rt_hw_interrupt_umask(dw_wdt->irq); + +#ifdef RT_USING_PM + rt_pm_device_register(&dw_wdt->parent.parent, &dw_wdt_pm_ops); +#endif + + rt_hw_watchdog_register(&dw_wdt->parent, dev_name, 0, dw_wdt); + + return RT_EOK; + +_free_res: + dw_wdt_free(dw_wdt); + + return err; +} + +static const struct rt_ofw_node_id dw_wdt_ofw_ids[] = +{ + { .compatible = "snps,dw-wdt" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver dw_wdt_driver = +{ + .name = "dw-wdt", + .ids = dw_wdt_ofw_ids, + + .probe = dw_wdt_probe, +}; +RT_PLATFORM_DRIVER_EXPORT(dw_wdt_driver); diff --git a/components/mm/ioremap.c b/components/mm/ioremap.c index 25200c9cf072..9b062adf2bc5 100644 --- a/components/mm/ioremap.c +++ b/components/mm/ioremap.c @@ -87,10 +87,6 @@ rt_weak void *rt_ioremap_early(void *paddr, size_t size) return paddr; } -rt_weak void rt_iounmap_early(void *vaddr, size_t size) -{ -} - void *rt_ioremap(void *paddr, size_t size) { return _ioremap_type(paddr, size, MM_AREA_TYPE_PHY); diff --git a/components/mm/ioremap.h b/components/mm/ioremap.h index 25dd639e0ec8..f17b5d5fff71 100644 --- a/components/mm/ioremap.h +++ b/components/mm/ioremap.h @@ -31,7 +31,6 @@ extern "C" { */ void *rt_ioremap_early(void *paddr, size_t size); -void rt_iounmap_early(void *vaddr, size_t size); void *rt_ioremap(void *paddr, size_t size); void *rt_ioremap_nocache(void *paddr, size_t size); void *rt_ioremap_cached(void *paddr, size_t size); diff --git a/include/rtatomic.h b/include/rtatomic.h index d3cd04dd4b60..4ace5307f16b 100644 --- a/include/rtatomic.h +++ b/include/rtatomic.h @@ -10,7 +10,7 @@ #ifndef __RT_ATOMIC_H__ #define __RT_ATOMIC_H__ -#include +#include rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr); void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val); diff --git a/include/rthw.h b/include/rthw.h index 1dcfb311baa1..7dbc28fc08c6 100644 --- a/include/rthw.h +++ b/include/rthw.h @@ -163,6 +163,7 @@ void rt_hw_us_delay(rt_uint32_t us); #ifdef RT_USING_SMP #include /* for spinlock from arch */ +#include struct rt_spinlock { @@ -171,6 +172,17 @@ struct rt_spinlock void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock); void rt_hw_spin_lock(rt_hw_spinlock_t *lock); +rt_inline rt_bool_t rt_hw_spin_trylock(rt_hw_spinlock_t *lock) +{ + volatile rt_atomic_t old = (rt_uint32_t)rt_atomic_load((rt_atomic_t *)lock); + + if ((old >> 16) != (old & 0xffff)) + { + return RT_FALSE; + } + + return rt_atomic_compare_exchange_strong((rt_atomic_t *)&lock->slock, &old, old + (1 << 16)); +} void rt_hw_spin_unlock(rt_hw_spinlock_t *lock); int rt_hw_cpu_id(void); diff --git a/include/rtthread.h b/include/rtthread.h index e64437b85a69..0222731c60ab 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -517,15 +517,19 @@ struct rt_spinlock; void rt_spin_lock_init(struct rt_spinlock *lock); void rt_spin_lock(struct rt_spinlock *lock); +rt_err_t rt_spin_trylock(struct rt_spinlock *lock); void rt_spin_unlock(struct rt_spinlock *lock); rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock); +rt_err_t rt_spin_trylock_irqsave(struct rt_spinlock *lock, rt_ubase_t *out_level); void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level); #else #define rt_spin_lock_init(lock) /* nothing */ #define rt_spin_lock(lock) rt_enter_critical() +#define rt_spin_trylock(lock) ({ rt_spin_lock(lock), RT_EOK }) #define rt_spin_unlock(lock) (RT_UNUSED(lock), rt_exit_critical()) #define rt_spin_lock_irqsave(lock) (RT_UNUSED(lock), rt_hw_interrupt_disable()) +#define rt_spin_trylock_irqsave(lock, out_level)({ RT_UNUSED(lock), *out_level = rt_hw_interrupt_disable(); RT_EOK }) #define rt_spin_unlock_irqrestore(lock, level) rt_hw_interrupt_enable(level) #endif diff --git a/libcpu/aarch64/common/armv8.h b/libcpu/aarch64/common/armv8.h index d96a5af72ab5..b3edd4d9ca58 100644 --- a/libcpu/aarch64/common/armv8.h +++ b/libcpu/aarch64/common/armv8.h @@ -1,57 +1,62 @@ /* - * Copyright (c) 2006-2020, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2011-09-15 Bernard first version + * 2023-07-13 GuEe-GUI append fpu: Q16 ~ Q31 */ #ifndef __ARMV8_H__ #define __ARMV8_H__ +#include + +typedef struct { rt_uint64_t value[2]; } rt_uint128_t; + /* the exception stack without VFP registers */ struct rt_hw_exp_stack { - unsigned long pc; - unsigned long cpsr; - unsigned long sp_el0; - unsigned long x30; - unsigned long fpcr; - unsigned long fpsr; - unsigned long x28; - unsigned long x29; - unsigned long x26; - unsigned long x27; - unsigned long x24; - unsigned long x25; - unsigned long x22; - unsigned long x23; - unsigned long x20; - unsigned long x21; - unsigned long x18; - unsigned long x19; - unsigned long x16; - unsigned long x17; - unsigned long x14; - unsigned long x15; - unsigned long x12; - unsigned long x13; - unsigned long x10; - unsigned long x11; - unsigned long x8; - unsigned long x9; - unsigned long x6; - unsigned long x7; - unsigned long x4; - unsigned long x5; - unsigned long x2; - unsigned long x3; - unsigned long x0; - unsigned long x1; + rt_uint64_t pc; + rt_uint64_t cpsr; + rt_uint64_t sp_el0; + rt_uint64_t x30; + rt_uint64_t fpcr; + rt_uint64_t fpsr; + rt_uint64_t x28; + rt_uint64_t x29; + rt_uint64_t x26; + rt_uint64_t x27; + rt_uint64_t x24; + rt_uint64_t x25; + rt_uint64_t x22; + rt_uint64_t x23; + rt_uint64_t x20; + rt_uint64_t x21; + rt_uint64_t x18; + rt_uint64_t x19; + rt_uint64_t x16; + rt_uint64_t x17; + rt_uint64_t x14; + rt_uint64_t x15; + rt_uint64_t x12; + rt_uint64_t x13; + rt_uint64_t x10; + rt_uint64_t x11; + rt_uint64_t x8; + rt_uint64_t x9; + rt_uint64_t x6; + rt_uint64_t x7; + rt_uint64_t x4; + rt_uint64_t x5; + rt_uint64_t x2; + rt_uint64_t x3; + rt_uint64_t x0; + rt_uint64_t x1; - unsigned long long fpu[16]; + rt_uint128_t fpu[32]; }; #define SP_ELx ((unsigned long)0x01) diff --git a/libcpu/aarch64/common/asm_fpu.h b/libcpu/aarch64/common/asm_fpu.h index 8ac4ab9bd881..556d1847deaf 100644 --- a/libcpu/aarch64/common/asm_fpu.h +++ b/libcpu/aarch64/common/asm_fpu.h @@ -25,8 +25,40 @@ STR Q13, [\reg, #-0x10]! STR Q14, [\reg, #-0x10]! STR Q15, [\reg, #-0x10]! + STR Q16, [\reg, #-0x10]! + STR Q17, [\reg, #-0x10]! + STR Q18, [\reg, #-0x10]! + STR Q19, [\reg, #-0x10]! + STR Q20, [\reg, #-0x10]! + STR Q21, [\reg, #-0x10]! + STR Q22, [\reg, #-0x10]! + STR Q23, [\reg, #-0x10]! + STR Q24, [\reg, #-0x10]! + STR Q25, [\reg, #-0x10]! + STR Q26, [\reg, #-0x10]! + STR Q27, [\reg, #-0x10]! + STR Q28, [\reg, #-0x10]! + STR Q29, [\reg, #-0x10]! + STR Q30, [\reg, #-0x10]! + STR Q31, [\reg, #-0x10]! .endm .macro RESTORE_FPU, reg + LDR Q31, [\reg], #0x10 + LDR Q30, [\reg], #0x10 + LDR Q29, [\reg], #0x10 + LDR Q28, [\reg], #0x10 + LDR Q27, [\reg], #0x10 + LDR Q26, [\reg], #0x10 + LDR Q25, [\reg], #0x10 + LDR Q24, [\reg], #0x10 + LDR Q23, [\reg], #0x10 + LDR Q22, [\reg], #0x10 + LDR Q21, [\reg], #0x10 + LDR Q20, [\reg], #0x10 + LDR Q19, [\reg], #0x10 + LDR Q18, [\reg], #0x10 + LDR Q17, [\reg], #0x10 + LDR Q16, [\reg], #0x10 LDR Q15, [\reg], #0x10 LDR Q14, [\reg], #0x10 LDR Q13, [\reg], #0x10 diff --git a/libcpu/aarch64/common/atomic_aarch64.c b/libcpu/aarch64/common/atomic_aarch64.c index c55cd8a84ffb..4b3295161335 100644 --- a/libcpu/aarch64/common/atomic_aarch64.c +++ b/libcpu/aarch64/common/atomic_aarch64.c @@ -8,6 +8,7 @@ * 2023-05-18 GuEe-GUI first version */ +#include #include rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr) @@ -15,7 +16,7 @@ rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr) rt_atomic_t ret; __asm__ volatile ( - " ldr %w0, %1\n" + " ldr %0, %1\n" " dmb ish" : "=r" (ret) : "Q" (*ptr) @@ -27,7 +28,7 @@ rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr) void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val) { __asm__ volatile ( - " stlr %w1, %0\n" + " str %1, %0\n" " dmb ish" : "=Q" (*ptr) : "r" (val) @@ -41,9 +42,9 @@ rt_atomic_t rt_hw_atomic_##op(volatile rt_atomic_t *ptr, rt_atomic_t in_val) \ __asm__ volatile ( \ " prfm pstl1strm, %3\n" \ - "1: ldxr %w0, %3\n" \ - " "#ins " %w1, %w0, %w4\n" \ - " stlxr %w2, %w1, %3\n" \ + "1: ldxr %0, %3\n" \ + " "#ins " %1, %0, %4\n" \ + " stlxr %w2, %1, %3\n" \ " cbnz %w2, 1b\n" \ " dmb ish" \ : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (*ptr) \ @@ -65,8 +66,8 @@ rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val) __asm__ volatile ( " prfm pstl1strm, %2\n" - "1: ldxr %w0, %2\n" - " stlxr %w1, %w3, %2\n" + "1: ldxr %0, %2\n" + " stlxr %w1, %3, %2\n" " cbnz %w1, 1b\n" " dmb ish" : "=&r" (ret), "=&r" (tmp), "+Q" (*ptr) @@ -92,10 +93,10 @@ rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_a __asm__ volatile ( " prfm pstl1strm, %2\n" - "1: ldxr %w0, %2\n" - " eor %w1, %w0, %w3\n" - " cbnz %w1, 2f\n" - " stlxr %w1, %w4, %2\n" + "1: ldxr %0, %2\n" + " eor %1, %0, %3\n" + " cbnz %1, 2f\n" + " stlxr %w1, %4, %2\n" " cbnz %w1, 1b\n" " dmb ish\n" "2:" @@ -103,6 +104,5 @@ rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_a : "Kr" (*old), "r" (new) : "memory"); - return oldval; + return oldval == *old; } - diff --git a/libcpu/aarch64/common/backtrace.c b/libcpu/aarch64/common/backtrace.c index d8985d0c09ea..0ff342f21ebf 100644 --- a/libcpu/aarch64/common/backtrace.c +++ b/libcpu/aarch64/common/backtrace.c @@ -56,13 +56,33 @@ void backtrace(unsigned long pc, unsigned long lr, unsigned long fp) rt_kprintf("\n"); } -int rt_backtrace(void) +int rt_backtrace_skipn(int level) { - unsigned long pc = (unsigned long)backtrace; - unsigned long ra = (unsigned long)__builtin_return_address(0U); - unsigned long fr = (unsigned long)__builtin_frame_address(0U); + unsigned long lr; + unsigned long fp = (unsigned long)__builtin_frame_address(0U); + + /* skip current frames */ + struct bt_frame frame; + frame.fp = fp; + + /* skip n frames */ + do + { + if (unwind_frame(&frame)) + return -RT_ERROR; + lr = frame.pc; + + /* INFO: level is signed integer */ + } while (level-- > 0); - backtrace(pc, ra, fr); + backtrace(0, lr, frame.fp); + return 0; +} + +int rt_backtrace(void) +{ + /* skip rt_backtrace itself */ + rt_backtrace_skipn(1); return 0; } -MSH_CMD_EXPORT_ALIAS(rt_backtrace, bt_test, backtrace test); +MSH_CMD_EXPORT_ALIAS(rt_backtrace, bt_test, backtrace test); \ No newline at end of file diff --git a/libcpu/aarch64/common/cpu.c b/libcpu/aarch64/common/cpu.c index d3291961a2bd..ea4eb7e103e1 100644 --- a/libcpu/aarch64/common/cpu.c +++ b/libcpu/aarch64/common/cpu.c @@ -84,9 +84,9 @@ rt_weak void rt_hw_cpu_shutdown() rt_pic_irq_finit(); /* Power management shutdown */ - if (rt_pm_shutdown) + if (rt_pm_machine_shutdown) { - rt_pm_shutdown(); + rt_pm_machine_shutdown(); } level = rt_hw_interrupt_disable(); @@ -107,9 +107,9 @@ rt_weak void rt_hw_cpu_reset() rt_pic_irq_finit(); /* Power management reset */ - if (rt_pm_reset) + if (rt_pm_machine_reset) { - rt_pm_reset(); + rt_pm_machine_reset(); } level = rt_hw_interrupt_disable(); diff --git a/libcpu/aarch64/common/cpuport.h b/libcpu/aarch64/common/cpuport.h index 2cc4e0b1fd87..282114f93d03 100644 --- a/libcpu/aarch64/common/cpuport.h +++ b/libcpu/aarch64/common/cpuport.h @@ -44,4 +44,35 @@ typedef union { #define sysreg_read(sysreg, val) \ __asm__ volatile ("mrs %0, "RT_STRINGIFY(sysreg)"":"=r"((val))) +rt_inline unsigned long __rt_clz(unsigned long word) +{ +#ifdef __GNUC__ + return __builtin_clz(word); +#else + unsigned long val; + + __asm__ volatile ("clz %0, %1" + :"=r"(val) + :"r"(word)); + + return val; +#endif +} + +rt_inline unsigned long __rt_ffsl(unsigned long word) +{ +#ifdef __GNUC__ + return __builtin_ffsl(word); +#else + if (!word) + { + return 0; + } + + __asm__ volatile ("rbit %0, %0" : "+r" (word)); + + return __rt_clz(word); +#endif +} + #endif /*CPUPORT_H__*/ diff --git a/libcpu/aarch64/common/mmu.c b/libcpu/aarch64/common/mmu.c index 6152428051cc..ceff4f799a31 100644 --- a/libcpu/aarch64/common/mmu.c +++ b/libcpu/aarch64/common/mmu.c @@ -489,10 +489,14 @@ int rt_hw_mmu_map_init(rt_aspace_t aspace, void *v_address, size_t size, void mmu_tcr_init(void) { unsigned long val64; + unsigned long pa_range; val64 = 0x00447fUL; __asm__ volatile("msr MAIR_EL1, %0\n dsb sy\n" ::"r"(val64)); + __asm__ volatile ("mrs %0, ID_AA64MMFR0_EL1":"=r"(val64)); + pa_range = val64 & 0xf; /* PARange */ + /* TCR_EL1 */ val64 = (16UL << 0) /* t0sz 48bit */ | (0x0UL << 6) /* reserved */ @@ -508,7 +512,7 @@ void mmu_tcr_init(void) | (0x3UL << 26) /* t1 outer wb cacheable */ | (0x2UL << 28) /* t1 outer shareable */ | (0x2UL << 30) /* t1 4k */ - | (0x1UL << 32) /* 001b 64GB PA */ + | (pa_range << 32) /* PA range */ | (0x0UL << 35) /* reserved */ | (0x1UL << 36) /* as: 0:8bit 1:16bit */ | (0x0UL << 37) /* tbi0 */ @@ -584,26 +588,34 @@ static int _map_single_page_2M(unsigned long *lv0_tbl, unsigned long va, void *rt_ioremap_early(void *paddr, size_t size) { - static void *ttbr0 = RT_NULL; + size_t count; + rt_ubase_t base; + static void *tbl = RT_NULL; if (!size) { return RT_NULL; } - if (!ttbr0) + if (!tbl) { - __asm__ volatile ("mrs %0, ttbr0_el1":"=r"(ttbr0)); + tbl = rt_hw_mmu_tbl_get(); } - _map_single_page_2M(ttbr0, (unsigned long)paddr, (unsigned long)paddr, MMU_MAP_K_DEVICE); + count = (size + ARCH_SECTION_MASK) >> ARCH_SECTION_SHIFT; + base = (rt_ubase_t)paddr & (~ARCH_SECTION_MASK); - return paddr; -} + while (count --> 0) + { + if (_map_single_page_2M(tbl, base, base, MMU_MAP_K_DEVICE)) + { + return RT_NULL; + } -void rt_iounmap_early(void *vaddr, size_t size) -{ + base += ARCH_SECTION_SIZE; + } + return paddr; } static int _init_map_2M(unsigned long *lv0_tbl, unsigned long va, diff --git a/libcpu/aarch64/common/setup.c b/libcpu/aarch64/common/setup.c index d1fe9d305d5a..ed74090cb5e1 100644 --- a/libcpu/aarch64/common/setup.c +++ b/libcpu/aarch64/common/setup.c @@ -21,10 +21,14 @@ #ifdef RT_USING_DFS #include +#ifdef RT_USING_DFS_DIRECTFS +#include +#endif #endif #ifdef RT_USING_SMART #include #endif +#include #include #include #include @@ -93,6 +97,68 @@ void rt_hw_console_output(const char *str) rt_fdt_earlycon_output(str); } +#ifdef RT_USING_HWTIMER +static rt_ubase_t loops_per_tick[RT_CPUS_NR]; + +static rt_ubase_t cpu_get_cycles(void) +{ + rt_ubase_t cycles; + + sysreg_read(cntpct_el0, cycles); + + return cycles; +} + +static void cpu_loops_per_tick_init(void) +{ + rt_ubase_t offset; + volatile rt_ubase_t freq, step, cycles_end1, cycles_end2; + volatile rt_uint32_t cycles_count1 = 0, cycles_count2 = 0; + + sysreg_read(cntfrq_el0, freq); + step = freq / RT_TICK_PER_SECOND; + + cycles_end1 = cpu_get_cycles() + step; + + while (cpu_get_cycles() < cycles_end1) + { + __asm__ volatile ("nop"); + __asm__ volatile ("add %0, %0, #1":"=r"(cycles_count1)); + } + + cycles_end2 = cpu_get_cycles() + step; + + while (cpu_get_cycles() < cycles_end2) + { + __asm__ volatile ("add %0, %0, #1":"=r"(cycles_count2)); + } + + if ((rt_int32_t)(cycles_count2 - cycles_count1) > 0) + { + offset = cycles_count2 - cycles_count1; + } + else + { + /* Impossible, but prepared for any eventualities */ + offset = cycles_count2 / 4; + } + + loops_per_tick[rt_hw_cpu_id()] = offset; +} + +static void cpu_us_delay(rt_uint32_t us) +{ + volatile rt_base_t start = cpu_get_cycles(), cycles; + + cycles = ((us * 0x10c7UL) * loops_per_tick[rt_hw_cpu_id()] * RT_TICK_PER_SECOND) >> 32; + + while ((cpu_get_cycles() - start) < cycles) + { + rt_hw_cpu_relax(); + } +} +#endif /* RT_USING_HWTIMER */ + rt_weak void rt_hw_idle_wfi(void) { __asm__ volatile ("wfi"); @@ -103,7 +169,7 @@ static void system_vectors_init(void) rt_hw_set_current_vbar((rt_ubase_t)&system_vectors); } -static void cpu_info_init(void) +rt_inline void cpu_info_init(void) { int i = 0; rt_uint64_t mpidr; @@ -150,6 +216,56 @@ static void cpu_info_init(void) } rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, rt_cpu_mpidr_table, sizeof(rt_cpu_mpidr_table)); + +#ifdef RT_USING_HWTIMER + cpu_loops_per_tick_init(); + + if (!rt_device_hwtimer_us_delay) + { + rt_device_hwtimer_us_delay = &cpu_us_delay; + } +#endif /* RT_USING_HWTIMER */ +} + +rt_inline void directfs_init(void) +{ +#ifdef RT_USING_DFS_DIRECTFS + static char *directfs_root[] = + { + "bus", + "firmware", + }; + static struct rt_object objs[RT_ARRAY_SIZE(directfs_root)]; + + for (int i = 0; i < RT_ARRAY_SIZE(directfs_root); ++i) + { + dfs_directfs_create_link(RT_NULL, &objs[i], directfs_root[i]); + } +#endif +} + +rt_inline rt_bool_t is_kernel_aspace(const char *name) +{ + static char * const names[] = + { + "kernel", + "memheap", + }; + + if (!name) + { + return RT_FALSE; + } + + for (int i = 0; i < RT_ARRAY_SIZE(names); ++i) + { + if (!rt_strcmp(names[i], name)) + { + return RT_TRUE; + } + } + + return RT_FALSE; } void rt_hw_common_setup(void) @@ -203,19 +319,19 @@ void rt_hw_common_setup(void) #else /* * The bootloader doesn't know the region of our memheap so maybe load the - * device tree to the memheap, it's safety to move to the end of memheap + * device tree to the memheap, it's safety to move to the end of the memheap */ if (memheap_end && fdt_ptr > kernel_start) { - rt_memmove(memheap_end, fdt_ptr - PV_OFFSET, fdt_size); + rt_memmove(memheap_end - PV_OFFSET, fdt_ptr - PV_OFFSET, fdt_size); fdt_ptr = memheap_end; - /* Now, we use page in the end of fdt */ + /* Now, we use the page in the end of the fdt */ page_best_start = (rt_size_t)fdt_ptr + fdt_size; } - /* Reserved fdt region */ + /* Reserved the fdt region */ rt_fdt_commit_memregion_early(&(rt_region_t) { .name = "fdt", @@ -223,12 +339,12 @@ void rt_hw_common_setup(void) .end = (rt_size_t)(fdt_ptr + fdt_size), }, RT_TRUE); - /* Fixup fdt pointer to kernel address space */ + /* Fixup the fdt pointer to kernel address space */ fdt_ptr -= PV_OFFSET; #endif /* !RT_USING_BUILTIN_FDT */ - /* Reserved kernel image region */ + /* Reserved the kernel image region */ rt_fdt_commit_memregion_early(&(rt_region_t) { .name = "kernel", @@ -250,13 +366,13 @@ void rt_hw_common_setup(void) /* Reserved your memory block before here */ rt_fdt_scan_memory(); - /* Init system memheap */ + /* Init the system memheap */ if (memheap_start && memheap_end) { rt_system_heap_init(memheap_start - PV_OFFSET, memheap_end - PV_OFFSET); } - /* Find SoC memory limit */ + /* Find the SoC memory limit */ platform_mem_region.start = ~0UL; platform_mem_region.end = 0; @@ -266,14 +382,17 @@ void rt_hw_common_setup(void) while (mem_region_nr --> 0) { - if (platform_mem_region.start > mem_region->start) - { - platform_mem_region.start = mem_region->start; - } - - if (platform_mem_region.end < mem_region->end) + if (is_kernel_aspace(mem_region->name)) { - platform_mem_region.end = mem_region->end; + if (platform_mem_region.start > mem_region->start) + { + platform_mem_region.start = mem_region->start; + } + + if (platform_mem_region.end < mem_region->end) + { + platform_mem_region.end = mem_region->end; + } } LOG_I(" %-*.s [%p, %p]", RT_NAME_MAX, mem_region->name, mem_region->start, mem_region->end); @@ -289,7 +408,7 @@ void rt_hw_common_setup(void) LOG_I("Usable memory:"); - /* Now, we will find the best page region by for each usable memory */ + /* Now, we will find the best page region by for each the usable memory */ for (int i = 0; i < mem_region_nr; ++i, ++mem_region) { if (!mem_region->name) @@ -320,26 +439,29 @@ void rt_hw_common_setup(void) LOG_I(" %-*.s [%p, %p]", RT_NAME_MAX, mem_region->name, mem_region->start, mem_region->end); } - /* Init kernel page pool */ + /* Init the kernel page pool */ RT_ASSERT(page_region != RT_NULL); init_page_region.start = page_region->start - PV_OFFSET; init_page_region.end = page_region->end - PV_OFFSET; rt_page_init(init_page_region); - /* Init mmu address space config */ + /* Init the mmu address space config */ + platform_mem_region.start = RT_ALIGN(platform_mem_region.start, ARCH_PAGE_SIZE); + platform_mem_region.end = RT_ALIGN_DOWN(platform_mem_region.end, ARCH_PAGE_SIZE); RT_ASSERT(platform_mem_region.end - platform_mem_region.start != 0); platform_mem_desc.paddr_start = platform_mem_region.start; platform_mem_desc.vaddr_start = platform_mem_region.start - PV_OFFSET; platform_mem_desc.vaddr_end = platform_mem_region.end - PV_OFFSET - 1; platform_mem_desc.attr = NORMAL_MEM; + rt_hw_mmu_setup(&rt_kernel_space, &platform_mem_desc, 1); /* MMU config was changed, update the mmio map in earlycon */ rt_fdt_earlycon_kick(FDT_EARLYCON_KICK_UPDATE); - /* Install all usable memory to memory system */ + /* Install all usable memory into memory system */ mem_region = usable_mem_region; for (int i = 0; i < mem_region_nr; ++i, ++mem_region) @@ -351,11 +473,13 @@ void rt_hw_common_setup(void) } } + directfs_init(); + rt_fdt_unflatten(); cpu_info_init(); - /* Init hardware interrupt */ + /* Init the hardware interrupt */ rt_pic_init(); rt_hw_interrupt_init(); @@ -375,7 +499,7 @@ void rt_hw_common_setup(void) rt_thread_idle_sethook(rt_hw_idle_wfi); #ifdef RT_USING_SMP - /* install IPI handle */ + /* Install the IPI handle */ rt_hw_ipi_handler_install(RT_SCHEDULE_IPI, rt_scheduler_ipi_handler); rt_hw_ipi_handler_install(RT_STOP_IPI, rt_scheduler_ipi_handler); rt_hw_interrupt_umask(RT_SCHEDULE_IPI); @@ -387,8 +511,17 @@ void rt_hw_common_setup(void) static int rootfs_mnt_init(void) { void *fsdata = RT_NULL; + const char *cpio_type = "cpio"; const char *dev = rt_ofw_bootargs_select("root=", 0); const char *fstype = rt_ofw_bootargs_select("rootfstype=", 0); + const char *rw = rt_ofw_bootargs_select("rw", 0); + +#ifdef RT_USING_DFS_DIRECTFS + if (!dfs_mount(RT_NULL, "/direct", "direct", 0, 0)) + { + LOG_I("Mount %s %s%s type=%s %s", "direct", "/direct", "", "direct", "done"); + } +#endif if ((!dev || !fstype) && initrd_ranges[0] && initrd_ranges[1]) { @@ -399,20 +532,83 @@ static int rootfs_mnt_init(void) if (fsdata) { - fstype = "cpio"; + fstype = cpio_type; initrd_ranges[3] = (rt_uint64_t)fsdata; } } + if (fstype != cpio_type && dev) + { + rt_tick_t timeout = 0; + const char *rootwait, *rootdelay = RT_NULL; + + rootwait = rt_ofw_bootargs_select("rootwait", 0); + + /* Maybe it is undefined or 'rootwaitABC' */ + if (!rootwait || *rootwait) + { + rootdelay = rt_ofw_bootargs_select("rootdelay=", 0); + + if (rootdelay) + { + timeout = rt_tick_from_millisecond(atoi(rootdelay)); + } + + rootwait = RT_NULL; + } + + /* + * Delays in boot flow is a terrible behavior in RTOS, but the RT-Thread + * SDIO framework init the devices in a task that we need to wait for + * SDIO devices to init complete... + * + * WHAT THE F*CK PROBLEMS WILL HAPPENED? + * + * Your main PE, applications, services that depend on the root FS and + * the multi cores setup, init will delay, too... + * + * So, you can try to link this function to `INIT_APP_EXPORT` even later + * and remove the delays if you want to optimize the boot time and mount + * the FS auto. + */ + for (; rootdelay || rootwait; --timeout) + { + if (!rootwait && timeout == 0) + { + LOG_E("Wait for /dev/%s init time out", dev); + + /* + * We don't return at once because the device driver may init OK + * when we break from this point, might as well give it another + * try. + */ + break; + } + + if (rt_device_find(dev)) + { + break; + } + + rt_thread_mdelay(1); + } + } + if (fstype) { - if (!dfs_mount(dev, "/", fstype, 0, fsdata)) + if (!dfs_mount(dev, "/", fstype, rw ? 0 : ~0, fsdata)) { - LOG_I("Mount root %s%s type=%s %s", dev ? "on /dev/" : "", dev ? dev : "", fstype, "done"); + LOG_I("Mount root %s%s type=%s %s", + (dev && *dev) ? "on /dev/" : "", + (dev && *dev) ? dev : "\b", + fstype, "done"); } else { - LOG_W("Mount root %s%s type=%s %s", dev ? "on /dev/" : "", dev ? dev : "", fstype, "fail"); + LOG_W("Mount root %s%s type=%s %s", + (dev && *dev) ? "on /dev/" : "", + (dev && *dev) ? dev : "\b", + fstype, "fail"); } } @@ -486,6 +682,13 @@ rt_weak void secondary_cpu_c_start(void) LOG_I("Call cpu %d on %s", cpu_id, "success"); +#ifdef RT_USING_HWTIMER + if (rt_device_hwtimer_us_delay == &cpu_us_delay) + { + cpu_loops_per_tick_init(); + } +#endif + rt_system_scheduler_start(); } diff --git a/libcpu/aarch64/common/stack.c b/libcpu/aarch64/common/stack.c index eaa9a4d1588b..19b3e5cb00d9 100644 --- a/libcpu/aarch64/common/stack.c +++ b/libcpu/aarch64/common/stack.c @@ -31,38 +31,12 @@ rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, stk = (rt_ubase_t *)stack_addr; - *(--stk) = (rt_ubase_t)0; /* Q0 */ - *(--stk) = (rt_ubase_t)0; /* Q0 */ - *(--stk) = (rt_ubase_t)0; /* Q1 */ - *(--stk) = (rt_ubase_t)0; /* Q1 */ - *(--stk) = (rt_ubase_t)0; /* Q2 */ - *(--stk) = (rt_ubase_t)0; /* Q2 */ - *(--stk) = (rt_ubase_t)0; /* Q3 */ - *(--stk) = (rt_ubase_t)0; /* Q3 */ - *(--stk) = (rt_ubase_t)0; /* Q4 */ - *(--stk) = (rt_ubase_t)0; /* Q4 */ - *(--stk) = (rt_ubase_t)0; /* Q5 */ - *(--stk) = (rt_ubase_t)0; /* Q5 */ - *(--stk) = (rt_ubase_t)0; /* Q6 */ - *(--stk) = (rt_ubase_t)0; /* Q6 */ - *(--stk) = (rt_ubase_t)0; /* Q7 */ - *(--stk) = (rt_ubase_t)0; /* Q7 */ - *(--stk) = (rt_ubase_t)0; /* Q8 */ - *(--stk) = (rt_ubase_t)0; /* Q8 */ - *(--stk) = (rt_ubase_t)0; /* Q9 */ - *(--stk) = (rt_ubase_t)0; /* Q9 */ - *(--stk) = (rt_ubase_t)0; /* Q10 */ - *(--stk) = (rt_ubase_t)0; /* Q10 */ - *(--stk) = (rt_ubase_t)0; /* Q11 */ - *(--stk) = (rt_ubase_t)0; /* Q11 */ - *(--stk) = (rt_ubase_t)0; /* Q12 */ - *(--stk) = (rt_ubase_t)0; /* Q12 */ - *(--stk) = (rt_ubase_t)0; /* Q13 */ - *(--stk) = (rt_ubase_t)0; /* Q13 */ - *(--stk) = (rt_ubase_t)0; /* Q14 */ - *(--stk) = (rt_ubase_t)0; /* Q14 */ - *(--stk) = (rt_ubase_t)0; /* Q15 */ - *(--stk) = (rt_ubase_t)0; /* Q15 */ + for (int i = 0; i < 32; ++i) + { + stk -= sizeof(rt_uint128_t) / sizeof(rt_ubase_t); + + *(rt_uint128_t *)stk = (rt_uint128_t) { 0 }; + } *(--stk) = (rt_ubase_t)1; /* X1 */ *(--stk) = (rt_ubase_t)parameter; /* X0 */ diff --git a/libcpu/aarch64/cortex-a/entry_point.S b/libcpu/aarch64/cortex-a/entry_point.S index 969b48230f15..42e18b941a7b 100644 --- a/libcpu/aarch64/cortex-a/entry_point.S +++ b/libcpu/aarch64/cortex-a/entry_point.S @@ -10,7 +10,9 @@ * 2023-06-04 GuEe-GUI support cpu init by device-tree */ +#ifndef __ASSEMBLY__ #define __ASSEMBLY__ +#endif #include #include @@ -84,13 +86,9 @@ _start: b init_mmu_early kernel_start: - /* Set sp to current cpu's stack top to visual address */ - get_pvoff x1 x0 - mov x1, stack_top - add x1, x1, x0 - mov sp, x1 - /* jump to the PE's system entry */ + mov x29, xzr + mov x30, x8 br x8 cpu_idle: @@ -260,6 +258,15 @@ enable_mmu_early: bl mmu_tcr_init + /* + * OK, now, we don't use sp before jump to kernel, set sp to current cpu's + * stack top to visual address + */ + get_pvoff x1 x0 + mov x1, stack_top + sub x1, x1, x0 + mov sp, x1 + ldr x30, =kernel_start /* Set LR to kernel_start function, it's virtual addresses */ mrs x1, sctlr_el1 diff --git a/src/cpu.c b/src/cpu.c index 77ce65d69f05..def05cb9e18d 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -102,6 +102,32 @@ void rt_spin_lock(struct rt_spinlock *lock) } RTM_EXPORT(rt_spin_lock) +/** + * @brief This function will try to lock the spinlock. + * + * @note If the spinlock is locked, the current CPU will return error. + * + * @param lock is a pointer to the spinlock. + */ +rt_err_t rt_spin_trylock(struct rt_spinlock *lock) +{ + rt_err_t err; +#ifdef RT_USING_SMP + _cpu_preempt_disable(); + + if ((err = rt_hw_spin_trylock(&lock->lock))) + { + _cpu_preempt_enable(); + } +#else + rt_enter_critical(); + err = RT_EOK; +#endif + + return err; +} +RTM_EXPORT(rt_spin_trylock) + /** * @brief This function will unlock the spinlock. * @@ -145,6 +171,36 @@ rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock) } RTM_EXPORT(rt_spin_lock_irqsave) +#ifdef RT_USING_SMP +/** + * @brief This function will try to lock the spinlock. + * + * @note If the spinlock is locked, the current CPU will return error. + * + * @param lock is a pointer to the spinlock. + */ +rt_err_t rt_spin_trylock_irqsave(struct rt_spinlock *lock, rt_ubase_t *out_level) +{ + rt_err_t res; + + rt_ubase_t level = rt_hw_local_irq_disable(); + + RT_ASSERT(out_level != RT_NULL); + res = rt_spin_trylock(lock); + + if (!res) + { + *out_level = level; + } + else + { + rt_hw_local_irq_enable(level); + } + + return res; +} +#endif + /** * @brief This function will unlock the spinlock and then restore current cpu interrupt status. * diff --git a/tools/building.py b/tools/building.py index 9d661ad2cda8..99ecc83cd1ca 100644 --- a/tools/building.py +++ b/tools/building.py @@ -802,7 +802,9 @@ def local_group(group, objects): CCFLAGS = Env.get('CCFLAGS', '') + group.get('LOCAL_CCFLAGS', '') CXXFLAGS = Env.get('CXXFLAGS', '') + group.get('LOCAL_CXXFLAGS', '') CPPPATH = Env.get('CPPPATH', ['']) + group.get('LOCAL_CPPPATH', ['']) - CPPDEFINES = Env.get('CPPDEFINES', ['']) + group.get('LOCAL_CPPDEFINES', ['']) + CPPDEFINES = Env.get('CPPDEFINES', ['']) + if len(group.get('LOCAL_CPPDEFINES', [''])) != 0: + CPPDEFINES += group.get('LOCAL_CPPDEFINES', ['']) ASFLAGS = Env.get('ASFLAGS', '') + group.get('LOCAL_ASFLAGS', '') for source in group['src']: diff --git a/tools/dtc.py b/tools/dtc.py index b80e279bebc8..0e63518b4e2c 100644 --- a/tools/dtc.py +++ b/tools/dtc.py @@ -25,4 +25,4 @@ def dts_to_dtb(RTT_ROOT, dts_list): dtb = path + dts.replace('.dts', '.dtb') dts = path + dts if not os.path.exists(dtb) or os.path.getmtime(dtb) < os.path.getmtime(dts): - os.system("\"{}\" -I dts -O dtb {} -o {}".format(dtc_cmd, dts, dtb)) + os.system("\"{}\" -I dts -O dtb -@ -A {} -o {}".format(dtc_cmd, dts, dtb))