diff --git a/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml b/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml new file mode 100644 index 00000000000000..9e88ac647ae2a7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jh7100-clkgen.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jh7100-clkgen.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 Clock Generator + +maintainers: + - FIXME + - Geert Uytterhoeven + +properties: + compatible: + const: starfive,jh7100-clkgen + + reg: + maxItems: 1 + + clocks: + items: + - description: Main clock source (default 25 MHz) + - description: Application-specific clock source (12-27 MHz) + + clock-names: + items: + - const: osc0 + - const: osc1 + + '#clock-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x11800000 0x10000>; + clocks = <&osc0_clk>, <&osc1_clk>; + clock-names = "osc0", "osc1"; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml index 79e241498e2532..09d3e9ee3939e1 100644 --- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml @@ -51,7 +51,7 @@ properties: dma-channels: minimum: 1 - maximum: 8 + maximum: 16 snps,dma-masters: description: | @@ -71,14 +71,14 @@ properties: Channel priority specifier associated with the DMA channels. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 - maxItems: 8 + maxItems: 16 snps,block-size: description: | Channel block size specifier associated with the DMA channels. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 - maxItems: 8 + maxItems: 16 snps,axi-max-burst-len: description: | diff --git a/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml b/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml new file mode 100644 index 00000000000000..8c9d14d9ac3b69 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/starfive,jh7100-gpio.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/starfive,jh7100-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 GPIO controller + +maintainers: + - Huan Feng + - Drew Fustini + +properties: + compatible: + items: + - const: starfive,jh7100-gpio + + reg: + maxItems: 1 + + interrupts: + description: + Interrupt mapping, one per GPIO. Maximum 32 GPIOs. + minItems: 1 + maxItems: 32 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - "#interrupt-cells" + - "#gpio-cells" + - gpio-controller + +additionalProperties: false + +examples: + - | + gpio@11910000 { + compatible = "starfive,jh7100-gpio"; + reg = <0x11910000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <32>; + }; + +... diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml new file mode 100644 index 00000000000000..5ca52c08d142e5 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/starfive,jh7100-temp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7100 Temperature Sensor + +maintainers: + - Emil Renner Berthing + +description: | + StarFive Technology Co. JH7100 embedded temperature sensor + +properties: + compatible: + enum: + - starfive,jh7100-temp + + reg: + maxItems: 1 + + '#thermal-sensor-cells': + const: 0 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + tmon: tmon@124a0000 { + compatible = "starfive,jh7100-temp"; + reg = <0x124a0000 0x10000>; + #thermal-sensor-cells = <0>; + interrupts = <122>; + }; diff --git a/Documentation/devicetree/bindings/riscv/starfive.yaml b/Documentation/devicetree/bindings/riscv/starfive.yaml new file mode 100644 index 00000000000000..4deae9f5c60d7c --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/starfive.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/starfive.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive SoC-based boards + +maintainers: + - Michael Zhu + - Drew Fustini + +description: + SiFive SoC-based boards + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - items: + - const: beagle,beaglev-starlight-jh7100 + - const: starfive,jh7100 + + - items: + - const: starfive,jh7100 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml index a407e1143cf425..8dedfa16c9929d 100644 --- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml +++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml @@ -28,9 +28,9 @@ properties: interrupts: minItems: 3 items: - - description: OTG/DRD controller interrupt - description: XHCI host controller interrupt - description: Device controller interrupt + - description: OTG/DRD controller interrupt - description: interrupt used to wake up core, e.g when usbcmd.rs is cleared by xhci core, this interrupt is optional diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index b868cefc7c5500..3dd6a42fbbad2b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1085,6 +1085,8 @@ patternProperties: (formerly part of MStar Semiconductor, Inc.) "^st,.*": description: STMicroelectronics + "^starfive,.*": + description: StarFive Technology Co. Ltd. "^starry,.*": description: Starry Electronic Technology (ShenZhen) Co., LTD "^startek,.*": diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 9ed60fa84cbec6..f23308e97d2e6f 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -161,6 +161,7 @@ Hardware Monitoring Kernel Drivers sch5627 sch5636 scpi-hwmon + sfctemp sht15 sht21 sht3x diff --git a/Documentation/hwmon/sfctemp.rst b/Documentation/hwmon/sfctemp.rst new file mode 100644 index 00000000000000..465edce2fea5e2 --- /dev/null +++ b/Documentation/hwmon/sfctemp.rst @@ -0,0 +1,32 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver sfctemp +===================== + +Supported chips: + - StarFive JH7100 + +Authors: + - Emil Renner Berthing + +Description +----------- + +This driver adds support for reading the built-in temperature sensor on the +JH7100 RISC-V SoC by StarFive Technology Co. Ltd. + +``sysfs`` interface +------------------- + +The temperature sensor can be enabled, disabled and queried via the standard +hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of +``X``: + +================ ==== ============================================= +Name Perm Description +================ ==== ============================================= +temp1_enable RW Enable or disable temperature sensor. + Automatically enabled by the driver, + but may be disabled to save power. +temp1_input RO Temperature reading in milli-degrees Celsius. +================ ==== ============================================= diff --git a/MAINTAINERS b/MAINTAINERS index 8c5ee008301a65..a7d25a67227092 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16535,6 +16535,14 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/sfc/ +SFCTEMP HWMON DRIVER +M: Emil Renner Berthing +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/starfive,jh7100-temp.yaml +F: Documentation/hwmon/sfctemp.rst +F: drivers/hwmon/sfctemp.c + SFF/SFP/SFP+ MODULE SUPPORT M: Russell King L: netdev@vger.kernel.org diff --git a/README.md b/README.md new file mode 100644 index 00000000000000..920d185c6ef935 --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +# Linux kernel for the BeagleV Starlight + +## What is this? + +The [BeagleV Starlight][bborg] board is a new Linux-capable 64bit RISC-V +development board. It has not shipped yet, but [beta versions][beta] are out to +developers. Consequently the board is not yet supported by upstream Linux. This +tree is meant to collect all the in-development patches for running Linux on +the board. + +[bborg]: https://beagleboard.org/beaglev +[beta]: https://github.com/beagleboard/beaglev-starlight + +## Cross-compiling + +Cross-compiling the Linux kernel is surprisingly easy since it doesn't depend +on any (target) libraries and most distributions already have packages with a +working cross-compiler. We'll also need a few other tools to build everything: +```shell +# Debian/Ubuntu +sudo apt-get install libncurses-dev libssl-dev bc flex bison make gcc gcc-riscv64-linux-gnu +# Fedora +sudo dnf install ncurses-devel openssl openssl-devel bc flex bison make gcc gcc-riscv64-linux-gnu +# Archlinux +sudo pacman -S --needed ncurses openssl bc flex bison make gcc riscv64-linux-gnu-gcc +``` + +The build system needs to know that we want to cross-compile a kernel for +RISC-V by setting `ARCH=riscv`. It also needs to know the prefix of our +cross-compiler using `CROSS_COMPILE=riscv64-linux-gnu-`. Also let's assume +we're building on an 8-core machine so compilation can be greatly sped up by +telling make to use all 8 cores with `-j8`. + +First we need to configure the kernel though. Linux has a *very* extensive +configuration system, but you can get a good baseline configuration for the +board using: +```shell +make -j8 ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- beaglev_defconfig +``` + +There is nothing magic about this configuration other than it has all the +drivers enabled that are working for the hardware on the board. In fact it has +very little extra features enabled which is great for compile times, but you +are very much encouraged to add additional drivers and configure your kernel +further using +```shell +make -j8 ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- nconfig +``` + +Now compile the whole thing with +``` +make -j8 ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- +``` + + +## Installing + +Once the build has finished the resulting kernel can be found at +```shell +arch/riscv/boot/Image +``` +You'll also need the matching device tree at +```shell +arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dtb +``` +These two files should be copied to the boot partition on the SD card. That is +onto the same file system that contains the `extlinux/extlinux.conf`. On the +default Fedora image this is mounted at `/boot`. + +Now add the following entry to the `extlinux/extlinux.conf` file: +``` +label My New Kernel +kernel /Image +fdt /jh7100-beaglev-starlight.dtb +append earlycon console=ttyS0,115200n8 root=/dev/mmcblk0p2 rootwait stmmac.chain_mode=1 +``` + +This assumes your root file system is at `/dev/mmcblk0p2` which it is on the +default Fedora image. Also if your kernel is very big it might be beneficial to +use the compressed `Image.gz` rather than the uncompressed `Image`. + +The `beaglev_defconfig` doesn't enable modules, but if you enabled them in +your build you'll also need to install them in `/lib/modules/` on the root file +system. How to do that best is out of scope for this README though. + + +## Status + +#### SoC + +- [x] GPIO +- [x] Serial port +- [x] I2C +- [x] SPI +- [x] MMC / SDIO / SD card +- [x] Random number generator +- [x] Temperature sensor +- [x] Ethernet, though a little flaky and `stmmac.chain_mode=1` needed on the cmdline +- [x] Framebuffer, fbdev driver so not upstreamable +- [x] NVDLA +- [ ] Clock tree, statically set up by u-boot, WIP clock driver +- [ ] Pinctrl/Pinmux, statically set up by u-boot +- [ ] Watchdog +- [ ] USB, USB 2.0 seems to work ok, but USB 3.0 is very flaky / broken +- [ ] Security Engine +- [ ] MIPI-DSI +- [ ] ISP +- [ ] MIPI-CSI +- [ ] Video Decode +- [ ] Video Encode +- [ ] NNE50 +- [ ] Vision DSP + +#### Board + +- [x] LED +- [x] PMIC / Reboot +- [x] Ethernet PHY +- [x] HDMI, working with [some screens][hdmi] +- [x] AP6236 Wifi +- [ ] AP6236 Bluetooth +- [ ] GD25LQ256D SPI flash + +[hdmi]: https://forum.beagleboard.org/t/hdmi-displays-compatible-list/ + +## Contributing + +If you're working on cleaning up or upstreaming some of this or adding support +for more of the SoC I'd very much like to incorporate it into this tree. Either +send a pull request, mail or contact Esmil on IRC/Slack. + +Also I think of this tree mostly as a collection of patches that will hopefully +mature enough to be submitted upstream. So expect regular rebases. diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 18ec0f9bb8d5c4..bf5e8de0d0d496 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -206,6 +206,20 @@ config PGTABLE_LEVELS config LOCKDEP_SUPPORT def_bool y +config RISCV_UNCACHED_OFFSET + hex "Base address of uncached alias" + default 0xF80000000 if ARCH_HAS_DMA_SET_UNCACHED && SOC_STARFIVE_VIC7100 + default 0 if !ARCH_HAS_DMA_SET_UNCACHED + +config RISCV_DMA_NONCOHERENT + bool + select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_DMA_SET_UNCACHED + select ARCH_HAS_DMA_CLEAR_UNCACHED + select ARCH_HAS_SETUP_DMA_OPS + source "arch/riscv/Kconfig.socs" source "arch/riscv/Kconfig.erratas" diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 30676ebb16ebd7..db560407b09882 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -19,6 +19,32 @@ config SOC_SIFIVE help This enables support for SiFive SoC platform hardware. +config SOC_STARFIVE_VIC7100 + bool "StarFive VIC7100 SoC" + select SOC_SIFIVE + select OF_RESERVED_MEM + select SIFIVE_L2 + select SIFIVE_L2_FLUSH + select DW_AXI_DMAC_STARFIVE + select GPIO_STARFIVE_VIC + select HW_RANDOM_STARFIVE_VIC + select RISCV_DMA_NONCOHERENT + help + This enables support for StarFive VIC7100 SoC Platform Hardware. + +menu "StarFive VIC7100 SoC Debug Option" + depends on SOC_STARFIVE_VIC7100 + +config SOC_STARFIVE_VIC7100_I2C_GPIO + bool "VIC7100 SOC I2C GPIO init" + depends on I2C_DESIGNWARE_CORE + depends on SOC_STARFIVE_VIC7100 + default y if SOC_STARFIVE_VIC7100 + help + enable VIC7100 DW I2C GPIO init in Synopsys DesignWare master driver + +endmenu + config SOC_VIRT bool "QEMU Virt Machine" select CLINT_TIMER if RISCV_M_MODE diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index fe996b88319eb7..f2a652103b4e21 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -subdir-y += sifive +subdir-y += sifive starfive subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan subdir-y += microchip diff --git a/arch/riscv/boot/dts/starfive/Makefile b/arch/riscv/boot/dts/starfive/Makefile new file mode 100644 index 00000000000000..b0a89a15fc5cd5 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_SOC_STARFIVE_VIC7100) += jh7100-beaglev-starlight.dtb diff --git a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts new file mode 100644 index 00000000000000..b21e13bbc78ef4 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright (c) 2021 StarFive Technology Co., Ltd. */ + +/dts-v1/; +#include "jh7100.dtsi" +#include +#include +#include + +/ { + model = "BeagleV Starlight Beta"; + compatible = "beagle,beaglev-starlight-jh7100", "starfive,jh7100"; + + aliases { + mshc0 = &sdio0; + mshc1 = &sdio1; + serial0 = &uart3; + serial1 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + cpus { + timebase-frequency = <6250000>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x2 0x0>; + }; + + leds { + compatible = "gpio-leds"; + + led-ack { + gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; + color = ; + function = LED_FUNCTION_HEARTBEAT; + linux,default-trigger = "heartbeat"; + label = "ack"; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x28000000>; + alignment = <0x0 0x1000>; + alloc-ranges = <0x0 0xa0000000 0x0 0x28000000>; + linux,cma-default; + }; + + jpu_reserved: framebuffer@c9000000 { + reg = <0x0 0xc9000000 0x0 0x4000000>; + }; + + nvdla_reserved: framebuffer@d0000000 { + no-map; + reg = <0x0 0xd0000000 0x0 0x28000000>; + }; + + vin_reserved: framebuffer@f9000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x0 0xf9000000 0x0 0x1000000>; + }; + + sffb_reserved: framebuffer@fb000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x0 0xfb000000 0x0 0x2000000>; + }; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio 37 GPIO_ACTIVE_LOW>; + }; +}; + +&i2c0 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <500>; + i2c-scl-falling-time-ns = <500>; + scl-gpio = <&gpio 62 0>; + sda-gpio = <&gpio 61 0>; + status = "okay"; + + imx219@10 { + compatible = "imx219"; + reg = <0x10>; + reset-gpio = <&gpio 58 0>; + }; + + tps65086@5e { + compatible = "ti,tps65086"; + reg = <0x5e>; + /* + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + */ + gpio-controller; + #gpio-cells = <2>; + }; + + tda998x@70 { + compatible = "nxp,tda998x"; + reg = <0x70>; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <100>; + i2c-scl-falling-time-ns = <100>; + scl-gpio = <&gpio 47 0>; + sda-gpio = <&gpio 48 0>; + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <500>; + i2c-scl-falling-time-ns = <500>; + scl-gpio = <&gpio 60 0>; + sda-gpio = <&gpio 59 0>; + status = "okay"; + + seeed_plane_i2c@45 { + compatible = "seeed_panel"; + reg = <0x45>; + }; +}; + +&osc0_clk { + clock-frequency = <25000000>; +}; + +&osc1_clk { + clock-frequency = <27000000>; +}; + +&qspi { + nor_flash: nor-flash@0 { + compatible = "spi-flash"; + reg = <0>; + spi-max-frequency = <31250000>; + page-size = <256>; + block-size = <16>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <1>; + cdns,tsd2d-ns = <1>; + cdns,tchsh-ns = <1>; + cdns,tslch-ns = <1>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; + + nand_flash: nand-flash@1 { + compatible = "spi-flash-nand"; + reg = <1>; + spi-max-frequency = <31250000>; + page-size = <2048>; + block-size = <17>; + cdns,read-delay = <4>; + cdns,tshsl-ns = <1>; + cdns,tsd2d-ns = <1>; + cdns,tchsh-ns = <1>; + cdns,tslch-ns = <1>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +}; + +&sdio0 { + broken-cd; + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <10000000>; + status = "okay"; +}; + +&sdio1 { + #address-cells = <1>; + #size-cells = <0>; + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + cap-power-off-card; + max-frequency = <10000000>; + mmc-pwrseq = <&wifi_pwrseq>; + non-removable; + status = "okay"; + + wifi@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + }; +}; + +&sfivefb { + status = "okay"; + + /* + pp1 { + pp-id = <1>; + fifo-out; + src-format = ; + src-width = <800>; + src-height = <480>; + dst-format = ; + dst-width = <800>; + dst-height = <480>; + }; + */ + + tda_998x_1080p { + compatible = "starfive,display-dev"; + panel_name = "tda_998x_1080p"; + panel_lcd_id = <22>; /* 1080p */ + interface_info = "rgb_interface"; + refresh_en = <1>; + bits-per-pixel = <16>; + physical-width = <62>; + physical-height = <114>; + panel-width = <1920>; + panel-height = <1080>; + pixel-clock = <78000000>; + /*dyn_fps;*/ /*dynamic frame rate support*/ + + /*.flags = PREFER_CMD_SEND_MONOLITHIC | CE_CMD_SEND_MONOLITHIC | RESUME_WITH_PREFER | RESUME_WITH_CE*/ + /*gamma-command-monolithic;*/ + /*ce-command-monolithic;*/ + /*resume-with-gamma;*/ + /*resume-with-ce;*/ + + /*mipi info*/ + mipi-byte-clock = <78000>; + mipi-escape-clock = <13000>; + lane-no = <4>; + display_mode = "video_mode"; /*video_mode, command_mode*/ + + /* + auto_stop_clklane_en; + im_pin_val;*/ + + color_bits = ; + /*is_18bit_loosely;*/ + + /*video mode info*/ + h-pulse-width = <44>; + h-back-porch = <148>; + h-front-porch = <88>; + v-pulse-width = <5>; + v-back-porch = <36>; + v-front-porch = <4>; + status = "okay"; + sync_pol = "vsync_high_act"; /*vsync_high_act, hsync_high_act*/ + lp_cmd_en; + /*lp_hfp_en;*/ + /*lp_hbp_en;*/ + /*lp_vact_en;*/ + lp_vfp_en; + lp_vbp_en; + lp_vsa_en; + traffic-mode = "burst_with_sync_pulses"; /*non_burst_with_sync_pulses, non_burst_with_sync_events*/ + + /*phy info*/ + data_tprepare = /bits/ 8 <0>; + data_hs_zero = /bits/ 8 <0>; + data_hs_exit = /bits/ 8 <0>; + data_hs_trail = /bits/ 8 <0>; + + /*te info*/ + te_source = "external_pin"; /*external_pin, dsi_te_trigger*/ + te_trigger_mode = "rising_edge"; /*rising_edge, high_1000us*/ + te_enable = <0>; + cm_te_effect_sync_enable = <0>; /*used in command mode*/ + te_count_per_sec = <64>; /*used in esd*/ + + /*ext info*/ + /* + crc_rx_en; + ecc_rx_en; + eotp_rx_en; + */ + eotp_tx_en; + + dev_read_time = <0x7fff>; + /*type cmd return_count return_code*/ + /*id_read_cmd_info = [];*/ + /*pre_id_cmd = [];*/ + /*esd_read_cmd_info = [DCS_CMD 0A 01 9C];*/ + /*pre_esd_cmd = [];*/ + /*panel-on-command = [];*/ + /*panel-off-command = [];*/ + /*reset-sequence = <1 5>, <0 10>, <1 30>;*/ + /* + panel-gamma-warm-command = [ + + ]; + panel-gamma-nature-command = [ + + ]; + panel-gamma-cool-command = [ + + ]; + + panel-ce-std-command = [ + + ]; + panel-ce-vivid-command = [ + + ]; + */ + }; + + seeed_5_inch { + compatible = "starfive,display-dev"; + panel_name = "seeed_5_inch"; + panel_lcd_id = <22>; /* 480p */ + interface_info = "mipi_interface"; + refresh_en = <1>; + bits-per-pixel = <24>; + physical-width = <62>; + physical-height = <114>; + panel-width = <800>; + panel-height = <480>; + pixel-clock = <27500000>; + /*dyn_fps;*/ /*dynamic frame rate support*/ + fps = <50>; + /*.flags = PREFER_CMD_SEND_MONOLITHIC | CE_CMD_SEND_MONOLITHIC | RESUME_WITH_PREFER | RESUME_WITH_CE*/ + /*gamma-command-monolithic;*/ + /*ce-command-monolithic;*/ + /*resume-with-gamma;*/ + /*resume-with-ce;*/ + + /*mipi info*/ + mipi-byte-clock = <78000>; + mipi-escape-clock = <13000>; + lane-no = <1>; + display_mode = "video_mode"; /*video_mode, command_mode*/ + + /* + auto_stop_clklane_en; + im_pin_val; + */ + + color_bits = ; + /*is_18bit_loosely;*/ + + /*video mode info*/ + h-pulse-width = <10>; + h-back-porch = <20>; + h-front-porch = <50>; + v-pulse-width = <5>; + v-back-porch = <5>; + v-front-porch = <135>; + + /*seeed panel mode info*/ + dphy_bps = <700000000>; + dsi_burst_mode = <0>; + dsi_sync_pulse = <1>; + // bytes + dsi_hsa = <30>; + dsi_hbp = <211>; + dsi_hfp = <159>; + // lines + dsi_vsa = <5>; + dsi_vbp = <5>; + dsi_vfp = <134>; + + status = "okay"; + sync_pol = "vsync_high_act"; /*vsync_high_act, hsync_high_act*/ + lp_cmd_en; + /*lp_hfp_en;*/ + /*lp_hbp_en;*/ + /*lp_vact_en;*/ + lp_vfp_en; + lp_vbp_en; + lp_vsa_en; + traffic-mode = "burst_with_sync_pulses"; /*non_burst_with_sync_pulses, non_burst_with_sync_events*/ + + /*phy info*/ + data_tprepare = /bits/ 8 <0>; + data_hs_zero = /bits/ 8 <0>; + data_hs_exit = /bits/ 8 <0>; + data_hs_trail = /bits/ 8 <0>; + + /*te info*/ + te_source = "external_pin"; /*external_pin, dsi_te_trigger*/ + te_trigger_mode = "rising_edge"; /*rising_edge, high_1000us*/ + te_enable = <0>; + cm_te_effect_sync_enable = <0>; /*used in command mode*/ + te_count_per_sec = <64>; /*used in esd*/ + + /*ext info*/ + /* + crc_rx_en; + ecc_rx_en; + eotp_rx_en; + */ + eotp_tx_en; + + dev_read_time = <0x7fff>; + /*type cmd return_count return_code*/ + /*id_read_cmd_info = [];*/ + /*pre_id_cmd = [];*/ + /*esd_read_cmd_info = [DCS_CMD 0A 01 9C];*/ + /*pre_esd_cmd = [];*/ + /*panel-on-command = [];*/ + /*panel-off-command = [];*/ + /*reset-sequence = <1 5>, <0 10>, <1 30>;*/ + /* + panel-gamma-warm-command = [ + + ]; + panel-gamma-nature-command = [ + + ]; + panel-gamma-cool-command = [ + + ]; + + panel-ce-std-command = [ + + ]; + panel-ce-vivid-command = [ + + ]; + */ + }; +}; + +&spi2 { + status = "okay"; + + spi_dev0: spi@0 { + compatible = "rohm,dh2228fv"; + spi-max-frequency = <10000000>; + reg = <0>; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&usb3 { + dr_mode = "host"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi new file mode 100644 index 00000000000000..a22b1b936fdab1 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright (c) 2021 StarFive Technology Co., Ltd. */ + +/dts-v1/; +#include +#include +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + compatible = "starfive,jh7100"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + compatible = "sifive,u74-mc", "riscv"; + d-cache-block-size = <64>; + d-cache-sets = <64>; + d-cache-size = <32768>; + d-tlb-sets = <1>; + d-tlb-size = <32>; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <64>; + i-cache-size = <32768>; + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; + next-level-cache = <&ccache>; + reg = <0>; + riscv,isa = "rv64imafdc"; + starfive,itim = <&itim0>; + status = "okay"; + tlb-split; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + + cpu@1 { + compatible = "sifive,u74-mc", "riscv"; + d-cache-block-size = <64>; + d-cache-sets = <64>; + d-cache-size = <32768>; + d-tlb-sets = <1>; + d-tlb-size = <32>; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <64>; + i-cache-size = <32768>; + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; + next-level-cache = <&ccache>; + reg = <1>; + riscv,isa = "rv64imafdc"; + starfive,itim = <&itim1>; + status = "okay"; + tlb-split; + cpu1_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + + osc0_clk: osc0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + + osc1_clk: osc1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ccache: cache-controller@2010000 { + cache-block-size = <64>; + cache-level = <2>; + cache-sets = <2048>; + cache-size = <2097152>; + cache-unified; + compatible = "sifive,fu540-c000-ccache", "starfive,ccache0", "cache"; + interrupts = <128 131 129 130>; + /*next-level-cache = <&L40 &L36>;*/ + reg = <0x0 0x2010000 0x0 0x1000>, + <0x0 0x8000000 0x0 0x2000000>; + reg-names = "control", "sideband"; + }; + + dtim: dtim@1000000 { + compatible = "starfive,dtim0"; + reg = <0x0 0x1000000 0x0 0x2000>; + reg-names = "mem"; + }; + + itim0: itim@1808000 { + compatible = "starfive,itim0"; + reg = <0x0 0x1808000 0x0 0x8000>; + reg-names = "mem"; + }; + + itim1: itim@1820000 { + compatible = "starfive,itim0"; + reg = <0x0 0x1820000 0x0 0x8000>; + reg-names = "mem"; + }; + + clint: clint@2000000 { + #interrupt-cells = <1>; + compatible = "riscv,clint0"; + interrupts-extended = <&cpu0_intc 3>, + <&cpu0_intc 7>, + <&cpu1_intc 3>, + <&cpu1_intc 7>; + reg = <0x0 0x2000000 0x0 0x10000>; + reg-names = "control"; + }; + + plic: interrupt-controller@c000000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = <&cpu0_intc 11>, + <&cpu0_intc 9>, + <&cpu1_intc 11>, + <&cpu1_intc 9>; + reg = <0x0 0xc000000 0x0 0x4000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <127>; + }; + + clkgen: clock-controller@11800000 { + compatible = "starfive,jh7100-clkgen"; + reg = <0x0 0x11800000 0x0 0x10000>; + clocks = <&osc0_clk>, <&osc1_clk>; + clock-names = "osc0", "osc1"; + #clock-cells = <1>; + }; + + uart0: serial@11870000 { + compatible = "snps,dw-apb-uart"; + interrupts = <92>; + reg = <0x0 0x11870000 0x0 0x10000>; + reg-io-width = <4>; + reg-shift = <2>; + clocks = <&clkgen JH7100_CLK_HS_UART>, + <&clkgen JH7100_CLK_APB1>; + clock-names = "baudclk", "apb_pclk"; + current-clock = <74250000>; + current-speed = <115200>; + status = "disabled"; + }; + + uart1: serial@11880000 { + compatible = "snps,dw-apb-uart"; + interrupts = <93>; + reg = <0x0 0x11880000 0x0 0x10000>; + reg-io-width = <4>; + reg-shift = <2>; + clocks = <&clkgen JH7100_CLK_HS_UART>, + <&clkgen JH7100_CLK_APB1>; + clock-names = "baudclk", "apb_pclk"; + current-clock = <74250000>; + current-speed = <115200>; + status = "disabled"; + }; + + uart2: serial@12430000 { + compatible = "snps,dw-apb-uart"; + interrupts = <72>; + reg = <0x0 0x12430000 0x0 0x10000>; + reg-io-width = <4>; + reg-shift = <2>; + clocks = <&clkgen JH7100_CLK_UART>, + <&clkgen JH7100_CLK_APB2>; + clock-names = "baudclk", "apb_pclk"; + current-clock = <100000000>; + current-speed = <115200>; + status = "disabled"; + }; + + uart3: serial@12440000 { + compatible = "snps,dw-apb-uart"; + interrupts = <73>; + reg = <0x0 0x12440000 0x0 0x10000>; + reg-io-width = <4>; + reg-shift = <2>; + clocks = <&clkgen JH7100_CLK_UART>, + <&clkgen JH7100_CLK_APB2>; + clock-names = "baudclk", "apb_pclk"; + current-clock = <100000000>; + current-speed = <115200>; + status = "disabled"; + }; + + dma2p: dma-controller@100b0000 { + compatible = "snps,axi-dma-1.01a"; + reg = <0x0 0x100b0000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_AXI>, + <&clkgen JH7100_CLK_AHB0>; + clock-names = "core-clk", "cfgr-clk"; + interrupts = <2>; + #dma-cells = <1>; + dma-channels = <4>; + snps,dma-masters = <1>; + snps,data-width = <4>; + snps,block-size = <4096 4096 4096 4096>; + snps,priority = <0 1 2 3>; + snps,axi-max-burst-len = <128>; + status = "okay"; + }; + + dma1p: dma-controller@10500000 { + compatible = "snps,axi-dma-1.01a"; + reg = <0x0 0x10500000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_AXI>, + <&clkgen JH7100_CLK_AHB0>; + clock-names = "core-clk", "cfgr-clk"; + interrupts = <1>; + #dma-cells = <1>; + dma-channels = <16>; + snps,dma-masters = <1>; + snps,data-width = <3>; + snps,block-size = <4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096>; + snps,priority = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>; + snps,axi-max-burst-len = <64>; + status = "okay"; + }; + + usb3: usb@104c0000 { + compatible = "cdns,usb3"; + reg = <0x0 0x104c0000 0x0 0x10000>, // memory area for HOST registers + <0x0 0x104d0000 0x0 0x10000>, // memory area for DEVICE registers + <0x0 0x104e0000 0x0 0x10000>; // memory area for OTG/DRD registers + reg-names = "otg", "xhci", "dev"; + interrupts = <44>, <52>, <43>; + interrupt-names = "host", "peripheral", "otg"; + phy-names = "cdns3,usb3-phy", "cdns3,usb2-phy"; + maximum-speed = "super-speed"; + status = "disabled"; + }; + + gpio: gpio@11910000 { + compatible = "starfive,jh7100-gpio"; + reg = <0x0 0x11910000 0x0 0x10000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <32>; + }; + + i2c0: i2c@118b0000 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x0 0x118b0000 0x0 0x10000>; + interrupts = <96>; + clocks = <&clkgen JH7100_CLK_I2C0>; + status = "disabled"; + }; + + i2c1: i2c@118c0000 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x0 0x118c0000 0x0 0x10000>; + interrupts = <97>; + clocks = <&clkgen JH7100_CLK_I2C0>; + status = "disabled"; + }; + + i2c2: i2c@12450000 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x0 0x12450000 0x0 0x10000>; + interrupts = <74>; + clocks = <&clkgen JH7100_CLK_I2C2>; + status = "disabled"; + }; + + i2c3: i2c@12460000 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x0 0x12460000 0x0 0x10000>; + interrupts = <75>; + clocks = <&clkgen JH7100_CLK_I2C2>; + status = "disabled"; + }; + + trng: trng@118d0000 { + compatible = "starfive,vic-rng"; + reg = <0x0 0x118d0000 0x0 0x10000>; + interrupts = <98>; + clocks = <&clkgen JH7100_CLK_HF>; + }; + + crypto: crypto@100d0000 { + compatible = "starfive,vic-sec"; + reg = <0x0 0x100d0000 0x0 0x20000>, + <0x0 0x11800234 0x0 0xc>; + reg-names = "secmem", "secclk"; + interrupts = <31>; + clocks = <&clkgen JH7100_CLK_HF>; + }; + + /* gmac device configuration */ + stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0xf>; + snps,rd_osr_lmt = <0xf>; + snps,blen = <256 128 64 32 0 0 0>; + }; + + gmac: ethernet@10020000 { + compatible = "snps,dwmac"; + reg = <0x0 0x10020000 0x0 0x10000>; + interrupts = <6 7>; + interrupt-names = "macirq", "eth_wake_irq"; + max-frame-size = <9000>; + phy-mode = "rgmii-txid"; + snps,multicast-filter-bins = <256>; + snps,perfect-filter-entries = <128>; + rx-fifo-depth = <32768>; + tx-fifo-depth = <16384>; + clocks = <&clkgen JH7100_CLK_GMAC>; + clock-names = "stmmaceth"; + snps,fixed-burst; + snps,no-pbl-x8 = <1>; + /*snps,force_sf_dma_mode;*/ + snps,force_thresh_dma_mode; + snps,axi-config = <&stmmac_axi_setup>; + }; + + nbdla: nvdla@11940000 { + compatible = "nvidia,nvdla_os_initial"; + interrupts = <22>; + memory-region = <&nvdla_reserved>; + reg = <0x0 0x11940000 0x0 0x40000>; + status = "okay"; + }; + + jpu: coadj12@11900000 { + compatible = "cm,codaj12-jpu-1"; + reg = <0x0 0x11900000 0x0 0x300>; + memory-region = <&jpu_reserved>; + interrupts = <24>; + clocks = <&clkgen JH7100_CLK_JPU>; + clock-names = "jpege"; + reg-names = "control"; + status = "okay"; + }; + + vpu_dec: vpu_dec@118f0000 { + compatible = "c&m,cm511-vpu"; + reg = <0 0x118f0000 0 0x10000>; + //memory-region = <&vpu_reserved>; + interrupts = <23>; + clocks = <&clkgen JH7100_CLK_VPU>; + clock-names = "vcodec"; + status = "okay"; + }; + + vpu_enc: vpu_enc@118e0000 { + compatible = "cm,cm521-vpu"; + reg = <0x0 0x118e0000 0x0 0x4000>; + interrupts = <26>; + clocks = <&clkgen JH7100_CLK_VPU>; + clock-names = "vcodec"; + reg-names = "control"; + }; + + ptc: pwm@12490000 { + compatible = "starfive,pwm0"; + reg = <0x0 0x12490000 0x0 0x10000>; + reg-names = "control"; + sifive,approx-period = <100000000>; + clocks = <&clkgen JH7100_CLK_PWM>; + #pwm-cells = <3>; + sifive,npwm = <8>; + + }; + + qspi: spi@11860000 { + compatible = "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x11860000 0x0 0x10000>, + <0x0 0x20000000 0x0 0x20000000>; + interrupts = <3>; + clocks = <&clkgen JH7100_CLK_QSPI>; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + status = "disabled"; + spi-max-frequency = <250000000>; + }; + + spi0: spi@11890000 { + compatible = "snps,dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <94>; + reg = <0x0 0x11890000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SPI>; + status = "disabled"; + }; + + spi1: spi@118a0000 { + compatible = "snps,dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <95>; + reg = <0x0 0x118a0000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SPI>; + status = "disabled"; + }; + + spi2: spi@12410000 { + compatible = "snps,dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <70>; + reg = <0x0 0x12410000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SPI>; + status = "disabled"; + }; + + spi3: spi@12420000 { + compatible = "snps,dw-apb-ssi"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <71>; + reg = <0x0 0x12420000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SPI>; + status = "disabled"; + }; + + xrp@f0000000 { + compatible = "cdns,xrp"; + reg = <0x0 0xf0000000 0x0 0x01ffffff>, + <0x10 0x72000000 0x0 0x00001000>, + <0x10 0x72001000 0x0 0x00fff000>, + <0x0 0x124b0000 0x0 0x00010000>; + clocks = <&clkgen JH7100_CLK_HF>; + firmware-name = "vp6_elf"; + dsp-irq = <19 20>; + dsp-irq-src = <0x20 0x21>; + intc-irq-mode = <1>; + intc-irq = <0 1>; + interrupts = <27 28>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x40000000 0x0 0x40000000 0x01000000>, + <0xb0000000 0x10 0x70000000 0x3000000>; + dsp@0 { + }; + }; + + sdio0: mmc@10000000 { + compatible = "snps,dw-mshc"; + reg = <0x0 0x10000000 0x0 0x10000>; + interrupts = <4>; + clocks = <&clkgen JH7100_CLK_DWMMC_BIU>; + clock-names = "biu"; + clock-frequency = <100000000>; + data-addr = <0>; + fifo-depth = <32>; + fifo-watermark-aligned; + status = "disabled"; + }; + + sdio1: mmc@10010000 { + compatible = "snps,dw-mshc"; + reg = <0x0 0x10010000 0x0 0x10000>; + interrupts = <5>; + clocks = <&clkgen JH7100_CLK_DWMMC_BIU>; + clock-names = "biu"; + clock-frequency = <100000000>; + data-addr = <0>; + fifo-depth = <32>; + fifo-watermark-aligned; + status = "disabled"; + }; + + sfivefb: sfivefb@12000000 { + compatible = "starfive,vpp-lcdc"; + interrupts = <101>, <103>; + interrupt-names = "lcdc_irq", "vpp1_irq"; + reg = <0x0 0x12000000 0x0 0x10000>, + <0x0 0x12100000 0x0 0x10000>, + <0x0 0x12040000 0x0 0x10000>, + <0x0 0x12080000 0x0 0x10000>, + <0x0 0x120c0000 0x0 0x10000>, + <0x0 0x12240000 0x0 0x10000>, + <0x0 0x12250000 0x0 0x10000>, + <0x0 0x12260000 0x0 0x10000>; + reg-names = "lcdc", "dsitx", "vpp0", "vpp1", "vpp2", "clk", "rst", "sys"; + memory-region = <&sffb_reserved>; + clocks = <&clkgen JH7100_CLK_UART>, + <&clkgen JH7100_CLK_APB2>; + clock-names = "baudclk", "apb_pclk"; + ddr-format = ;/*LCDC win_format*/ + status = "disabled"; + }; + + vin_sysctl: vin_sysctl@19800000 { + compatible = "starfive,stf-vin"; + reg = <0x0 0x19800000 0x0 0x10000>, + <0x0 0x19810000 0x0 0x10000>, + <0x0 0x19820000 0x0 0x10000>, + <0x0 0x19830000 0x0 0x10000>, + <0x0 0x19840000 0x0 0x10000>, + <0x0 0x19870000 0x0 0x30000>, + <0x0 0x198a0000 0x0 0x30000>, + <0x0 0x11800000 0x0 0x10000>, + <0x0 0x11840000 0x0 0x10000>, + <0x0 0x11858000 0x0 0x10000>; + reg-names = "mipi0", "vclk", "vrst", "mipi1", "sctrl", + "isp0", "isp1", "tclk", "trst", "iopad"; + interrupts = <119 109>; + memory-region = <&vin_reserved>; + /*defaule config for imx219 vin&isp*/ + format = ; + frame-width = <800>; + frame-height =<480>; + isp0_enable; + csi-lane = <2>; + csi-dlane-swaps = /bits/ 8 <1>,/bits/ 8 <2>,/bits/ 8 <3>,/bits/ 8 <4>; + csi-dlane-pn-swaps = /bits/ 8 <0>,/bits/ 8 <0>,/bits/ 8 <0>,/bits/ 8 <0>; + csi-clane-swap = /bits/ 8 <0>; + csi-clane-pn-swap = /bits/ 8 <0>; + csi-mipiID = <0>; + csi-width = <1920>; + csi-height = <1080>; + csi-dt = <0x2b>; + }; + + sfctemp: tmon@124a0000 { + compatible = "starfive,jh7100-temp"; + reg = <0x0 0x124a0000 0x0 0x10000>; + #thermal-sensor-cells = <0>; + interrupts = <122>; + }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <250>; + polling-delay = <15000>; + + thermal-sensors = <&sfctemp>; + + cooling-maps { + }; + + trips { + cpu_alert0: cpu_alert0 { + /* milliCelsius */ + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_crit: cpu_crit { + /* milliCelsius */ + temperature = <90000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; + + otp: otp@11810000 { + compatible = "starfive,fu740-otp"; + reg = <0x0 0x11810000 0x0 0x10000>; + fuse-count = <0x200>; + }; + }; +}; diff --git a/arch/riscv/configs/beaglev_defconfig b/arch/riscv/configs/beaglev_defconfig new file mode 100644 index 00000000000000..e87745e739e6c6 --- /dev/null +++ b/arch/riscv/configs/beaglev_defconfig @@ -0,0 +1,206 @@ +CONFIG_LOCALVERSION="-beaglev" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_WATCH_QUEUE=y +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_PSI=y +# CONFIG_CPU_ISOLATION is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_EXPERT=y +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_USERFAULTFD=y +CONFIG_PERF_EVENTS=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLUB_DEBUG is not set +CONFIG_SHUFFLE_PAGE_ALLOCATOR=y +CONFIG_SOC_STARFIVE_VIC7100=y +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +# CONFIG_RISCV_SBI_V01 is not set +CONFIG_PM=y +CONFIG_JUMP_LABEL=y +# CONFIG_STACKPROTECTOR is not set +# CONFIG_GCC_PLUGINS is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +CONFIG_IOSCHED_BFQ=y +CONFIG_KSM=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6_SIT is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_FQ_CODEL=y +CONFIG_CFG80211=y +# CONFIG_CFG80211_DEFAULT_PS is not set +CONFIG_RFKILL=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_EXTRA_FIRMWARE="regulatory.db regulatory.db.p7s brcm/brcmfmac43430-sdio.bin brcm/brcmfmac43430-sdio.clm_blob brcm/brcmfmac43430-sdio.beagle,beaglev-starlight-jh7100.txt" +CONFIG_EXTRA_FIRMWARE_DIR="firmware" +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_PARTITIONED_MASTER=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_ZRAM=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=1 +CONFIG_BLK_DEV_NBD=y +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +CONFIG_WIREGUARD=y +CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +CONFIG_MICREL_PHY=y +CONFIG_BRCMFMAC=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LDISC_AUTOLOAD is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_DEVMEM is not set +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_SPI=y +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_SPI_DESIGNWARE=y +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_MMIO=y +CONFIG_SPI_SPIDEV=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=256 +CONFIG_GPIO_SYSFS=y +# CONFIG_GPIO_CDEV_V1 is not set +CONFIG_GPIO_TPS65086=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_TPS65086=y +CONFIG_SENSORS_SFCTEMP=y +CONFIG_THERMAL=y +CONFIG_THERMAL_NETLINK=y +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_CPU_THERMAL=y +CONFIG_MFD_TPS65086=y +CONFIG_DRM=y +CONFIG_FB_STARFIVE=y +CONFIG_FB_STARFIVE_HDMI_TDA998X=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DBGCAP=y +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_USB_CDNS_SUPPORT=y +CONFIG_USB_CDNS3=y +CONFIG_USB_CDNS3_HOST=y +CONFIG_MMC=y +# CONFIG_PWRSEQ_EMMC is not set +CONFIG_MMC_DW=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_DMADEVICES=y +CONFIG_DW_AXI_DMAC=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_PWM=y +CONFIG_PWM_SIFIVE_PTC=y +CONFIG_NVDLA=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_DNOTIFY is not set +CONFIG_FANOTIFY=y +CONFIG_AUTOFS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-15" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_EXFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_UTF8=y +CONFIG_LSM="" +CONFIG_CRYPTO_ZSTD=y +# CONFIG_CRYPTO_HW is not set +# CONFIG_RAID6_PQ_BENCHMARK is not set +CONFIG_DMA_CMA=y +# CONFIG_SYMBOLIC_ERRNAME is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_MISC is not set +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_WX=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_STACKTRACE=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h index 9090493665555c..3348a00c958efb 100644 --- a/arch/riscv/include/asm/string.h +++ b/arch/riscv/include/asm/string.h @@ -6,18 +6,18 @@ #ifndef _ASM_RISCV_STRING_H #define _ASM_RISCV_STRING_H -#include -#include - +#ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE #define __HAVE_ARCH_MEMSET -extern asmlinkage void *memset(void *, int, size_t); -extern asmlinkage void *__memset(void *, int, size_t); +void *memset(void *s, int c, size_t count); +void *__memset(void *s, int c, size_t count); #define __HAVE_ARCH_MEMCPY -extern asmlinkage void *memcpy(void *, const void *, size_t); -extern asmlinkage void *__memcpy(void *, const void *, size_t); +void *memcpy(void *dest, const void *src, size_t count); +void *__memcpy(void *dest, const void *src, size_t count); #define __HAVE_ARCH_MEMMOVE -extern asmlinkage void *memmove(void *, const void *, size_t); -extern asmlinkage void *__memmove(void *, const void *, size_t); +void *memmove(void *dest, const void *src, size_t count); +void *__memmove(void *dest, const void *src, size_t count); +#endif + /* For those files which don't want to check by kasan. */ #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) #define memcpy(dst, src, len) __memcpy(dst, src, len) diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index d3081e4d96006d..e635ce1e564564 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -31,7 +31,6 @@ obj-y += syscall_table.o obj-y += sys_riscv.o obj-y += time.o obj-y += traps.o -obj-y += riscv_ksyms.o obj-y += stacktrace.o obj-y += cacheinfo.o obj-y += patch.o diff --git a/arch/riscv/kernel/riscv_ksyms.c b/arch/riscv/kernel/riscv_ksyms.c deleted file mode 100644 index 5ab1c7e1a6ed5d..00000000000000 --- a/arch/riscv/kernel/riscv_ksyms.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 Zihao Yu - */ - -#include -#include - -/* - * Assembly functions that may be used (directly or indirectly) by modules - */ -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(__memcpy); -EXPORT_SYMBOL(__memmove); diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 25d5c9664e57e4..e33263cc622a1f 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -1,9 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only lib-y += delay.o -lib-y += memcpy.o -lib-y += memset.o -lib-y += memmove.o lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_64BIT) += tishift.o +lib-$(CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE) += string.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/riscv/lib/memcpy.S b/arch/riscv/lib/memcpy.S deleted file mode 100644 index 51ab716253fa3c..00000000000000 --- a/arch/riscv/lib/memcpy.S +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2013 Regents of the University of California - */ - -#include -#include - -/* void *memcpy(void *, const void *, size_t) */ -ENTRY(__memcpy) -WEAK(memcpy) - move t6, a0 /* Preserve return value */ - - /* Defer to byte-oriented copy for small sizes */ - sltiu a3, a2, 128 - bnez a3, 4f - /* Use word-oriented copy only if low-order bits match */ - andi a3, t6, SZREG-1 - andi a4, a1, SZREG-1 - bne a3, a4, 4f - - beqz a3, 2f /* Skip if already aligned */ - /* - * Round to nearest double word-aligned address - * greater than or equal to start address - */ - andi a3, a1, ~(SZREG-1) - addi a3, a3, SZREG - /* Handle initial misalignment */ - sub a4, a3, a1 -1: - lb a5, 0(a1) - addi a1, a1, 1 - sb a5, 0(t6) - addi t6, t6, 1 - bltu a1, a3, 1b - sub a2, a2, a4 /* Update count */ - -2: - andi a4, a2, ~((16*SZREG)-1) - beqz a4, 4f - add a3, a1, a4 -3: - REG_L a4, 0(a1) - REG_L a5, SZREG(a1) - REG_L a6, 2*SZREG(a1) - REG_L a7, 3*SZREG(a1) - REG_L t0, 4*SZREG(a1) - REG_L t1, 5*SZREG(a1) - REG_L t2, 6*SZREG(a1) - REG_L t3, 7*SZREG(a1) - REG_L t4, 8*SZREG(a1) - REG_L t5, 9*SZREG(a1) - REG_S a4, 0(t6) - REG_S a5, SZREG(t6) - REG_S a6, 2*SZREG(t6) - REG_S a7, 3*SZREG(t6) - REG_S t0, 4*SZREG(t6) - REG_S t1, 5*SZREG(t6) - REG_S t2, 6*SZREG(t6) - REG_S t3, 7*SZREG(t6) - REG_S t4, 8*SZREG(t6) - REG_S t5, 9*SZREG(t6) - REG_L a4, 10*SZREG(a1) - REG_L a5, 11*SZREG(a1) - REG_L a6, 12*SZREG(a1) - REG_L a7, 13*SZREG(a1) - REG_L t0, 14*SZREG(a1) - REG_L t1, 15*SZREG(a1) - addi a1, a1, 16*SZREG - REG_S a4, 10*SZREG(t6) - REG_S a5, 11*SZREG(t6) - REG_S a6, 12*SZREG(t6) - REG_S a7, 13*SZREG(t6) - REG_S t0, 14*SZREG(t6) - REG_S t1, 15*SZREG(t6) - addi t6, t6, 16*SZREG - bltu a1, a3, 3b - andi a2, a2, (16*SZREG)-1 /* Update count */ - -4: - /* Handle trailing misalignment */ - beqz a2, 6f - add a3, a1, a2 - - /* Use word-oriented copy if co-aligned to word boundary */ - or a5, a1, t6 - or a5, a5, a3 - andi a5, a5, 3 - bnez a5, 5f -7: - lw a4, 0(a1) - addi a1, a1, 4 - sw a4, 0(t6) - addi t6, t6, 4 - bltu a1, a3, 7b - - ret - -5: - lb a4, 0(a1) - addi a1, a1, 1 - sb a4, 0(t6) - addi t6, t6, 1 - bltu a1, a3, 5b -6: - ret -END(__memcpy) diff --git a/arch/riscv/lib/memmove.S b/arch/riscv/lib/memmove.S deleted file mode 100644 index 07d1d2152ba5ce..00000000000000 --- a/arch/riscv/lib/memmove.S +++ /dev/null @@ -1,64 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#include -#include - -ENTRY(__memmove) -WEAK(memmove) - move t0, a0 - move t1, a1 - - beq a0, a1, exit_memcpy - beqz a2, exit_memcpy - srli t2, a2, 0x2 - - slt t3, a0, a1 - beqz t3, do_reverse - - andi a2, a2, 0x3 - li t4, 1 - beqz t2, byte_copy - -word_copy: - lw t3, 0(a1) - addi t2, t2, -1 - addi a1, a1, 4 - sw t3, 0(a0) - addi a0, a0, 4 - bnez t2, word_copy - beqz a2, exit_memcpy - j byte_copy - -do_reverse: - add a0, a0, a2 - add a1, a1, a2 - andi a2, a2, 0x3 - li t4, -1 - beqz t2, reverse_byte_copy - -reverse_word_copy: - addi a1, a1, -4 - addi t2, t2, -1 - lw t3, 0(a1) - addi a0, a0, -4 - sw t3, 0(a0) - bnez t2, reverse_word_copy - beqz a2, exit_memcpy - -reverse_byte_copy: - addi a0, a0, -1 - addi a1, a1, -1 - -byte_copy: - lb t3, 0(a1) - addi a2, a2, -1 - sb t3, 0(a0) - add a1, a1, t4 - add a0, a0, t4 - bnez a2, byte_copy - -exit_memcpy: - move a0, t0 - move a1, t1 - ret -END(__memmove) diff --git a/arch/riscv/lib/memset.S b/arch/riscv/lib/memset.S deleted file mode 100644 index 34c5360c6705c5..00000000000000 --- a/arch/riscv/lib/memset.S +++ /dev/null @@ -1,113 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2013 Regents of the University of California - */ - - -#include -#include - -/* void *memset(void *, int, size_t) */ -ENTRY(__memset) -WEAK(memset) - move t0, a0 /* Preserve return value */ - - /* Defer to byte-oriented fill for small sizes */ - sltiu a3, a2, 16 - bnez a3, 4f - - /* - * Round to nearest XLEN-aligned address - * greater than or equal to start address - */ - addi a3, t0, SZREG-1 - andi a3, a3, ~(SZREG-1) - beq a3, t0, 2f /* Skip if already aligned */ - /* Handle initial misalignment */ - sub a4, a3, t0 -1: - sb a1, 0(t0) - addi t0, t0, 1 - bltu t0, a3, 1b - sub a2, a2, a4 /* Update count */ - -2: /* Duff's device with 32 XLEN stores per iteration */ - /* Broadcast value into all bytes */ - andi a1, a1, 0xff - slli a3, a1, 8 - or a1, a3, a1 - slli a3, a1, 16 - or a1, a3, a1 -#ifdef CONFIG_64BIT - slli a3, a1, 32 - or a1, a3, a1 -#endif - - /* Calculate end address */ - andi a4, a2, ~(SZREG-1) - add a3, t0, a4 - - andi a4, a4, 31*SZREG /* Calculate remainder */ - beqz a4, 3f /* Shortcut if no remainder */ - neg a4, a4 - addi a4, a4, 32*SZREG /* Calculate initial offset */ - - /* Adjust start address with offset */ - sub t0, t0, a4 - - /* Jump into loop body */ - /* Assumes 32-bit instruction lengths */ - la a5, 3f -#ifdef CONFIG_64BIT - srli a4, a4, 1 -#endif - add a5, a5, a4 - jr a5 -3: - REG_S a1, 0(t0) - REG_S a1, SZREG(t0) - REG_S a1, 2*SZREG(t0) - REG_S a1, 3*SZREG(t0) - REG_S a1, 4*SZREG(t0) - REG_S a1, 5*SZREG(t0) - REG_S a1, 6*SZREG(t0) - REG_S a1, 7*SZREG(t0) - REG_S a1, 8*SZREG(t0) - REG_S a1, 9*SZREG(t0) - REG_S a1, 10*SZREG(t0) - REG_S a1, 11*SZREG(t0) - REG_S a1, 12*SZREG(t0) - REG_S a1, 13*SZREG(t0) - REG_S a1, 14*SZREG(t0) - REG_S a1, 15*SZREG(t0) - REG_S a1, 16*SZREG(t0) - REG_S a1, 17*SZREG(t0) - REG_S a1, 18*SZREG(t0) - REG_S a1, 19*SZREG(t0) - REG_S a1, 20*SZREG(t0) - REG_S a1, 21*SZREG(t0) - REG_S a1, 22*SZREG(t0) - REG_S a1, 23*SZREG(t0) - REG_S a1, 24*SZREG(t0) - REG_S a1, 25*SZREG(t0) - REG_S a1, 26*SZREG(t0) - REG_S a1, 27*SZREG(t0) - REG_S a1, 28*SZREG(t0) - REG_S a1, 29*SZREG(t0) - REG_S a1, 30*SZREG(t0) - REG_S a1, 31*SZREG(t0) - addi t0, t0, 32*SZREG - bltu t0, a3, 3b - andi a2, a2, SZREG-1 /* Update count */ - -4: - /* Handle trailing misalignment */ - beqz a2, 6f - add a3, t0, a2 -5: - sb a1, 0(t0) - addi t0, t0, 1 - bltu t0, a3, 5b -6: - ret -END(__memset) diff --git a/arch/riscv/lib/string.c b/arch/riscv/lib/string.c new file mode 100644 index 00000000000000..1fe6831431fa19 --- /dev/null +++ b/arch/riscv/lib/string.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * String functions optimized for hardware which doesn't + * handle unaligned memory accesses efficiently. + * + * Copyright (C) 2021 Matteo Croce + */ + +#include +#include + +/* Minimum size for a word copy to be convenient */ +#define MIN_THRESHOLD (sizeof(long) * 2) + +/* convenience union to avoid cast between different pointer types */ +union types { + u8 *as_u8; + unsigned long *as_ulong; + uintptr_t as_uptr; +}; + +union const_types { + const u8 *as_u8; + const unsigned long *as_ulong; + uintptr_t as_uptr; +}; + +static const unsigned int bytes_long = sizeof(long); +static const unsigned int mask = bytes_long - 1; + +void *__memcpy(void *dest, const void *src, size_t count) +{ + union const_types s = { .as_u8 = src }; + union types d = { .as_u8 = dest }; + int distance = 0; + + if (count < MIN_THRESHOLD) + goto copy_remainder; + + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { + /* Copy a byte at time until destination is aligned. */ + for (; d.as_uptr & mask; count--) + *d.as_u8++ = *s.as_u8++; + + distance = s.as_uptr & mask; + } + + if (distance) { + unsigned long last, next; + + /* + * s is distance bytes ahead of d, and d just reached + * the alignment boundary. Move s backward to word align it + * and shift data to compensate for distance, in order to do + * word-by-word copy. + */ + s.as_u8 -= distance; + + /* + * Word-by-word copy by shifting data. + * Works only on Little Endian machines. + */ + next = s.as_ulong[0]; + for (; count >= bytes_long + mask; count -= bytes_long) { + last = next; + next = s.as_ulong[1]; + + d.as_ulong[0] = last >> (distance * 8) | + next << ((bytes_long - distance) * 8); + + d.as_ulong++; + s.as_ulong++; + } + + /* Restore s with the original offset. */ + s.as_u8 += distance; + } else { + /* + * If the source and dest lower bits are the same, do a simple + * 32/64 bit wide copy. + */ + for (; count >= bytes_long; count -= bytes_long) + *d.as_ulong++ = *s.as_ulong++; + } + +copy_remainder: + while (count--) + *d.as_u8++ = *s.as_u8++; + + return dest; +} +EXPORT_SYMBOL(__memcpy); + +void *memcpy(void *dest, const void *src, size_t count) __weak __alias(__memcpy); +EXPORT_SYMBOL(memcpy); + +/* + * Simply check if the buffer overlaps an call memcpy() in case, + * otherwise do a simple one byte at time backward copy. + */ +void *__memmove(void *dest, const void *src, size_t count) +{ + if (dest < src || src + count <= dest) + return memcpy(dest, src, count); + + if (dest > src) { + const char *s = src + count; + char *tmp = dest + count; + + while (count--) + *--tmp = *--s; + } + return dest; +} +EXPORT_SYMBOL(__memmove); + +void *memmove(void *dest, const void *src, size_t count) __weak __alias(__memmove); +EXPORT_SYMBOL(memmove); + +void *__memset(void *s, int c, size_t count) +{ + union types dest = { .as_u8 = s }; + + if (count >= MIN_THRESHOLD) { + unsigned long cu = (unsigned long)c; + + /* Compose an ulong with 'c' repeated 4/8 times */ + cu |= cu << 8; + cu |= cu << 16; +#if BITS_PER_LONG == 64 + cu |= cu << 32; +#endif + + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { + /* + * Fill the buffer one byte at time until + * the destination is word aligned. + */ + for (; count && dest.as_uptr & mask; count--) + *dest.as_u8++ = c; + } + + /* Copy using the largest size allowed */ + for (; count >= bytes_long; count -= bytes_long) + *dest.as_ulong++ = cu; + } + + /* copy the remainder */ + while (count--) + *dest.as_u8++ = c; + + return s; +} +EXPORT_SYMBOL(__memset); + +void *memset(void *s, int c, size_t count) __weak __alias(__memset); +EXPORT_SYMBOL(memset); diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 7ebaef10ea1b69..959bef49098b23 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -27,3 +27,4 @@ KASAN_SANITIZE_init.o := n endif obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o +obj-$(CONFIG_RISCV_DMA_NONCOHERENT) += dma-noncoherent.o diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c new file mode 100644 index 00000000000000..81628e47eaeaf2 --- /dev/null +++ b/arch/riscv/mm/dma-noncoherent.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * DMA mapping implementation inspired from arm/mm/dma-mapping.c + * + * Copyright (c) 2021 Western Digital Corporation or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +//TODO Do it through SBI +#include + +void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, enum dma_data_direction dir) +{ + sifive_l2_flush64_range(paddr, size); +} + +void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, enum dma_data_direction dir) +{ + sifive_l2_flush64_range(paddr, size); +} + +void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, + const struct iommu_ops *iommu, bool coherent) +{ + dev_info(dev, "coherent device %d dev->dma_coherent %d\n", coherent, dev->dma_coherent); + dev->dma_coherent = coherent; +} + +//TODO: We are supposed to invalidate the cache here +void arch_dma_prep_coherent(struct page *page, size_t size) +{ + void *flush_addr = page_address(page); + + memset(flush_addr, 0, size); + sifive_l2_flush64_range(__pa(flush_addr), size); +} + +void arch_dma_clear_uncached(void *addr, size_t size) +{ + memunmap(addr); +} + +void *arch_dma_set_uncached(void *addr, size_t size) +{ + phys_addr_t phys_addr = __pa(addr) + CONFIG_RISCV_UNCACHED_OFFSET; + void *mem_base = NULL; + + mem_base = memremap(phys_addr, size, MEMREMAP_WT); + if (!mem_base) { + pr_err("%s memremap failed for addr %px\n", __func__, addr); + return ERR_PTR(-EINVAL); + } + + return mem_base; +} diff --git a/drivers/Kconfig b/drivers/Kconfig index 47980c6b1945d1..7652cecf3f0380 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -238,4 +238,6 @@ source "drivers/interconnect/Kconfig" source "drivers/counter/Kconfig" source "drivers/most/Kconfig" + +source "drivers/nvdla/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 5a6d613e868d3f..1a8f65af768bbb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -190,3 +190,4 @@ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_INTERCONNECT) += interconnect/ obj-$(CONFIG_COUNTER) += counter/ obj-$(CONFIG_MOST) += most/ +obj-$(CONFIG_NVDLA) += nvdla/ diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 1fe006f3f12fab..b21b7d33357e24 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -335,6 +335,19 @@ config HW_RANDOM_POWERNV If unsure, say Y. +config HW_RANDOM_STARFIVE_VIC + tristate "Starfive VIC Random Number Generator support" + depends on HW_RANDOM + default y if SOC_STARFIVE_VIC7100 + help + This driver provides kernel-side support for the Random Number + Generator hardware found on Starfive VIC SoC. + + To compile this driver as a module, choose M here: the + module will be called starfive-vic-rng. + + If unsure, say Y. + config HW_RANDOM_HISI tristate "Hisilicon Random Number Generator support" depends on HW_RANDOM && ARCH_HISI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 8933fada74f2fb..9b959cfc1b3086 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o +obj-$(CONFIG_HW_RANDOM_STARFIVE_VIC) += starfive-vic-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o diff --git a/drivers/char/hw_random/starfive-vic-rng.c b/drivers/char/hw_random/starfive-vic-rng.c new file mode 100644 index 00000000000000..6142b6a7ace6be --- /dev/null +++ b/drivers/char/hw_random/starfive-vic-rng.c @@ -0,0 +1,256 @@ +/* + ****************************************************************************** + * @file starfive-vic-rng.c + * @author StarFive Technology + * @version V1.0 + * @date 08/13/2020 + * @brief + ****************************************************************************** + * @copy + * + * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "starfive-vic-rng.h" + +#define to_vic_rng(p) container_of(p, struct vic_rng, rng) + +struct vic_rng { + struct device *dev; + void __iomem *base; + struct hwrng rng; +}; + +static inline void vic_wait_till_idle(struct vic_rng *hrng) +{ + while(readl(hrng->base + VIC_STAT) & VIC_STAT_BUSY) + ; +} + +static inline void vic_rng_irq_mask_clear(struct vic_rng *hrng) +{ + // clear register: ISTAT + u32 data = readl(hrng->base + VIC_ISTAT); + writel(data, hrng->base + VIC_ISTAT); + writel(0, hrng->base + VIC_ALARM); +} + +static int vic_trng_cmd(struct vic_rng *hrng, u32 cmd) { + int res = 0; + // wait till idle + vic_wait_till_idle(hrng); + switch (cmd) { + case VIC_CTRL_CMD_NOP: + case VIC_CTRL_CMD_GEN_NOISE: + case VIC_CTRL_CMD_GEN_NONCE: + case VIC_CTRL_CMD_CREATE_STATE: + case VIC_CTRL_CMD_RENEW_STATE: + case VIC_CTRL_CMD_REFRESH_ADDIN: + case VIC_CTRL_CMD_GEN_RANDOM: + case VIC_CTRL_CMD_ADVANCE_STATE: + case VIC_CTRL_CMD_KAT: + case VIC_CTRL_CMD_ZEROIZE: + writel(cmd, hrng->base + VIC_CTRL); + break; + default: + res = -1; + break; + } + + return res; +} + +static int vic_rng_init(struct hwrng *rng) +{ + struct vic_rng *hrng = to_vic_rng(rng); + + // wait till idle + + // clear register: ISTAT + vic_rng_irq_mask_clear(hrng); + + // set mission mode + writel(VIC_SMODE_SECURE_EN(1), hrng->base + VIC_SMODE); + + vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE); + vic_wait_till_idle(hrng); + + // set interrupt + writel(VIC_IE_ALL, hrng->base + VIC_IE); + + // zeroize + vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE); + + vic_wait_till_idle(hrng); + + return 0; +} + +static irqreturn_t vic_rng_irq(int irq, void *priv) +{ + u32 status, val; + struct vic_rng *hrng = (struct vic_rng *)priv; + + /* + * clearing the interrupt will also clear the error register + * read error and status before clearing + */ + status = readl(hrng->base + VIC_ISTAT); + + if (status & VIC_ISTAT_ALARMS) { + writel(VIC_ISTAT_ALARMS, hrng->base + VIC_ISTAT); + val = readl(hrng->base + VIC_ALARM); + if (val & VIC_ALARM_ILLEGAL_CMD_SEQ) { + writel(VIC_ALARM_ILLEGAL_CMD_SEQ, hrng->base + VIC_ALARM); + //dev_info(hrng->dev, "ILLEGAL CMD SEQ: LAST_CMD=0x%x\r\n", + //VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT))); + } else { + dev_info(hrng->dev, "Failed test: %x\r\n", val); + } + } + + if (status & VIC_ISTAT_ZEROIZE) { + writel(VIC_ISTAT_ZEROIZE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "zeroized\r\n"); + } + + if (status & VIC_ISTAT_KAT_COMPLETE) { + writel(VIC_ISTAT_KAT_COMPLETE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "kat_completed\r\n"); + } + + if (status & VIC_ISTAT_NOISE_RDY) { + writel(VIC_ISTAT_NOISE_RDY, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "noise_rdy\r\n"); + } + + if (status & VIC_ISTAT_DONE) { + writel(VIC_ISTAT_DONE, hrng->base + VIC_ISTAT); + //dev_info(hrng->dev, "done\r\n"); + /* + if (VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)) == + VIC_CTRL_CMD_GEN_RANDOM) { + dev_info(hrng->dev, "Need Update Buffer\r\n"); + } + */ + } + vic_rng_irq_mask_clear(hrng); + + return IRQ_HANDLED; +} + +static void vic_rng_cleanup(struct hwrng *rng) +{ + struct vic_rng *hrng = to_vic_rng(rng); + + writel(0, hrng->base + VIC_CTRL); +} + +static int vic_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct vic_rng *hrng = to_vic_rng(rng); + + vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE); + vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE); + vic_trng_cmd(hrng, VIC_CTRL_CMD_CREATE_STATE); + + vic_wait_till_idle(hrng); + max = min_t(size_t, max, (VIC_RAND_LEN * 4)); + + writel(0x0, hrng->base + VIC_MODE); + vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_RANDOM); + + vic_wait_till_idle(hrng); + memcpy_fromio(buf, hrng->base + VIC_RAND0, max); + vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE); + + vic_wait_till_idle(hrng); + return max; +} + +static int vic_rng_probe(struct platform_device *pdev) +{ + int ret; + int irq; + struct vic_rng *rng; + struct resource *res; + + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); + if (!rng){ + return -ENOMEM; + } + + platform_set_drvdata(pdev, rng); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rng->base)){ + return PTR_ERR(rng->base); + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "Couldn't get irq %d\n", irq); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, vic_rng_irq, 0, pdev->name, + (void *)rng); + if (ret) { + dev_err(&pdev->dev, "Can't get interrupt working.\n"); + return ret; + } + + rng->rng.name = pdev->name; + rng->rng.init = vic_rng_init; + rng->rng.cleanup = vic_rng_cleanup; + rng->rng.read = vic_rng_read; + + rng->dev = &pdev->dev; + + ret = devm_hwrng_register(&pdev->dev, &rng->rng); + if (ret) { + dev_err(&pdev->dev, "failed to register hwrng\n"); + return ret; + } + + dev_info(&pdev->dev, "Initialized\n"); + + return 0; +} + +static const struct of_device_id vic_rng_dt_ids[] = { + { .compatible = "starfive,vic-rng" }, + { } +}; +MODULE_DEVICE_TABLE(of, vic_rng_dt_ids); + +static struct platform_driver vic_rng_driver = { + .probe = vic_rng_probe, + .driver = { + .name = "vic-rng", + .of_match_table = of_match_ptr(vic_rng_dt_ids), + }, +}; + +module_platform_driver(vic_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huan Feng "); +MODULE_DESCRIPTION("Starfive VIC random number generator driver"); diff --git a/drivers/char/hw_random/starfive-vic-rng.h b/drivers/char/hw_random/starfive-vic-rng.h new file mode 100644 index 00000000000000..b3bbabde0cfb13 --- /dev/null +++ b/drivers/char/hw_random/starfive-vic-rng.h @@ -0,0 +1,167 @@ +/* + ****************************************************************************** + * @file starfive-vic-rng.h + * @author StarFive Technology + * @version V1.0 + * @date 08/13/2020 + * @brief + ****************************************************************************** + * @copy + * + * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. + */ + +#define VIC_CTRL 0x00 +#define VIC_MODE 0x04 +#define VIC_SMODE 0x08 +#define VIC_STAT 0x0C +#define VIC_IE 0x10 +#define VIC_ISTAT 0x14 +#define VIC_ALARM 0x18 +#define VIC_BUILD_ID 0x1C +#define VIC_FEATURES 0x20 +#define VIC_RAND0 0x24 +#define VIC_NPA_DATA0 0x34 +#define VIC_SEED0 0x74 +#define VIC_IA_RDATA 0xA4 +#define VIC_IA_WDATA 0xA8 +#define VIC_IA_ADDR 0xAC +#define VIC_IA_CMD 0xB0 + +/* CTRL */ +#define VIC_CTRL_CMD_NOP 0 +#define VIC_CTRL_CMD_GEN_NOISE 1 +#define VIC_CTRL_CMD_GEN_NONCE 2 +#define VIC_CTRL_CMD_CREATE_STATE 3 +#define VIC_CTRL_CMD_RENEW_STATE 4 +#define VIC_CTRL_CMD_REFRESH_ADDIN 5 +#define VIC_CTRL_CMD_GEN_RANDOM 6 +#define VIC_CTRL_CMD_ADVANCE_STATE 7 +#define VIC_CTRL_CMD_KAT 8 +#define VIC_CTRL_CMD_ZEROIZE 15 + +/* MODE */ +#define _VIC_MODE_ADDIN_PRESENT 4 +#define _VIC_MODE_PRED_RESIST 3 +#define _VIC_MODE_KAT_SEL 2 +#define _VIC_MODE_KAT_VEC 1 +#define _VIC_MODE_SEC_ALG 0 + +#define VIC_MODE_ADDIN_PRESENT (1UL << _VIC_MODE_ADDIN_PRESENT) +#define VIC_MODE_PRED_RESIST (1UL << _VIC_MODE_PRED_RESIST) +#define VIC_MODE_KAT_SEL (1UL << _VIC_MODE_KAT_SEL) +#define VIC_MODE_KAT_VEC (1UL << _VIC_MODE_KAT_VEC) +#define VIC_MODE_SEC_ALG (1UL << _VIC_MODE_SEC_ALG) + +/* SMODE */ +#define _VIC_SMODE_MAX_REJECTS 2 +#define _VIC_SMODE_SECURE_EN 1 +#define _VIC_SMODE_NONCE 0 + +#define VIC_SMODE_MAX_REJECTS(x) ((x) << _VIC_SMODE_MAX_REJECTS) +#define VIC_SMODE_SECURE_EN(x) ((x) << _VIC_SMODE_SECURE_EN) +#define VIC_SMODE_NONCE (1UL << _VIC_SMODE_NONCE) + +/* STAT */ +#define _VIC_STAT_BUSY 31 +#define _VIC_STAT_DRBG_STATE 7 +#define _VIC_STAT_SECURE 6 +#define _VIC_STAT_NONCE_MODE 5 +#define _VIC_STAT_SEC_ALG 4 +#define _VIC_STAT_LAST_CMD 0 + +#define VIC_STAT_BUSY (1UL << _VIC_STAT_BUSY) +#define VIC_STAT_DRBG_STATE (1UL << _VIC_STAT_DRBG_STATE) +#define VIC_STAT_SECURE (1UL << _VIC_STAT_SECURE) +#define VIC_STAT_NONCE_MODE (1UL << _VIC_STAT_NONCE_MODE) +#define VIC_STAT_SEC_ALG (1UL << _VIC_STAT_SEC_ALG) +#define VIC_STAT_LAST_CMD(x) (((x) >> _VIC_STAT_LAST_CMD) & 0xF) + +/* IE */ +#define _VIC_IE_GLBL 31 +#define _VIC_IE_DONE 4 +#define _VIC_IE_ALARMS 3 +#define _VIC_IE_NOISE_RDY 2 +#define _VIC_IE_KAT_COMPLETE 1 +#define _VIC_IE_ZEROIZE 0 + +#define VIC_IE_GLBL (1UL << _VIC_IE_GLBL) +#define VIC_IE_DONE (1UL << _VIC_IE_DONE) +#define VIC_IE_ALARMS (1UL << _VIC_IE_ALARMS) +#define VIC_IE_NOISE_RDY (1UL << _VIC_IE_NOISE_RDY) +#define VIC_IE_KAT_COMPLETE (1UL << _VIC_IE_KAT_COMPLETE) +#define VIC_IE_ZEROIZE (1UL << _VIC_IE_ZEROIZE) +#define VIC_IE_ALL (VIC_IE_GLBL | VIC_IE_DONE | VIC_IE_ALARMS | \ + VIC_IE_NOISE_RDY | VIC_IE_KAT_COMPLETE | VIC_IE_ZEROIZE) + +/* ISTAT */ +#define _VIC_ISTAT_DONE 4 +#define _VIC_ISTAT_ALARMS 3 +#define _VIC_ISTAT_NOISE_RDY 2 +#define _VIC_ISTAT_KAT_COMPLETE 1 +#define _VIC_ISTAT_ZEROIZE 0 + +#define VIC_ISTAT_DONE (1UL << _VIC_ISTAT_DONE) +#define VIC_ISTAT_ALARMS (1UL << _VIC_ISTAT_ALARMS) +#define VIC_ISTAT_NOISE_RDY (1UL << _VIC_ISTAT_NOISE_RDY) +#define VIC_ISTAT_KAT_COMPLETE (1UL << _VIC_ISTAT_KAT_COMPLETE) +#define VIC_ISTAT_ZEROIZE (1UL << _VIC_ISTAT_ZEROIZE) + +/* ALARMS */ +#define VIC_ALARM_ILLEGAL_CMD_SEQ (1UL << 4) +#define VIC_ALARM_FAILED_TEST_ID_OK 0 +#define VIC_ALARM_FAILED_TEST_ID_KAT_STAT 1 +#define VIC_ALARM_FAILED_TEST_ID_KAT 2 +#define VIC_ALARM_FAILED_TEST_ID_MONOBIT 3 +#define VIC_ALARM_FAILED_TEST_ID_RUN 4 +#define VIC_ALARM_FAILED_TEST_ID_LONGRUN 5 +#define VIC_ALARM_FAILED_TEST_ID_AUTOCORRELATION 6 +#define VIC_ALARM_FAILED_TEST_ID_POKER 7 +#define VIC_ALARM_FAILED_TEST_ID_REPETITION_COUNT 8 +#define VIC_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9 + +/* BUILD_ID */ +#define VIC_BUILD_ID_STEPPING(x) (((x) >> 28) & 0xF) +#define VIC_BUILD_ID_EPN(x) ((x) & 0xFFFF) + +/* FEATURES */ +#define VIC_FEATURES_AES_256(x) (((x) >> 9) & 1) +#define VIC_FEATURES_EXTRA_PS_PRESENT(x) (((x) >> 8) & 1) +#define VIC_FEATURES_DIAG_LEVEL_NS(x) (((x) >> 7) & 1) +#define VIC_FEATURES_DIAG_LEVEL_CLP800(x) (((x) >> 4) & 7) +#define VIC_FEATURES_DIAG_LEVEL_ST_HLT(x) (((x) >> 1) & 7) +#define VIC_FEATURES_SECURE_RST_STATE(x) ((x) & 1) + +/* IA_CMD */ +#define VIC_IA_CMD_GO (1UL << 31) +#define VIC_IA_CMD_WR (1) + +#define _VIC_SMODE_MAX_REJECTS_MASK 255UL +#define _VIC_SMODE_SECURE_EN_MASK 1UL +#define _VIC_SMODE_NONCE_MASK 1UL +#define _VIC_MODE_SEC_ALG_MASK 1UL +#define _VIC_MODE_ADDIN_PRESENT_MASK 1UL +#define _VIC_MODE_PRED_RESIST_MASK 1UL + +#define VIC_SMODE_SET_MAX_REJECTS(y, x) (((y) & ~(_VIC_SMODE_MAX_REJECTS_MASK << _VIC_SMODE_MAX_REJECTS)) | ((x) << _VIC_SMODE_MAX_REJECTS)) +#define VIC_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_VIC_SMODE_SECURE_EN_MASK << _VIC_SMODE_SECURE_EN)) | ((x) << _VIC_SMODE_SECURE_EN)) +#define VIC_SMODE_SET_NONCE(y, x) (((y) & ~(_VIC_SMODE_NONCE_MASK << _VIC_SMODE_NONCE)) | ((x) << _VIC_SMODE_NONCE)) +#define VIC_SMODE_GET_MAX_REJECTS(x) (((x) >> _VIC_SMODE_MAX_REJECTS) & _VIC_SMODE_MAX_REJECTS_MASK) +#define VIC_SMODE_GET_SECURE_EN(x) (((x) >> _VIC_SMODE_SECURE_EN) & _VIC_SMODE_SECURE_EN_MASK) +#define VIC_SMODE_GET_NONCE(x) (((x) >> _VIC_SMODE_NONCE) & _VIC_SMODE_NONCE_MASK) + +#define VIC_MODE_SET_SEC_ALG(y, x) (((y) & ~(_VIC_MODE_SEC_ALG_MASK << _VIC_MODE_SEC_ALG)) | ((x) << _VIC_MODE_SEC_ALG)) +#define VIC_MODE_SET_PRED_RESIST(y, x) (((y) & ~(_VIC_MODE_PRED_RESIST_MASK << _VIC_MODE_PRED_RESIST)) | ((x) << _VIC_MODE_PRED_RESIST)) +#define VIC_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_VIC_MODE_ADDIN_PRESENT_MASK << _VIC_MODE_ADDIN_PRESENT)) | ((x) << _VIC_MODE_ADDIN_PRESENT)) +#define VIC_MODE_GET_SEC_ALG(x) (((x) >> _VIC_MODE_SEC_ALG) & _VIC_MODE_SEC_ALG_MASK) +#define VIC_MODE_GET_PRED_RESIST(x) (((x) >> _VIC_MODE_PRED_RESIST) & _VIC_MODE_PRED_RESIST_MASK) +#define VIC_MODE_GET_ADDIN_PRESENT(x) (((x) >> _VIC_MODE_ADDIN_PRESENT) & _VIC_MODE_ADDIN_PRESENT_MASK) + +#define VIC_RAND_LEN 4 diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e80918be8e9c45..61b243a14f428b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -397,6 +397,7 @@ source "drivers/clk/samsung/Kconfig" source "drivers/clk/sifive/Kconfig" source "drivers/clk/socfpga/Kconfig" source "drivers/clk/sprd/Kconfig" +source "drivers/clk/starfive/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f06879d7fe98c..c154596d1ab5c6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -109,6 +109,7 @@ obj-y += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ +obj-$(CONFIG_SOC_STARFIVE_VIC7100) += starfive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig new file mode 100644 index 00000000000000..0e23c9a8a66381 --- /dev/null +++ b/drivers/clk/starfive/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +config CLK_STARFIVE_JH7100 + bool "StarFive JH7100 clock support" + depends on SOC_STARFIVE_VIC7100 || COMPILE_TEST + default y if SOC_STARFIVE_VIC7100 + help + Say yes here to support the clock controller on the StarFive JH7100 + SoC. diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile new file mode 100644 index 00000000000000..09759cc735307f --- /dev/null +++ b/drivers/clk/starfive/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +# StarFive Clock +obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c new file mode 100644 index 00000000000000..a768394c28f0a1 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7100 Clock Generator Driver + * This is part of the PCR (Power/Clock/Reset) Management Unit Driver + * + * FIXME PRELIMINARY + * For now, all clocks are implemented as fixed-factor clocks relative to osc0 + * + * TODO Real clock topology, clock register programming + * PLL0 used for system main logic, including CPU, bus + * PLL1 output to support DDR, DLA and DSP + * PLL2 output to support slow speed peripherals, video input and video output + * + * Copyright (C) 2021 Glider bv + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const struct jh7100_clk { + const char *name; + unsigned int mult; + unsigned int div; +} jh7100_clks[] = { + [JH7100_CLK_AXI] = { "axi", .mult = 20, .div = 1 }, + [JH7100_CLK_AHB0] = { "ahb0", .mult = 10, .div = 1 }, + [JH7100_CLK_AHB2] = { "ahb2", .mult = 5, .div = 1 }, + [JH7100_CLK_APB1] = { "apb1", .mult = 5, .div = 1 }, + [JH7100_CLK_APB2] = { "apb2", .mult = 5, .div = 1 }, + [JH7100_CLK_VPU] = { "vpu", .mult = 16, .div = 1 }, + [JH7100_CLK_JPU] = { "jpu", .mult = 40, .div = 3 }, + [JH7100_CLK_PWM] = { "pwm", .mult = 5, .div = 1 }, + [JH7100_CLK_DWMMC_BIU] = { "dwmmc-biu", .mult = 4, .div = 1 }, + [JH7100_CLK_DWMMC_CIU] = { "dwmmc-ciu", .mult = 4, .div = 1 }, + [JH7100_CLK_UART] = { "uart", .mult = 4, .div = 1 }, + [JH7100_CLK_HS_UART] = { "hs_uart", .mult = 297, .div = 100 }, + [JH7100_CLK_I2C0] = { "i2c0", .mult = 99, .div = 50 }, + [JH7100_CLK_I2C2] = { "i2c2", .mult = 2, .div = 1 }, + [JH7100_CLK_QSPI] = { "qspi", .mult = 2, .div = 1 }, + [JH7100_CLK_SPI] = { "spi", .mult = 2, .div = 1 }, + [JH7100_CLK_GMAC] = { "gmac", .mult = 1, .div = 1 }, + [JH7100_CLK_HF] = { "hf", .mult = 1, .div = 1 }, + [JH7100_CLK_RTC] = { "rtc", .mult = 1, .div = 4 } +}; + +struct clk_starfive_jh7100_priv { + struct clk_onecell_data data; + void __iomem *base; + struct clk *clks[]; +}; + +static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + unsigned int nclks = ARRAY_SIZE(jh7100_clks); + struct clk_starfive_jh7100_priv *priv; + const char *osc0_name; + struct clk_hw *hw; + struct clk *osc0; + unsigned int i; + + priv = devm_kzalloc(dev, struct_size(priv, clks, nclks), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + osc0 = devm_clk_get(dev, "osc0"); + if (IS_ERR(osc0)) + return PTR_ERR(osc0); + + osc0_name = __clk_get_name(osc0); + + for (i = 0; i < nclks; i++) { + hw = devm_clk_hw_register_fixed_factor(dev, + jh7100_clks[i].name, osc0_name, 0, jh7100_clks[i].mult, + jh7100_clks[i].div); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->clks[i] = hw->clk; + } + + priv->data.clks = priv->clks; + priv->data.clk_num = nclks; + + return of_clk_add_provider(np, of_clk_src_onecell_get, &priv->data); +} + +static const struct of_device_id clk_starfive_jh7100_match[] = { + { + .compatible = "starfive,jh7100-clkgen", + }, + { /* sentinel */ } +}; +static struct platform_driver clk_starfive_jh7100_driver = { + .driver = { + .name = "clk-starfive-jh7100", + .of_match_table = clk_starfive_jh7100_match, + }, +}; + +static int __init clk_starfive_jh7100_init(void) +{ + return platform_driver_probe(&clk_starfive_jh7100_driver, + clk_starfive_jh7100_probe); +} + +subsys_initcall(clk_starfive_jh7100_init); + +MODULE_DESCRIPTION("StarFive JH7100 Clock Generator Driver"); +MODULE_AUTHOR("Geert Uytterhoeven "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 39b5b46e880f29..025d8a9dcfb58b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -181,6 +181,13 @@ config DW_AXI_DMAC NOTE: This driver wasn't tested on 64 bit platform because of lack 64 bit platform with Synopsys DW AXI DMAC. +config DW_AXI_DMAC_STARFIVE + tristate "Synopsys DesignWare AXI DMA support for StarFive SOC" + depends on SOC_STARFIVE_VIC7100 + help + Enable support for Synopsys DesignWare AXI DMA controller. + NOTE: It's for StarFive SOC. + config EP93XX_DMA bool "Cirrus Logic EP93xx DMA support" depends on ARCH_EP93XX || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index aa69094e35470c..7d332af8b96c6f 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/ +obj-$(CONFIG_DW_AXI_DMAC_STARFIVE) += dw-axi-dmac-starfive/ obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_DW_EDMA) += dw-edma/ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o diff --git a/drivers/dma/dw-axi-dmac-starfive/Makefile b/drivers/dma/dw-axi-dmac-starfive/Makefile new file mode 100644 index 00000000000000..c30fd928982f9e --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_DW_AXI_DMAC_STARFIVE) += starfive_dmaengine_memcpy.o dw-axi-dmac-starfive-misc.o \ No newline at end of file diff --git a/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c b/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c new file mode 100644 index 00000000000000..a1189bbe1e5bae --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/dw-axi-dmac-starfive-misc.c @@ -0,0 +1,322 @@ +/* + * Copyright 2020 StarFive, Inc + * + * DW AXI dma driver for StarFive SoC VIC7100. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "dwaxidma" +#define AXIDMA_IOC_MAGIC 'A' +#define AXIDMA_IOCGETCHN _IO(AXIDMA_IOC_MAGIC, 0) +#define AXIDMA_IOCCFGANDSTART _IO(AXIDMA_IOC_MAGIC, 1) +#define AXIDMA_IOCGETSTATUS _IO(AXIDMA_IOC_MAGIC, 2) +#define AXIDMA_IOCRELEASECHN _IO(AXIDMA_IOC_MAGIC, 3) + +#define AXI_DMA_MAX_CHANS 20 + +#define DMA_CHN_UNUSED 0 +#define DMA_CHN_USED 1 +#define DMA_STATUS_UNFINISHED 0 +#define DMA_STATUS_FINISHED 1 + +/* for DEBUG*/ +//#define DW_DMA_CHECK_RESULTS +//#define DW_DMA_PRINT_MEM +//#define DW_DMA_FLUSH_DESC + +struct axidma_chncfg { + unsigned long src_addr; /*dma addr*/ + unsigned long dst_addr; /*dma addr*/ + unsigned long virt_src; /*mmap src addr*/ + unsigned long virt_dst; /*mmap dst addr*/ + unsigned long phys; /*desc phys addr*/ + unsigned int len; /*transport lenth*/ + int mem_fd; /*fd*/ + unsigned char chn_num; /*dma channels number*/ + unsigned char status; /*dma transport status*/ +}; + +struct axidma_chns { + struct dma_chan *dma_chan; + unsigned char used; + unsigned char status; + unsigned char reserve[2]; +}; + +struct axidma_chns channels[AXI_DMA_MAX_CHANS]; +#ifdef DW_DMA_PRINT_MEM +void print_in_line_u64(u8 *p_name, u64 *p_buf, u32 len) +{ + u32 i, j; + u32 line; + u32* ptmp; + u32 len_tmp; + u32 rest = len / 4; + + printk("%s: 0x%#llx, 0x%x\n", + p_name, dw_virt_to_phys((void *)p_buf), len); + + if(len >= 0x1000) + len_tmp = 0x1000 / 32; //print 128 size of memory. + else + len_tmp = len / 8; //print real 100% size of memory. + + rest = len / 4; //one line print 8 u32 + + for (i = 0; i < len_tmp; i += 4, rest -= line) { + if (!(i % 4)) + printk(KERN_CONT KERN_INFO" %#llx: ", + dw_virt_to_phys((void *)(p_buf + i))); + + ptmp = (u32*)(p_buf + i); + line = (rest > 8) ? 8 : rest; + + for (j = 0; j < line; j++) + printk(KERN_CONT KERN_INFO "%08x ", *(ptmp + j)); + + printk(KERN_CONT KERN_INFO"\n"); + } +} +#endif + +static int axidma_open(struct inode *inode, struct file *file) +{ + /*Open: do nothing*/ + return 0; +} + +static int axidma_release(struct inode *inode, struct file *file) +{ + /* Release: do nothing */ + return 0; +} + +static ssize_t axidma_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* Write: do nothing */ + return 0; +} + +static void dma_complete_func(void *status) +{ + *(char *)status = DMA_STATUS_FINISHED; +} + +static long axidma_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int i, ret; + dma_cap_mask_t mask; + dma_cookie_t cookie; + struct dma_device *dma_dev; + struct axidma_chncfg chncfg; + struct dma_async_tx_descriptor *tx; + +#ifdef DW_DMA_FLUSH_DESC + void *des_chncfg = &chncfg; + chncfg.phys = dw_virt_to_phys(des_chncfg); +#endif + memset(&chncfg, 0, sizeof(struct axidma_chncfg)); + + switch(cmd) { + case AXIDMA_IOCGETCHN: + for(i = 0; i < AXI_DMA_MAX_CHANS; i++) { + if(DMA_CHN_UNUSED == channels[i].used) + break; + } + if(AXI_DMA_MAX_CHANS == i) { + printk("Get dma chn failed, because no idle channel\n"); + goto error; + } else { + channels[i].used = DMA_CHN_USED; + channels[i].status = DMA_STATUS_UNFINISHED; + chncfg.status = DMA_STATUS_UNFINISHED; + chncfg.chn_num = i; + } + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + channels[i].dma_chan = dma_request_channel(mask, NULL, NULL); + if(!channels[i].dma_chan) { + printk("dma request channel failed\n"); + channels[i].used = DMA_CHN_UNUSED; + goto error; + } + ret = copy_to_user((void __user *)arg, &chncfg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy to user failed\n"); + goto error; + } + break; + case AXIDMA_IOCCFGANDSTART: +#ifdef DW_DMA_CHECK_RESULTS + void *src,*dst; +#endif + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if((chncfg.chn_num >= AXI_DMA_MAX_CHANS) || + (!channels[chncfg.chn_num].dma_chan)) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + dma_dev = channels[chncfg.chn_num].dma_chan->device; +#ifdef DW_DMA_FLUSH_DESC + starfive_flush_dcache(chncfg.phys,sizeof(chncfg)); +#endif +#ifdef DW_DMA_CHECK_RESULTS + src = dw_phys_to_virt(chncfg.src_addr); + dst = dw_phys_to_virt(chncfg.dst_addr); +#endif + starfive_flush_dcache(chncfg.src_addr, chncfg.len); + + tx = dma_dev->device_prep_dma_memcpy( + channels[chncfg.chn_num].dma_chan, + chncfg.dst_addr, chncfg.src_addr, chncfg.len, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if(!tx){ + printk("Failed to prepare DMA memcpy\n"); + goto error; + } + channels[chncfg.chn_num].status = DMA_STATUS_UNFINISHED; + tx->callback_param = &channels[chncfg.chn_num].status; + tx->callback = dma_complete_func; + cookie = tx->tx_submit(tx); + if(dma_submit_error(cookie)) { + printk("Failed to dma tx_submit\n"); + goto error; + } + dma_async_issue_pending(channels[chncfg.chn_num].dma_chan); + /*flush dcache*/ + starfive_flush_dcache(chncfg.dst_addr, chncfg.len); +#ifdef DW_DMA_PRINT_MEM + print_in_line_u64((u8 *)"src", (u64 *)src, chncfg.len); + print_in_line_u64((u8 *)"dst", (u64 *)dst, chncfg.len); +#endif +#ifdef DW_DMA_CHECK_RESULTS + if(memcmp(src, dst, chncfg.len)) + printk("check data faild.\n"); + else + printk("check data ok.\n"); +#endif + break; + + case AXIDMA_IOCGETSTATUS: + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if(chncfg.chn_num >= AXI_DMA_MAX_CHANS) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + + chncfg.status = channels[chncfg.chn_num].status; + + ret = copy_to_user((void __user *)arg, &chncfg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy to user failed\n"); + goto error; + } + break; + + case AXIDMA_IOCRELEASECHN: + ret = copy_from_user(&chncfg, (void __user *)arg, + sizeof(struct axidma_chncfg)); + if(ret) { + printk("Copy from user failed\n"); + goto error; + } + + if((chncfg.chn_num >= AXI_DMA_MAX_CHANS) || + (!channels[chncfg.chn_num].dma_chan)) { + printk("chn_num[%d] is invalid\n", chncfg.chn_num); + goto error; + } + + dma_release_channel(channels[chncfg.chn_num].dma_chan); + channels[chncfg.chn_num].used = DMA_CHN_UNUSED; + channels[chncfg.chn_num].status = DMA_STATUS_UNFINISHED; + break; + + default: + printk("Don't support cmd [%d]\n", cmd); + break; + } + return 0; + +error: + return -EFAULT; +} + +/* + * Kernel Interfaces + */ +static struct file_operations axidma_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = axidma_write, + .unlocked_ioctl = axidma_unlocked_ioctl, + .open = axidma_open, + .release = axidma_release, +}; + +static struct miscdevice axidma_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .fops = &axidma_fops, +}; + +static int __init axidma_init(void) +{ + int ret = misc_register(&axidma_miscdev); + if(ret) { + printk (KERN_ERR "cannot register miscdev (err=%d)\n", ret); + return ret; + } + + memset(&channels, 0, sizeof(channels)); + + return 0; +} + +static void __exit axidma_exit(void) +{ + misc_deregister(&axidma_miscdev); +} + +module_init(axidma_init); +module_exit(axidma_exit); + +MODULE_AUTHOR("samin.guo"); +MODULE_DESCRIPTION("DW Axi Dmac Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c b/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c new file mode 100644 index 00000000000000..aee72c10d77fa7 --- /dev/null +++ b/drivers/dma/dw-axi-dmac-starfive/starfive_dmaengine_memcpy.c @@ -0,0 +1,287 @@ +/* + * Copyright 2020 StarFive, Inc + * + * API for dma mem2mem. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static volatile int dma_finished = 0; +static DECLARE_WAIT_QUEUE_HEAD(wq); + +u64 dw_virt_to_phys(void *vaddr) +{ + u64 pfn_offset = ((u64)vaddr) & 0xfff; + + return _dw_virt_to_phys((u64 *)vaddr) + pfn_offset; +} +EXPORT_SYMBOL(dw_virt_to_phys); + +void *dw_phys_to_virt(u64 phys) +{ + u64 pfn_offset = phys & 0xfff; + + return (void *)(_dw_phys_to_virt(phys) + pfn_offset); +} +EXPORT_SYMBOL(dw_phys_to_virt); + +static void tx_callback(void *dma_async_param) +{ + dma_finished = 1; + wake_up_interruptible(&wq); +} + +static int _dma_async_alloc_buf(struct device *dma_dev, + void **src, void **dst, size_t size, + dma_addr_t *src_dma, dma_addr_t *dst_dma) +{ + *src = dma_alloc_coherent(dma_dev, size, src_dma, GFP_KERNEL); + if(!(*src)) { + DMA_DEBUG("src alloc err.\n"); + goto _FAILED_ALLOC_SRC; + } + + *dst = dma_alloc_coherent(dma_dev, size, dst_dma, GFP_KERNEL); + if(!(*dst)) { + DMA_DEBUG("dst alloc err.\n"); + goto _FAILED_ALLOC_DST; + } + + return 0; + +_FAILED_ALLOC_DST: + dma_free_coherent(dma_dev, size, *src, *src_dma); + +_FAILED_ALLOC_SRC: + dma_free_coherent(dma_dev, size, *dst, *dst_dma); + + return -1; +} + +static int _dma_async_prebuf(void *src, void *dst, size_t size) +{ + memset((u8 *)src, 0xff, size); + memset((u8 *)dst, 0x00, size); + return 0; +} + +static int _dma_async_check_data(void *src, void *dst, size_t size) +{ + return memcmp(src, dst, size); +} + +static void _dma_async_release(struct dma_chan *chan) +{ + dma_release_channel(chan); +} + +static struct dma_chan *_dma_get_channel(enum dma_transaction_type tx_type) +{ + dma_cap_mask_t dma_mask; + + dma_cap_zero(dma_mask); + dma_cap_set(tx_type, dma_mask); + + return dma_request_channel(dma_mask, NULL, NULL); +} + +static struct dma_async_tx_descriptor *_dma_async_get_desc( + struct dma_chan *chan, + dma_addr_t src_dma, dma_addr_t dst_dma, + size_t size) +{ + dma_finished = 0; + return dmaengine_prep_dma_memcpy(chan, dst_dma, src_dma, size, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +} + +static void _dma_async_do_start(struct dma_async_tx_descriptor *desc, + struct dma_chan *chan) +{ + dma_cookie_t dma_cookie = dmaengine_submit(desc); + if (dma_submit_error(dma_cookie)) + DMA_DEBUG("Failed to do DMA tx_submit\n"); + + dma_async_issue_pending(chan); + wait_event_interruptible(wq, dma_finished); +} + +int dw_dma_async_do_memcpy(void *src, void *dst, size_t size) +{ + int ret; + struct device *dma_dev; + struct dma_chan *chan; + dma_addr_t src_dma, dst_dma; + struct dma_async_tx_descriptor *desc; + + const struct iommu_ops *iommu; + u64 dma_addr = 0, dma_size = 0; + + dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL); + if(!dma_dev){ + dev_err(dma_dev, "kmalloc error.\n"); + return -ENOMEM; + } + + dma_dev->bus = NULL; + dma_dev->coherent_dma_mask = 0xffffffff; + + iort_dma_setup(dma_dev, &dma_addr, &dma_size); + iommu = iort_iommu_configure_id(dma_dev, NULL); + if (PTR_ERR(iommu) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + arch_setup_dma_ops(dma_dev, dst_dma, dma_size, iommu, true); + + if(_dma_async_alloc_buf(dma_dev, &src, &dst, size, &src_dma, &dst_dma)) { + dev_err(dma_dev, "Err alloc.\n"); + return -ENOMEM; + } + + DMA_DEBUG("src=%#llx, dst=%#llx\n", (u64)src, (u64)dst); + DMA_DEBUG("dma_src=%#x dma_dst=%#x\n", (u32)src_dma, (u32)dst_dma); + + _dma_async_prebuf(src, dst, size); + + chan = _dma_get_channel(DMA_MEMCPY); + if(!chan ){ + DMA_PRINTK("Err get chan.\n"); + return -EBUSY; + } + DMA_DEBUG("get chan ok.\n"); + + desc = _dma_async_get_desc(chan, src_dma, dst_dma, size); + if(!desc){ + DMA_PRINTK("Err get desc.\n"); + dma_release_channel(chan); + return -ENOMEM; + } + DMA_DEBUG("get desc ok.\n"); + + desc->callback = tx_callback; + + starfive_flush_dcache(src_dma, size); + starfive_flush_dcache(dst_dma, size); + + _dma_async_do_start(desc, chan); + _dma_async_release(chan); + + ret = _dma_async_check_data(src, dst, size); + + dma_free_coherent(dma_dev, size, src, src_dma); + dma_free_coherent(dma_dev, size, dst, dst_dma); + + return ret; +} +EXPORT_SYMBOL(dw_dma_async_do_memcpy); + +/* +* phys addr for dma. +*/ +int dw_dma_memcpy_raw(dma_addr_t src_dma, dma_addr_t dst_dma, size_t size) +{ + struct dma_chan *chan; + struct device *dma_dev; + struct dma_async_tx_descriptor *desc; + + const struct iommu_ops *iommu; + u64 dma_addr = 0, dma_size = 0; + + dma_dev = kzalloc(sizeof(*dma_dev), GFP_KERNEL); + if(!dma_dev){ + DMA_PRINTK("kmalloc error.\n"); + return -ENOMEM; + } + + dma_dev->bus = NULL; + dma_dev->coherent_dma_mask = 0xffffffff; + + iort_dma_setup(dma_dev, &dma_addr, &dma_size); + iommu = iort_iommu_configure_id(dma_dev, NULL); + if (PTR_ERR(iommu) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + arch_setup_dma_ops(dma_dev, dst_dma, dma_size, iommu, true); + + chan = _dma_get_channel(DMA_MEMCPY); + if(!chan){ + DMA_PRINTK("Error get chan.\n"); + return -EBUSY; + } + DMA_DEBUG("get chan ok.\n"); + + DMA_DEBUG("src_dma=%#llx, dst_dma=%#llx \n", src_dma, dst_dma); + desc = _dma_async_get_desc(chan, src_dma, dst_dma, size); + if(!desc){ + DMA_PRINTK("Error get desc.\n"); + dma_release_channel(chan); + return -ENOMEM; + } + DMA_DEBUG("get desc ok.\n"); + + desc->callback = tx_callback; + + starfive_flush_dcache(src_dma, size); + starfive_flush_dcache(dst_dma, size); + + _dma_async_do_start(desc, chan); + _dma_async_release(chan); + + return 0; +} +EXPORT_SYMBOL(dw_dma_memcpy_raw); + +/* +*virtl addr for cpu. +*/ +int dw_dma_memcpy(void *src, void *dst, size_t size) +{ + dma_addr_t src_dma, dst_dma; + + src_dma = dw_virt_to_phys(src); + dst_dma = dw_virt_to_phys(dst); + + dw_dma_memcpy_raw(src_dma, dst_dma, size); + return 0; +} +EXPORT_SYMBOL(dw_dma_memcpy); + +int dw_dma_mem2mem_test(void) +{ + int ret; + void *src = NULL; + void *dst = NULL; + size_t size = 256; + + ret = dw_dma_async_do_memcpy(src, dst, size); + if(ret){ + DMA_PRINTK("memcpy failed.\n"); + } else { + DMA_PRINTK("memcpy ok.\n"); + } + + return ret; +} diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index d9e4ac3edb4ea1..76a6585088463d 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -32,6 +32,8 @@ #include "../dmaengine.h" #include "../virt-dma.h" +#include + /* * The set of bus widths supported by the DMA controller. DW AXI DMAC supports * master data bus width up to 512 bits (for both AXI master interfaces), but @@ -148,24 +150,43 @@ static inline u32 axi_chan_irq_read(struct axi_dma_chan *chan) return axi_chan_ioread32(chan, CH_INTSTATUS); } +static inline bool axi_chan_get_nr8(struct axi_dma_chan *chan) +{ + return chan->chip->flag->nr_chan_8; +} + static inline void axi_chan_disable(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT); - val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)) { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN_8); + val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT_8); + val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHEN_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN); + val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT); + val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + } } static inline void axi_chan_enable(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT | - BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)) { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN_8); + val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT_8 | + BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHEN_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHEN); + val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT | + BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + } } static inline bool axi_chan_is_hw_enable(struct axi_dma_chan *chan) @@ -384,6 +405,27 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, irq_mask |= DWAXIDMAC_IRQ_SUSPENDED; axi_chan_irq_set(chan, irq_mask); + /* flush all the desc */ +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + if(chan->chip->flag->need_flush) { + int count = atomic_read(&chan->descs_allocated); + int i; + + for (i = 0; i < count; i++) { + starfive_flush_dcache(first->hw_desc[i].llp, + sizeof(*first->hw_desc[i].lli)); + + dev_dbg(chan->chip->dev, + "sar:%#llx dar:%#llx llp:%#llx ctl:0x%x:%08x\n", + first->hw_desc[i].lli->sar, + first->hw_desc[i].lli->dar, + first->hw_desc[i].lli->llp, + first->hw_desc[i].lli->ctl_hi, + first->hw_desc[i].lli->ctl_lo); + } + } +#endif + axi_chan_enable(chan); } @@ -1070,8 +1112,10 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id) if (status & DWAXIDMAC_IRQ_ALL_ERR) axi_chan_handle_err(chan, status); - else if (status & DWAXIDMAC_IRQ_DMA_TRF) + else if (status & DWAXIDMAC_IRQ_DMA_TRF) { axi_chan_block_xfer_complete(chan); + dev_dbg(chip->dev, "axi_chan_block_xfer_complete.\n"); + } } /* Re-enable interrupts */ @@ -1126,10 +1170,17 @@ static int dma_chan_pause(struct dma_chan *dchan) spin_lock_irqsave(&chan->vc.lock, flags); - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT | - BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT; - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); + if(axi_chan_get_nr8(chan)){ + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP_8); + val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT_8 | + BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT_8; + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP); + val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT | + BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT; + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP, val); + } do { if (axi_chan_irq_read(chan) & DWAXIDMAC_IRQ_SUSPENDED) @@ -1152,11 +1203,17 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan) { u32 val; - val = axi_dma_ioread32(chan->chip, DMAC_CHEN); - val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT); - val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT); - axi_dma_iowrite32(chan->chip, DMAC_CHEN, val); - + if(axi_chan_get_nr8(chan)){ + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP_8); + val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT_8); + val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT_8); + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP_8, val); + } else { + val = axi_dma_ioread32(chan->chip, DMAC_CHSUSP); + val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT); + val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT); + axi_dma_iowrite32(chan->chip, DMAC_CHSUSP, val); + } chan->is_paused = false; } @@ -1248,6 +1305,13 @@ static int parse_device_properties(struct axi_dma_chip *chip) chip->dw->hdata->nr_channels = tmp; + if(chip->dw->hdata->nr_channels > 8){ + chip->flag->nr_chan_8 = true; +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + chip->flag->need_flush = true; +#endif + } + ret = device_property_read_u32(dev, "snps,dma-masters", &tmp); if (ret) return ret; @@ -1309,6 +1373,7 @@ static int dw_probe(struct platform_device *pdev) struct resource *mem; struct dw_axi_dma *dw; struct dw_axi_dma_hcfg *hdata; + struct dw_dma_flag *flag; u32 i; int ret; @@ -1324,9 +1389,14 @@ static int dw_probe(struct platform_device *pdev) if (!hdata) return -ENOMEM; + flag = devm_kzalloc(&pdev->dev, sizeof(*flag), GFP_KERNEL); + if (!flag) + return -ENOMEM; + chip->dw = dw; chip->dev = &pdev->dev; chip->dw->hdata = hdata; + chip->flag = flag; chip->irq = platform_get_irq(pdev, 0); if (chip->irq < 0) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index b69897887c7654..0e454a926a82c8 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -5,6 +5,8 @@ * Synopsys DesignWare AXI DMA Controller driver. * * Author: Eugeniy Paltsev + * Samin.guo + * add support for (channels > 8). 2020. */ #ifndef _AXI_DMA_PLATFORM_H @@ -18,10 +20,17 @@ #include "../virt-dma.h" -#define DMAC_MAX_CHANNELS 8 +#define DMAC_MAX_CHANNELS 16 #define DMAC_MAX_MASTERS 2 #define DMAC_MAX_BLK_SIZE 0x200000 +struct dw_dma_flag { + bool nr_chan_8; +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + bool need_flush; +#endif +}; + struct dw_axi_dma_hcfg { u32 nr_channels; u32 nr_masters; @@ -68,6 +77,7 @@ struct axi_dma_chip { struct clk *core_clk; struct clk *cfgr_clk; struct dw_axi_dma *dw; + struct dw_dma_flag *flag; }; /* LLI == Linked List Item */ @@ -139,6 +149,15 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan) #define DMAC_CHEN 0x018 /* R/W DMAC Channel Enable */ #define DMAC_CHEN_L 0x018 /* R/W DMAC Channel Enable 00-31 */ #define DMAC_CHEN_H 0x01C /* R/W DMAC Channel Enable 32-63 */ +#define DMAC_CHSUSP 0x018 /* R/W DMAC Channel suspend */ +#define DMAC_CHABORT 0x018 /* R/W DMAC Channel Abort */ + +#define DMAC_CHEN_8 0x018 /* R/W DMAC Channel Enable */ +#define DMAC_CHEN_L_8 0x018 /* R/W DMAC Channel Enable */ +#define DMAC_CHEN_H_8 0x01C /* R/W DMAC Channel Enable */ +#define DMAC_CHSUSP_8 0x020 /* R/W DMAC Channel Suspend */ +#define DMAC_CHABORT_8 0x028 /* R/W DMAC Channel Abort */ + #define DMAC_INTSTATUS 0x030 /* R DMAC Interrupt Status */ #define DMAC_COMMON_INTCLEAR 0x038 /* W DMAC Interrupt Clear */ #define DMAC_COMMON_INTSTATUS_ENA 0x040 /* R DMAC Interrupt Status Enable */ @@ -199,6 +218,19 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan) #define DMAC_CHAN_SUSP_SHIFT 16 #define DMAC_CHAN_SUSP_WE_SHIFT 24 +#define DMAC_CHAN_ABORT_SHIFT 32 +#define DMAC_CHAN_ABORT_WE_SHIFT 40 + + +#define DMAC_CHAN_EN_SHIFT_8 0 +#define DMAC_CHAN_EN_WE_SHIFT_8 16 + +#define DMAC_CHAN_SUSP_SHIFT_8 0 +#define DMAC_CHAN_SUSP_WE_SHIFT_8 16 + +#define DMAC_CHAN_ABORT_SHIFT_8 0 +#define DMAC_CHAN_ABORT_WE_SHIFT_8 16 + /* CH_CTL_H */ #define CH_CTL_H_ARLEN_EN BIT(6) #define CH_CTL_H_ARLEN_POS 7 @@ -255,7 +287,7 @@ enum { #define CH_CTL_L_SRC_MAST BIT(0) /* CH_CFG_H */ -#define CH_CFG_H_PRIORITY_POS 17 +#define CH_CFG_H_PRIORITY_POS 15 #define CH_CFG_H_HS_SEL_DST_POS 4 #define CH_CFG_H_HS_SEL_SRC_POS 3 enum { diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1dd0ec6727fde2..26630e4852c077 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -542,6 +542,14 @@ config GPIO_SIFIVE help Say yes here to support the GPIO device on SiFive SoCs. +config GPIO_STARFIVE_JH7100 + bool "StarFive JH7100 GPIO support" + depends on OF_GPIO + select GPIOLIB_IRQCHIP + default y if SOC_STARFIVE_VIC7100 + help + Say yes here to support the GPIO device on StarFive JH7100 SoC. + config GPIO_SIOX tristate "SIOX GPIO support" depends on SIOX diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d7c81e1611a4d5..939922eaf5f355 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -132,6 +132,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o +obj-$(CONFIG_GPIO_STARFIVE_JH7100) += gpio-starfive-jh7100.o obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o diff --git a/drivers/gpio/gpio-starfive-jh7100.c b/drivers/gpio/gpio-starfive-jh7100.c new file mode 100644 index 00000000000000..039b020d721f07 --- /dev/null +++ b/drivers/gpio/gpio-starfive-jh7100.c @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPIO driver for StarFive JH7100 SoC + * + * Copyright (C) 2020 Shanghai StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#define GPIO_EN 0x0 +#define GPIO_IS_LOW 0x10 +#define GPIO_IS_HIGH 0x14 +#define GPIO_IBE_LOW 0x18 +#define GPIO_IBE_HIGH 0x1c +#define GPIO_IEV_LOW 0x20 +#define GPIO_IEV_HIGH 0x24 +#define GPIO_IE_LOW 0x28 +#define GPIO_IE_HIGH 0x2c +#define GPIO_IC_LOW 0x30 +#define GPIO_IC_HIGH 0x34 +//read only +#define GPIO_RIS_LOW 0x38 +#define GPIO_RIS_HIGH 0x3c +#define GPIO_MIS_LOW 0x40 +#define GPIO_MIS_HIGH 0x44 +#define GPIO_DIN_LOW 0x48 +#define GPIO_DIN_HIGH 0x4c + +#define GPIO_DOUT_X_REG 0x50 +#define GPIO_DOEN_X_REG 0x54 + +#define MAX_GPIO 64 + +struct starfive_gpio { + raw_spinlock_t lock; + void __iomem *base; + struct gpio_chip gc; + unsigned long enabled; + unsigned int trigger[MAX_GPIO]; + unsigned int irq_parent[MAX_GPIO]; +}; + +static DEFINE_SPINLOCK(sfg_lock); + +static void __iomem *gpio_base; + +static int starfive_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return -EINVAL; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int starfive_direction_output(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return -EINVAL; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8); + writel_relaxed(value, chip->base + GPIO_DOUT_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int starfive_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + + return readl_relaxed(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1; +} + +static int starfive_get_value(struct gpio_chip *gc, unsigned int offset) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + int value; + + if (offset >= gc->ngpio) + return -EINVAL; + + if (offset < 32) { + value = readl_relaxed(chip->base + GPIO_DIN_LOW); + value = (value >> offset) & 0x1; + } else { + value = readl_relaxed(chip->base + GPIO_DIN_HIGH); + value = (value >> (offset - 32)) & 0x1; + } + + return value; +} + +static void starfive_set_value(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned long flags; + + if (offset >= gc->ngpio) + return; + + raw_spin_lock_irqsave(&chip->lock, flags); + writel_relaxed(value, chip->base + GPIO_DOUT_X_REG + offset * 8); + raw_spin_unlock_irqrestore(&chip->lock, flags); +} + +static void starfive_set_ie(struct starfive_gpio *chip, int offset) +{ + unsigned long flags; + int old_value, new_value; + int reg_offset, index; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + raw_spin_lock_irqsave(&chip->lock, flags); + old_value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + new_value = old_value | (1 << index); + writel_relaxed(new_value, chip->base + GPIO_IE_LOW + reg_offset); + raw_spin_unlock_irqrestore(&chip->lock, flags); +} + +static int starfive_irq_set_type(struct irq_data *d, unsigned int trigger) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d); + unsigned int reg_is, reg_ibe, reg_iev; + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return -EINVAL; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + switch (trigger) { + case IRQ_TYPE_LEVEL_HIGH: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is &= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_LEVEL_LOW: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is &= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev &= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_BOTH: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + //reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe |= ~(1 << index); + //reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + //writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_RISING: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev |= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + case IRQ_TYPE_EDGE_FALLING: + reg_is = readl_relaxed(chip->base + GPIO_IS_LOW + reg_offset); + reg_ibe = readl_relaxed(chip->base + GPIO_IBE_LOW + reg_offset); + reg_iev = readl_relaxed(chip->base + GPIO_IEV_LOW + reg_offset); + reg_is |= ~(1 << index); + reg_ibe &= ~(1 << index); + reg_iev &= (1 << index); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + writel_relaxed(reg_is, chip->base + GPIO_IS_LOW + reg_offset); + break; + } + + chip->trigger[offset] = trigger; + starfive_set_ie(chip, offset); + return 0; +} + +/* chained_irq_{enter,exit} already mask the parent */ +static void starfive_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned int value; + int offset = irqd_to_hwirq(d); + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + value &= ~(0x1 << index); + writel_relaxed(value, chip->base + GPIO_IE_LOW + reg_offset); +} + +static void starfive_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + unsigned int value; + int offset = irqd_to_hwirq(d); + int reg_offset, index; + + if (offset < 0 || offset >= gc->ngpio) + return; + + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + value = readl_relaxed(chip->base + GPIO_IE_LOW + reg_offset); + value |= (0x1 << index); + writel_relaxed(value, chip->base + GPIO_IE_LOW + reg_offset); +} + +static void starfive_irq_enable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d); + + starfive_irq_unmask(d); + assign_bit(offset, &chip->enabled, 1); +} + +static void starfive_irq_disable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct starfive_gpio *chip = gpiochip_get_data(gc); + int offset = irqd_to_hwirq(d) % MAX_GPIO; // must not fail + + assign_bit(offset, &chip->enabled, 0); + starfive_set_ie(chip, offset); +} + +static struct irq_chip starfive_irqchip = { + .name = "starfive-jh7100-gpio", + .irq_set_type = starfive_irq_set_type, + .irq_mask = starfive_irq_mask, + .irq_unmask = starfive_irq_unmask, + .irq_enable = starfive_irq_enable, + .irq_disable = starfive_irq_disable, +}; + +static irqreturn_t starfive_irq_handler(int irq, void *gc) +{ + int offset; + int reg_offset, index; + unsigned int value; + unsigned long flags; + struct starfive_gpio *chip = gc; + + for (offset = 0; offset < 64; offset++) { + if (offset < 32) { + reg_offset = 0; + index = offset; + } else { + reg_offset = 4; + index = offset - 32; + } + + raw_spin_lock_irqsave(&chip->lock, flags); + value = readl_relaxed(chip->base + GPIO_MIS_LOW + reg_offset); + if (value & BIT(index)) + writel_relaxed(BIT(index), chip->base + GPIO_IC_LOW + + reg_offset); + + /* generic_handle_irq(irq_find_mapping(chip->gc.irq.domain, offset)); */ + raw_spin_unlock_irqrestore(&chip->lock, flags); + } + + return IRQ_HANDLED; +} + +void sf_vic_gpio_dout_reverse(int gpio, int en) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOUT_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0x1 << 31); + value |= (en & 0x1) << 31; + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_reverse); + +void sf_vic_gpio_dout_value(int gpio, int v) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOUT_X_REG; + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_value); + +void sf_vic_gpio_dout_low(int gpio) +{ + sf_vic_gpio_dout_value(gpio, 0); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_low); + +void sf_vic_gpio_dout_high(int gpio) +{ + sf_vic_gpio_dout_value(gpio, 1); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_dout_high); + +void sf_vic_gpio_doen_reverse(int gpio, int en) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOEN_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0x1 << 31); + value |= (en & 0x1) << 31; + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_reverse); + +void sf_vic_gpio_doen_value(int gpio, int v) +{ + unsigned int value; + int offset; + + if (!gpio_base) + return; + + offset = gpio * 8 + GPIO_DOEN_X_REG; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_value); + +void sf_vic_gpio_doen_low(int gpio) +{ + sf_vic_gpio_doen_value(gpio, 0); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_low); + +void sf_vic_gpio_doen_high(int gpio) +{ + sf_vic_gpio_doen_value(gpio, 1); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_doen_high); + +void sf_vic_gpio_manual(int offset, int v) +{ + unsigned int value; + + if (!gpio_base) + return; + + spin_lock(&sfg_lock); + value = ioread32(gpio_base + offset); + value &= ~(0xFF); + value |= (v&0xFF); + iowrite32(value, gpio_base + offset); + spin_unlock(&sfg_lock); +} +EXPORT_SYMBOL_GPL(sf_vic_gpio_manual); + +static int starfive_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct starfive_gpio *chip; + struct gpio_irq_chip *girq; + struct resource *res; + int irq, ret, ngpio; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->base)) { + dev_err(dev, "failed to allocate device memory\n"); + return PTR_ERR(chip->base); + } + gpio_base = chip->base; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "Cannot get IRQ resource\n"); + return irq; + } + + raw_spin_lock_init(&chip->lock); + chip->gc.direction_input = starfive_direction_input; + chip->gc.direction_output = starfive_direction_output; + chip->gc.get_direction = starfive_get_direction; + chip->gc.get = starfive_get_value; + chip->gc.set = starfive_set_value; + chip->gc.base = 0; + chip->gc.ngpio = 64; + chip->gc.label = dev_name(dev); + chip->gc.parent = dev; + chip->gc.owner = THIS_MODULE; + + girq = &chip->gc.irq; + girq->chip = &starfive_irqchip; + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + + ret = gpiochip_add_data(&chip->gc, chip); + if (ret) { + dev_err(dev, "gpiochip_add_data ret=%d!\n", ret); + return ret; + } + + /* Disable all GPIO interrupts before enabling parent interrupts */ + iowrite32(0, chip->base + GPIO_IE_HIGH); + iowrite32(0, chip->base + GPIO_IE_LOW); + chip->enabled = 0; + + ret = devm_request_irq(dev, irq, starfive_irq_handler, IRQF_SHARED, + dev_name(dev), chip); + if (ret) { + dev_err(dev, "IRQ handler registering failed (%d)\n", ret); + return ret; + } + + writel_relaxed(1, chip->base + GPIO_EN); + + dev_info(dev, "StarFive GPIO chip registered %d GPIOs\n", ngpio); + + return 0; +} + +static const struct of_device_id starfive_gpio_match[] = { + { .compatible = "starfive,jh7100-gpio", }, + { /* sentinel */ }, +}; + +static struct platform_driver starfive_gpio_driver = { + .probe = starfive_gpio_probe, + .driver = { + .name = "gpio_starfive_jh7100", + .of_match_table = of_match_ptr(starfive_gpio_match), + }, +}; + +static int __init starfive_gpio_init(void) +{ + return platform_driver_register(&starfive_gpio_driver); +} +subsys_initcall(starfive_gpio_init); + +static void __exit starfive_gpio_exit(void) +{ + platform_driver_unregister(&starfive_gpio_driver); +} +module_exit(starfive_gpio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huan Feng "); +MODULE_DESCRIPTION("StarFive JH7100 GPIO driver"); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 87624902ea8090..7da8fd8beb06e7 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1751,6 +1751,16 @@ config SENSORS_STTS751 This driver can also be built as a module. If so, the module will be called stts751. +config SENSORS_SFCTEMP + tristate "Starfive JH7100 temperature sensor" + depends on OF && (RISCV || COMPILE_TEST) + help + If you say yes here you get support for temperature sensor + on the Starfive JH7100 SoC. + + This driver can also be built as a module. If so, the module + will be called sfctemp. + config SENSORS_SMM665 tristate "Summit Microelectronics SMM665" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 59e78bc212cf3c..3723eb580bf3e7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -167,6 +167,7 @@ obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o +obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o diff --git a/drivers/hwmon/sfctemp.c b/drivers/hwmon/sfctemp.c new file mode 100644 index 00000000000000..b60ef599299c9c --- /dev/null +++ b/drivers/hwmon/sfctemp.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Emil Renner Berthing + * Copyright (C) 2021 Samin Guo + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TempSensor reset. The RSTN can be de-asserted once the analog core has + * powered up. Trst(min 100ns) + * 0:reset 1:de-assert + */ +#define SFCTEMP_RSTN BIT(0) + +/* TempSensor analog core power down. The analog core will be powered up + * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the + * analog core is powered up. + * 0:power up 1:power down + */ +#define SFCTEMP_PD BIT(1) + +/* TempSensor start conversion enable. + * 0:disable 1:enable + */ +#define SFCTEMP_RUN BIT(2) + +/* TempSensor conversion value output. + * Temp(c)=DOUT*Y/4094 - K + */ +#define SFCTEMP_DOUT_POS 16 +#define SFCTEMP_DOUT_MSK GENMASK(27, 16) + +/* DOUT to Celcius conversion constants */ +#define SFCTEMP_Y1000 237500L +#define SFCTEMP_Z 4094L +#define SFCTEMP_K1000 81100L + +struct sfctemp { + /* serialize access to hardware register and enabled below */ + struct mutex lock; + struct completion conversion_done; + void __iomem *regs; + bool enabled; +}; + +static irqreturn_t sfctemp_isr(int irq, void *data) +{ + struct sfctemp *sfctemp = data; + + complete(&sfctemp->conversion_done); + return IRQ_HANDLED; +} + +static void sfctemp_power_up(struct sfctemp *sfctemp) +{ + /* make sure we're powered down first */ + writel(SFCTEMP_PD, sfctemp->regs); + udelay(1); + + writel(0, sfctemp->regs); + /* wait t_pu(50us) + t_rst(100ns) */ + usleep_range(60, 200); + + /* de-assert reset */ + writel(SFCTEMP_RSTN, sfctemp->regs); + udelay(1); /* wait t_su(500ps) */ +} + +static void sfctemp_power_down(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_PD, sfctemp->regs); +} + +static void sfctemp_run_single(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs); + udelay(1); + writel(SFCTEMP_RSTN, sfctemp->regs); +} + +static int sfctemp_enable(struct sfctemp *sfctemp) +{ + mutex_lock(&sfctemp->lock); + if (sfctemp->enabled) + goto done; + + sfctemp_power_up(sfctemp); + sfctemp->enabled = true; +done: + mutex_unlock(&sfctemp->lock); + return 0; +} + +static int sfctemp_disable(struct sfctemp *sfctemp) +{ + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) + goto done; + + sfctemp_power_down(sfctemp); + sfctemp->enabled = false; +done: + mutex_unlock(&sfctemp->lock); + return 0; +} + +static void sfctemp_disable_action(void *data) +{ + sfctemp_disable(data); +} + +static int sfctemp_convert(struct sfctemp *sfctemp, long *val) +{ + int ret; + + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) { + ret = -ENODATA; + goto out; + } + + sfctemp_run_single(sfctemp); + + ret = wait_for_completion_interruptible_timeout(&sfctemp->conversion_done, + msecs_to_jiffies(10)); + if (ret < 0) + goto out; + + /* calculate temperature in milli Celcius */ + *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) + * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; + + ret = 0; +out: + mutex_unlock(&sfctemp->lock); + return ret; +} + +static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + return 0644; + case hwmon_temp_input: + return 0444; + } + return 0; + default: + return 0; + } +} + +static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + *val = sfctemp->enabled; + return 0; + case hwmon_temp_input: + return sfctemp_convert(sfctemp, val); + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + if (val == 0) + return sfctemp_disable(sfctemp); + if (val == 1) + return sfctemp_enable(sfctemp); + break; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct hwmon_channel_info *sfctemp_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops sfctemp_hwmon_ops = { + .is_visible = sfctemp_is_visible, + .read = sfctemp_read, + .write = sfctemp_write, +}; + +static const struct hwmon_chip_info sfctemp_chip_info = { + .ops = &sfctemp_hwmon_ops, + .info = sfctemp_info, +}; + +static int sfctemp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *hwmon_dev; + struct resource *mem; + struct sfctemp *sfctemp; + int ret; + + sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL); + if (!sfctemp) + return -ENOMEM; + + dev_set_drvdata(dev, sfctemp); + mutex_init(&sfctemp->lock); + init_completion(&sfctemp->conversion_done); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sfctemp->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(sfctemp->regs)) + return PTR_ERR(sfctemp->regs); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + + ret = devm_request_irq(dev, ret, sfctemp_isr, + IRQF_SHARED, pdev->name, sfctemp); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } + + ret = devm_add_action(dev, sfctemp_disable_action, sfctemp); + if (ret) + return ret; + + ret = sfctemp_enable(sfctemp); + if (ret) + return ret; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, pdev->name, sfctemp, + &sfctemp_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id sfctemp_of_match[] = { + { .compatible = "starfive,jh7100-temp" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, sfctemp_of_match); + +static struct platform_driver sfctemp_driver = { + .driver = { + .name = "sfctemp", + .of_match_table = of_match_ptr(sfctemp_of_match), + }, + .probe = sfctemp_probe, +}; +module_platform_driver(sfctemp_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH7100 temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 6a53f75abf7c79..c8e2c59bc29d50 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -286,6 +286,8 @@ struct dw_i2c_dev { int (*init)(struct dw_i2c_dev *dev); int (*set_sda_hold_time)(struct dw_i2c_dev *dev); int mode; + int scl_gpio; + int sda_gpio; struct i2c_bus_recovery_info rinfo; bool suspended; }; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 9b08bb5df38d29..85d2cddfcdf6c8 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "i2c-designware-core.h" @@ -164,6 +165,48 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) return 0; } +static void i2c_dw_configure_gpio(struct dw_i2c_dev *dev) +{ +#ifdef CONFIG_SOC_STARFIVE_VIC7100_I2C_GPIO + if((dev->scl_gpio > 0) && (dev->sda_gpio > 0)) { + SET_GPIO_dout_LOW(dev->scl_gpio); + SET_GPIO_dout_LOW(dev->sda_gpio); + SET_GPIO_doen_reverse_(dev->scl_gpio,1); + SET_GPIO_doen_reverse_(dev->sda_gpio,1); + switch(dev->adapter.nr) { + case 0: + SET_GPIO_doen_i2c0_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c0_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c0_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c0_pad_sda_in(dev->sda_gpio); + break; + case 1: + SET_GPIO_doen_i2c1_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c1_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c1_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c1_pad_sda_in(dev->sda_gpio); + break; + case 2: + SET_GPIO_doen_i2c2_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c2_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c2_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c2_pad_sda_in(dev->sda_gpio); + break; + case 3: + SET_GPIO_doen_i2c3_pad_sck_oe(dev->scl_gpio); + SET_GPIO_doen_i2c3_pad_sda_oe(dev->sda_gpio); + SET_GPIO_i2c3_pad_sck_in(dev->scl_gpio); + SET_GPIO_i2c3_pad_sda_in(dev->sda_gpio); + break; + default: + dev_err(dev->dev, "i2c adapter number is invalid\n"); + } + } else + dev_err(dev->dev, "scl/sda gpio number is invalid !\n"); +#endif + return; +} + /** * i2c_dw_init_master() - Initialize the designware I2C master hardware * @dev: device private data @@ -927,6 +970,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) dev_err(dev->dev, "failure adding adapter: %d\n", ret); pm_runtime_put_noidle(dev->dev); + i2c_dw_configure_gpio(dev); return ret; } EXPORT_SYMBOL_GPL(i2c_dw_probe_master); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 4b37f28ec0c6c1..d6ecae1f94f8c5 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,21 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) return clk_get_rate(dev->clk)/1000; } +#ifdef CONFIG_SOC_STARFIVE_VIC7100 +static u32 starfive_i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) +{ + u32 val; + + if(!device_property_read_u32(dev->dev, "clocks", &val)) { + dev_info(dev->dev, "Using 'clocks' : %u / 1000", val); + return (val / 1000); + } else { + dev_info(dev->dev, "Using the static setting value: 49500"); + return 49500; + } +} +#endif + #ifdef CONFIG_ACPI static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C2", 0 }, @@ -205,6 +221,7 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { static int dw_i2c_plat_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct i2c_adapter *adap; struct dw_i2c_dev *dev; struct i2c_timings *t; @@ -221,6 +238,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); dev->dev = &pdev->dev; dev->irq = irq; + dev->scl_gpio = of_get_named_gpio(np, "scl-gpio", 0); + dev->sda_gpio = of_get_named_gpio(np, "sda-gpio", 0); platform_set_drvdata(pdev, dev); ret = dw_i2c_plat_request_regs(dev); @@ -271,6 +290,18 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (!dev->sda_hold_time && t->sda_hold_ns) dev->sda_hold_time = div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000); +#ifdef CONFIG_SOC_STARFIVE_VIC7100 + } else { + u64 clk_khz; + + dev->get_clk_rate_khz = starfive_i2c_dw_get_clk_rate_khz; + clk_khz = dev->get_clk_rate_khz(dev); + + if (!dev->sda_hold_time && t->sda_hold_ns) + dev->sda_hold_time = + div_u64(clk_khz * t->sda_hold_ns + 500000, + 1000000); +#endif } adap = &dev->adapter; diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 97d4d04b0a80eb..63a8dea3fae5da 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -273,6 +273,44 @@ static int plic_starting_cpu(unsigned int cpu) return 0; } +#if IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) +#ifdef CONFIG_SOC_STARFIVE_VIC7100 +#define SIFIVE_L2_MAX_ECCINTR 4 +#else +#define SIFIVE_L2_MAX_ECCINTR 3 +#endif +static const struct of_device_id sifive_l2_ids[] = { + { .compatible = "sifive,fu540-c000-ccache" }, + { .compatible = "starfive,ccache0" }, + { /* end of table */ }, +}; + +static void sifive_l2_irq_disable(struct plic_handler *handler) +{ + int i, irq; + struct of_phandle_args oirq; + + struct device_node *np = of_find_matching_node(NULL, sifive_l2_ids); + if (!np) { + pr_err("Can't get L2 cache device node.\n"); + return; + } + + for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) { + if (!of_irq_parse_one(np, i, &oirq)) { + irq = *oirq.args; + if (irq) { + pr_info("disable L2 cache irq %d in plic\n", irq); + plic_toggle(handler, irq, 0); + continue; + } + } + pr_err("Can't get L2 cache irq(#%d).\n", i); + } +} +#endif + + static int __init plic_init(struct device_node *node, struct device_node *parent) { @@ -366,6 +404,9 @@ static int __init plic_init(struct device_node *node, done: for (hwirq = 1; hwirq <= nr_irqs; hwirq++) plic_toggle(handler, hwirq, 0); +#if IS_ENABLED(CONFIG_SIFIVE_L2_IRQ_DISABLE) + sifive_l2_irq_disable(handler); +#endif nr_handlers++; } diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 157c924686e4b6..3cd87484d8abd1 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -171,6 +171,7 @@ source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/sunxi/Kconfig" +source "drivers/media/platform/starfive/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index eedc14aafb32c2..23141e53e53ef8 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ obj-y += stm32/ +obj-y += starfive/ + obj-y += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o diff --git a/drivers/media/platform/starfive/Kconfig b/drivers/media/platform/starfive/Kconfig new file mode 100644 index 00000000000000..a79d7e1802d85d --- /dev/null +++ b/drivers/media/platform/starfive/Kconfig @@ -0,0 +1,32 @@ +# +# VIN sensor driver configuration +# +config VIDEO_STARFIVE_VIN + bool "starfive VIC video input support" + depends on OF + help + To compile this driver as a module, choose M here: the module + will be called stf-vin. + +choice + prompt "Image Sensor for VIC board" + default VIDEO_STARFIVE_VIN_SENSOR_IMX219 + depends on VIDEO_STARFIVE_VIN + optional + +config VIDEO_STARFIVE_VIN_SENSOR_OV5640 + bool "OmniVision OV5640 5mp MIPI Camera Module" + help + Say Y here if you want to have support for VIN sensor OV5640 + +config VIDEO_STARFIVE_VIN_SENSOR_IMX219 + bool "Sony IMX219 CMOS Image Sensor" + help + Say Y here if you want to have support for VIN sensor IMX219 + +config VIDEO_STARFIVE_VIN_SENSOR_SC2235 + bool "SmartSens Technology SC2235 CMOS Image Sensor" + help + Say Y here if you want to have support for VIN sensor SC2235 + +endchoice diff --git a/drivers/media/platform/starfive/Makefile b/drivers/media/platform/starfive/Makefile new file mode 100644 index 00000000000000..4585213935e653 --- /dev/null +++ b/drivers/media/platform/starfive/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for RTC class/drivers. +# + +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_OV5640) += ov5640_dvp.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_SC2235) += sc2235.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN_SENSOR_IMX219) += imx219_mipi.o +obj-$(CONFIG_VIDEO_STARFIVE_VIN) += video_stf_vin.o +video_stf_vin-objs += stf_vin.o stf_event.o stf_isp.o stf_csi.o diff --git a/drivers/media/platform/starfive/imx219_mipi.c b/drivers/media/platform/starfive/imx219_mipi.c new file mode 100644 index 00000000000000..a99e83f0a17a32 --- /dev/null +++ b/drivers/media/platform/starfive/imx219_mipi.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2011-2013 StarFive Technology Co., Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include