diff --git a/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml new file mode 100644 index 00000000000000..6cef956d33d25e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/bouffalolab,uart.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022 Jisheng Zhang +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/serial/bouffalolab,uart.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Bouffalolab UART Controller + +maintainers: + - Jisheng Zhang + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: bouffalolab,uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + aliases { + serial0 = &uart0; + }; + + uart0: serial@30002000 { + compatible = "bouffalolab,uart"; + reg = <0x30002000 0x1000>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 135d93368d36ed..a8ee2a529ecb54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17975,6 +17975,12 @@ F: arch/riscv/ N: riscv K: riscv +RISC-V BOUFFALOLAB SOC SUPPORT +M: Jisheng Zhang +L: linux-riscv at lists.infradead.org +S: Maintained +F: arch/riscv/boot/dts/bouffalolab/ + RISC-V MICROCHIP FPGA SUPPORT M: Conor Dooley M: Daire McNamara diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 4b6deb2715f1c4..a68ab2172230e5 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -1,5 +1,11 @@ menu "SoC selection" +config SOC_BOUFFALOLAB + bool "Bouffalolab SoCs" + select SIFIVE_PLIC + help + This enables support for Bouffalolab SoC platforms. + config SOC_MICROCHIP_POLARFIRE bool "Microchip PolarFire SoCs" select MCHP_CLK_MPFS diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index b0ff5fbabb0c9a..2d4376810bcc75 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +subdir-y += bouffalolab subdir-y += sifive subdir-y += starfive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan diff --git a/arch/riscv/boot/dts/bouffalolab/Makefile b/arch/riscv/boot/dts/bouffalolab/Makefile new file mode 100644 index 00000000000000..bc7aad3d560406 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-sipeed-m1s.dtb +dtb-$(CONFIG_SOC_BOUFFALOLAB) += bl808-pine64-ox64.dtb diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts new file mode 100644 index 00000000000000..50ca13e8e68e67 --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-pine64-ox64.dts @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" + +/ { + model = "Pine64 Ox64"; + compatible = "pine64,ox64", "bflb,bl808"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&pinctrl { + status = "okay"; +}; + +&seceng { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&sdhci0 { + status = "okay"; +}; + +&ipclic { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&enet0 { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts new file mode 100644 index 00000000000000..e22a162932424f --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808-sipeed-m1s.dts @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +/dts-v1/; + +#include "bl808.dtsi" +#include +#include + +/ { + model = "Sipeed M1s"; + compatible = "sipeed,m1s", "bflb,bl808"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:2000000n8"; + bootargs = "console=ttyS0,2000000 loglevel=8 earlycon=sbi root=/dev/mmcblk0p2 rootwait rootfstype=ext4"; + linux,initrd-start = <0x0 0x52000000>; + linux,initrd-end = <0x0 0x52941784>; + }; + + memory@50000000 { + device_type = "memory"; + reg = <0x50000000 0x04000000>; + }; + + xip_flash@58500000 { + compatible = "mtd-rom"; + reg = <0x58500000 0x400000>; + linux,mtd-name = "xip-flash.0"; + erase-size = <0x10000>; + bank-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + }; + + leds { + compatible = "gpio-leds"; + + led { + gpios = <&pinctrl 8 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&pinctrl { + status = "okay"; + + led { + pins = "GPIO8"; + function = "gpio"; + }; +}; + +&seceng { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&sdhci0 { + status = "okay"; +}; + +&ipclic { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&enet0 { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/bouffalolab/bl808.dtsi b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi new file mode 100644 index 00000000000000..c3617b61e0adaf --- /dev/null +++ b/arch/riscv/boot/dts/bouffalolab/bl808.dtsi @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2022 Jisheng Zhang + */ + +#include +#include + +/ { + compatible = "bflb,bl808"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + timebase-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "thead,c906", "riscv"; + device_type = "cpu"; + reg = <0>; + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <32768>; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <32768>; + mmu-type = "riscv,sv39"; + riscv,isa = "rv64imafdc"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + sdh: sdh-clk { + compatible = "fixed-clock"; + clock-frequency = <96000000>; + clock-output-names = "sdh"; + #clock-cells = <0>; + }; + + enet: enet-clk { + compatible = "fixed-clock"; + clock-frequency = <50000000>; + clock-output-names = "enet"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + ranges; + interrupt-parent = <&plic>; + dma-noncoherent; + #address-cells = <1>; + #size-cells = <1>; + + pinctrl: pinctrl@0x200008C4 { + compatible = "bflb,pinctrl"; + //Last register is for gpio_cfg141 at 0x20000af8 + reg = <0x200008C4 0x1000>; + //clocks = <&gpio_clk>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 46>; + bflb,npins = <46>; + + status = "disabled"; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_GPIO IRQ_TYPE_EDGE_RISING>; + + sdh_pins: sdh-pins { + pins = "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5"; + function = "sdh"; + }; + }; + + seceng: seceng@0x20004000 { + compatible = "bflb,seceng"; + reg = <0x20004000 0x1000>; + status = "disabled"; + }; + + uart0: serial@30002000 { + compatible = "bflb,bl808-uart"; + reg = <0x30002000 0x1000>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&xtal>; + status = "disabled"; + }; + + uart1: serial@0x2000AA00 { + compatible = "bflb,bl808-uart"; + reg = <0x2000AA00 0x0100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_UART2 + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_UART2>; + clocks = <&xtal>; + status = "disabled"; + }; + + sdhci0: sdhci@20060000 { + compatible = "bflb,bl808-sdhci"; + reg = <0x20060000 0x100>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_SDHCI + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipclic BFLB_IPC_SOURCE_M0 BFLB_IPC_DEVICE_SDHCI>; + clocks = <&sdh>; + status = "disabled"; + }; + + ehci0: usb@20072000 { + compatible = "generic-ehci"; + reg = <0x20072000 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_USB + IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + enet0: emac@20070000 { + compatible = "opencores,ethoc"; + reg = <0x20070000 0x1000>; + interrupts-extended = <&ipclic BFLB_IPC_SOURCE_M0 + BFLB_IPC_DEVICE_EMAC + IRQ_TYPE_EDGE_RISING>; + clocks = <&enet>; + status = "disabled"; + }; + + wdt: wdt@2000a500 { + compatible = "bflb,bl808-wdt"; + reg = <0x2000a500 0x100>; + status = "disabled"; + }; + + ipclic: mailbox@30005000 { + compatible = "bflb,bl808-ipc"; + reg = <0x30005000 0x20>, + <0x30005020 0x20>, + <0x2000a800 0x20>, + <0x2000a820 0x20>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + status = "disabled"; + }; + + plic: interrupt-controller@e0000000 { + compatible = "thead,c900-plic"; + reg = <0xe0000000 0x4000000>; + interrupts-extended = <&cpu0_intc 0xffffffff>, + <&cpu0_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <64>; + }; + + clint: timer@e4000000 { + compatible = "thead,c900-clint"; + reg = <0xe4000000 0xc000>; + interrupts-extended = <&cpu0_intc 3>, + <&cpu0_intc 7>; + }; + }; +}; diff --git a/arch/riscv/configs/bl808_defconfig b/arch/riscv/configs/bl808_defconfig new file mode 100644 index 00000000000000..f19f0e2e37d994 --- /dev/null +++ b/arch/riscv/configs/bl808_defconfig @@ -0,0 +1,216 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_GENERIC_IRQ_DEBUGFS=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +CONFIG_SOC_BOUFFALOLAB=y +CONFIG_SOC_VIRT=y +CONFIG_ERRATA_THEAD=y +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_RISCV_SBI_V01=y +# CONFIG_COMPAT is not set +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_PAGE_REPORTING=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_DNS_RESOLVER=y +CONFIG_NETLINK_DIAG=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK_RO=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_ROM=y +CONFIG_MTD_ABSENT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PHYSMAP_VERSATILE=y +CONFIG_MTD_PHYSMAP_GEMINI=y +CONFIG_MTD_PLATRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_VIRTIO_BLK=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_VIRTIO=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_ASIX is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_DAVICOM is not set +# CONFIG_NET_VENDOR_ENGLEDER is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FUNGIBLE is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_WANGXUN is not set +# CONFIG_NET_VENDOR_LITEX is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +CONFIG_ETHOC=y +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VERTEXCOM is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +# CONFIG_WLAN is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_BFLB=y +CONFIG_SERIAL_BFLB_CONSOLE=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_XILINX=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +CONFIG_I2C_DEBUG_BUS=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_BFLB_GPIO=y +CONFIG_GPIO_SYSFS=y +CONFIG_FB=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_HID_CHICONY=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_BFLB=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_USER=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_MTD=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_ACTIVITY=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_TRANSIENT=y +CONFIG_LEDS_TRIGGER_CAMERA=y +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_NETDEV=y +CONFIG_LEDS_TRIGGER_PATTERN=y +CONFIG_LEDS_TRIGGER_AUDIO=y +CONFIG_LEDS_TRIGGER_TTY=y +CONFIG_RTC_CLASS=y +CONFIG_SYNC_FILE=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +CONFIG_MAILBOX=y +CONFIG_BFLB_IPC=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_VIRTIO=y +CONFIG_GENERIC_PHY=y +CONFIG_EXT4_FS=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +# CONFIG_EFIVAR_FS is not set +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_KEYS=y +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_DEV_BFLB_SECENG=y +CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_XZ_DEC=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_VM_PGTABLE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_TIMEKEEPING=y +# CONFIG_FTRACE is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_RUNTIME_TESTING_MENU is not set +CONFIG_MEMTEST=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_BFLB_WATCHDOG=y diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0bc40b763b0652..8df5e1d38752a3 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -181,6 +181,17 @@ config BD957XMUF_WATCHDOG watchdog. Alternatively say M to compile the driver as a module, which will be called bd9576_wdt. +config BFLB_WATCHDOG + tristate "BFLB BL808 Watchdog" + depends on SOC_BOUFFALOLAB + select WATCHDOG_CORE + help + Support for the watchdog on BL808. + + Say Y here to include support for the BL808 watchdog. + Alternately say M to compile the driver as a module, + which will be called bflb_wdt. + config DA9052_WATCHDOG tristate "Dialog DA9052 Watchdog" depends on PMIC_DA9052 || COMPILE_TEST diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 9cbf6580f16c9f..736e7224fe4a6e 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -192,6 +192,9 @@ obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o +# RISC-V Architecture +obj-$(CONFIG_BFLB_WATCHDOG) += bflb_wdt.o + # S390 Architecture obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o diff --git a/drivers/watchdog/bflb_wdt.c b/drivers/watchdog/bflb_wdt.c new file mode 100644 index 00000000000000..27fbb877ad76fd --- /dev/null +++ b/drivers/watchdog/bflb_wdt.c @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Settings here get us the slowest possible clock speed on the hardware +// which is the closest we can get to the linux watchdog's resolution of +// 1 second. +#define BFLB_INT_TICKS_PER_SEC 1024 +#define BFLB_TICK_CLKDIV 256 +#define BFLB_TICKS_PER_SEC ( BFLB_INT_TICKS_PER_SEC / BFLB_TICK_CLKDIV ) +#define BFLB_MAX_SECS ( 65535 / BFLB_TICKS_PER_SEC ) + +#define BFLB_DEFAULT_TIMEOUT 60 + +#define BFLB_REG_BASE 0x2000A500 + +#define BFLB_REG_WFAR 0x9C +#define BFLB_WFAR_MAGIC 0xBABA + +#define BFLB_REG_WSAR 0xA0 +#define BFLB_WSAR_MAGIC 0xEB10 + +#define BFLB_REG_WVR 0x6C +#define BFLB_REG_WCR 0x98 +#define BFLB_WCR_RESET_COUNTER BIT(0) + +#define BFLB_REG_WMER 0x64 +#define BFLB_WMER_WATCHDOG_ENABLE BIT(0) +#define BFLB_WMER_RESET_SOURCE BIT(1) + +#define BFLB_REG_TCCR 0x00 +#define BFLB_SHIFT_CS_WDT 8 +#define BFLB_MASK_CS_WDT GENMASK(BFLB_SHIFT_CS_WDT+3,BFLB_SHIFT_CS_WDT) +#define BFLB_TCCR_CS_FCLK (0x0 << BFLB_SHIFT_CS_WDT) +#define BFLB_TCCR_CS_32K (0x1 << BFLB_SHIFT_CS_WDT) +#define BFLB_TCCR_CS_1K (0x2 << BFLB_SHIFT_CS_WDT) +#define BFLB_TCCR_CS_32M (0x3 << BFLB_SHIFT_CS_WDT) +#define BFLB_TCCR_CS_GPIO (0x4 << BFLB_SHIFT_CS_WDT) + +#define BFLB_REG_TCDR 0xbc +#define BFLB_SHIFT_WDT_CLKDIV 24 +#define BFLB_MASK_TCDR GENMASK(BFLB_SHIFT_WDT_CLKDIV+7,BFLB_SHIFT_WDT_CLKDIV) + +// CLKDIV is an eight bit counter, but the counter is +// zero indexed, so subtract 1 before setting +#define BFLB_TCDR_CLKDIV ((BFLB_TICK_CLKDIV - 1) << BFLB_SHIFT_WDT_CLKDIV) + +#define BFLB_REG_WMR 0x68 +#define BFLB_MASK_WMR GENMASK(15,0) + +struct bflb_watchdog_device { + struct watchdog_device wdd; + struct device *dev; + void __iomem *regs; +}; + +static inline +struct bflb_watchdog_device *to_bflb_wdd(struct watchdog_device *wdd) +{ + return container_of(wdd, struct bflb_watchdog_device, wdd); +} + +// Access key registers must be written before write +// operations presumably to prevent accidentally enabling +// the watchdog and killing the machine. +static inline int bflb_unlock_watchdog(struct bflb_watchdog_device *bflb_wdd) +{ + writew(BFLB_WFAR_MAGIC, bflb_wdd->regs + BFLB_REG_WFAR); + writew(BFLB_WSAR_MAGIC, bflb_wdd->regs + BFLB_REG_WSAR); + + return 0; +} + +static int bflb_wdt_ping(struct watchdog_device *wdd) +{ + uint32_t reg_val; + struct bflb_watchdog_device *bflb_wdd = to_bflb_wdd(wdd); + + dev_dbg(wdd->parent, "bflb_wdt_ping"); + bflb_unlock_watchdog(bflb_wdd); + reg_val = readl(bflb_wdd->regs + BFLB_REG_WCR); + reg_val |= BFLB_WCR_RESET_COUNTER; + writel(reg_val, bflb_wdd->regs + BFLB_REG_WCR); + + return 0; +}; + +static inline void bflb_wdt_update_timeout_reg(struct watchdog_device *wdd) +{ + unsigned int timeout_ticks; + struct bflb_watchdog_device *bflb_wdd = to_bflb_wdd(wdd); + + bflb_unlock_watchdog(bflb_wdd); + timeout_ticks = wdd->timeout * BFLB_TICKS_PER_SEC; + writew(timeout_ticks, bflb_wdd->regs + BFLB_REG_WMR); +} + +static int bflb_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + if (timeout >= wdd->max_timeout) { + dev_warn(wdd->parent, + "timeout %i > max_timeout %i, using max_timeout...", + timeout, wdd->max_timeout); + timeout = wdd->max_timeout; + } + + wdd->timeout = timeout; + + bflb_wdt_update_timeout_reg(wdd); + + dev_dbg(wdd->parent, "bflb_wdt_set_timeout (s=%i tps=%i)", + timeout, BFLB_TICKS_PER_SEC); + + return 0; +} + +static int bflb_wdt_start(struct watchdog_device *wdd) +{ + uint32_t reg_val; + struct bflb_watchdog_device *bflb_wdd = to_bflb_wdd(wdd); + + + // And enable the watchdog + bflb_unlock_watchdog(bflb_wdd); + reg_val = readl(bflb_wdd->regs + BFLB_REG_WMER); + reg_val |= BFLB_WMER_WATCHDOG_ENABLE; + writel(reg_val, bflb_wdd->regs + BFLB_REG_WMER); + + dev_info(wdd->parent, "bflb_wdt_start started..."); + + return 0; +} + +static int bflb_wdt_stop(struct watchdog_device *wdd) +{ + uint32_t reg_val; + struct bflb_watchdog_device *bflb_wdd = to_bflb_wdd(wdd); + + // disable + bflb_unlock_watchdog(bflb_wdd); + reg_val = readl(bflb_wdd->regs + BFLB_REG_WMER); + reg_val &= ~BFLB_WMER_WATCHDOG_ENABLE; + writel(reg_val, bflb_wdd->regs + BFLB_REG_WMER); + + dev_info(wdd->parent, "bflb_wdt_stopped..."); + + return 0; +}; + + +static unsigned int bflb_wdt_timeleft(struct watchdog_device *wdd) +{ + unsigned int used_seconds; + unsigned int remaining_seconds; + unsigned int ticks; + struct bflb_watchdog_device *bflb_wdd = to_bflb_wdd(wdd); + + ticks = readw(bflb_wdd->regs + BFLB_REG_WVR); + + used_seconds = ticks / BFLB_TICKS_PER_SEC; + remaining_seconds = wdd->max_timeout - used_seconds; + dev_dbg(wdd->parent, "bflb_wdt_time left %i (elapsed tick %i, sec %i)", + remaining_seconds, ticks, used_seconds); + + return remaining_seconds; +}; + +static const struct watchdog_info bflb_wdt_info = { + .identity = "bflb_wdt", + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static const struct watchdog_ops bflb_wdt_ops = { + .start = bflb_wdt_start, + .stop = bflb_wdt_stop, + .ping = bflb_wdt_ping, + .set_timeout = bflb_wdt_set_timeout, + .get_timeleft = bflb_wdt_timeleft, +}; + + +static int __init bflb_wdt_probe(struct platform_device *pdev) +{ + struct bflb_watchdog_device *bflb_wdd; + struct watchdog_device *wdd; + int err; + uint32_t reg_val; + + dev_dbg(&pdev->dev, "bflb_wdt_probe started"); + + bflb_wdd = devm_kzalloc(&pdev->dev, sizeof(*bflb_wdd), GFP_KERNEL); + if (!bflb_wdd) return -ENOMEM; + + bflb_wdd->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bflb_wdd->regs)) + return PTR_ERR(bflb_wdd->regs); + + wdd = &bflb_wdd->wdd; + + wdd->info = &bflb_wdt_info; + wdd->ops = &bflb_wdt_ops; + + wdd->timeout = BFLB_DEFAULT_TIMEOUT; + wdd->max_timeout = BFLB_MAX_SECS; + wdd->min_timeout = 1; + wdd->parent = &pdev->dev; + + watchdog_stop_on_reboot(wdd); + watchdog_stop_on_unregister(wdd); + watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); + watchdog_init_timeout(wdd, BFLB_DEFAULT_TIMEOUT, &pdev->dev); + + // Setup registers + + // Set to reboot on watchdog, disable until we start + bflb_unlock_watchdog(bflb_wdd); + reg_val = readl(bflb_wdd->regs + BFLB_REG_WMER); + reg_val &= ~BFLB_WMER_WATCHDOG_ENABLE; + reg_val |= BFLB_WMER_RESET_SOURCE; + writel(reg_val, bflb_wdd->regs + BFLB_REG_WMER); + + // Set to 1K per second clock + reg_val = readl(bflb_wdd->regs + BFLB_REG_TCCR); + reg_val &= ~BFLB_MASK_CS_WDT; + reg_val |= BFLB_TCCR_CS_1K; + writel(reg_val, bflb_wdd->regs + BFLB_REG_TCCR); + + reg_val = readl(bflb_wdd->regs + BFLB_REG_TCDR); + reg_val &= ~BFLB_MASK_TCDR; + reg_val |= BFLB_TCDR_CLKDIV; + writel(reg_val, bflb_wdd->regs + BFLB_REG_TCDR); + + // Set last valid timeout value + bflb_wdt_update_timeout_reg(wdd); + + err = devm_watchdog_register_device(&pdev->dev, wdd); + if (err) return err; + + platform_set_drvdata(pdev, bflb_wdd); + + dev_info(&pdev->dev, "bflb_wdt_probe completed..."); + + return 0; +} + +static int __exit bflb_wdt_remove(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "bflb_wdt_remove removed..."); + + return 0; +} + +static const struct of_device_id bflb_wdt_match[] = { + { + .compatible = "bflb,bl808-wdt", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, bflb_wdt_match); + +static struct platform_driver bflb_wdt_driver = { + .probe = bflb_wdt_probe, + .remove = bflb_wdt_remove, + .driver = { + .name = "bflb_wdt", + .owner = THIS_MODULE, + .of_match_table = bflb_wdt_match, + .suppress_bind_attrs = true, + }, +}; + + +module_platform_driver(bflb_wdt_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("BL808 Watchdog support"); +MODULE_AUTHOR("Grant Olson + */ + +#ifndef __DT_BINDINGS_MAILBOX_BFLB_IPC_H +#define __DT_BINDINGS_MAILBOX_BFLB_IPC_H + +/* Source processor */ +#define BFLB_IPC_SOURCE_M0 0 +#define BFLB_IPC_SOURCE_LP 1 + +/* Peripheral device ID */ +#define BFLB_IPC_DEVICE_SDHCI 0 +#define BFLB_IPC_DEVICE_UART2 1 +#define BFLB_IPC_DEVICE_USB 2 +#define BFLB_IPC_DEVICE_EMAC 3 +#define BFLB_IPC_DEVICE_GPIO 4 + +#endif