diff options
author | Zoltan HERPAI <wigyori@uid0.hu> | 2023-05-24 23:51:14 +0200 |
---|---|---|
committer | Zoltan HERPAI <wigyori@uid0.hu> | 2024-02-29 16:50:22 +0100 |
commit | 99545b4bb1faf7c328854cd5d74c63e11783b9bf (patch) | |
tree | f3c780976db618246ee63c1e9d3331fbca8dda22 /target/linux | |
parent | d41d9befb9302d33601fe3644886d8463d9f105d (diff) |
d1: add new target
This target adds support for the Allwinner D1 RISC-V based SoCs.
- RISC-V single-core T-Head C906 (RV64GCV)
- Tensilica HiFi4 DSP
- DDR2/DDR3 support
- 10/100/1000M ethernet
- usual peripherals like USB2, SPI, I2C, PWM, etc.
Four boards are supported:
- Dongshan Nezha STU
- 512Mb RAM
- ethernet
- LicheePi RV Dock
- 512Mb RAM
- wireless-only (RTL8723DS)
- MangoPi MQ-Pro
- 512Mb RAM
- there are pads available for an SPI flash
- wireless-only (RTL8723DS)
- Nezha D1
- 512Mb/1Gb/2Gb RAM
- 256Mb NAND flash
- ethernet, wireless
Installation:
Standard SD-card installation via dd-ing the generated image to
an SD-card of at least 256Mb.
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
Diffstat (limited to 'target/linux')
124 files changed, 13256 insertions, 0 deletions
diff --git a/target/linux/d1/Makefile b/target/linux/d1/Makefile new file mode 100644 index 0000000000..436ab94862 --- /dev/null +++ b/target/linux/d1/Makefile @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 Toco Technologies <info@toco.ae> +# +include $(TOPDIR)/rules.mk + +ARCH:=riscv64 +BOARD:=d1 +BOARDNAME:=AllWinner D1 RISC-V SoC +FEATURES:=ext4 squashfs +KERNELNAME:=Image dtbs + +KERNEL_PATCHVER:=6.1 + +include $(INCLUDE_DIR)/target.mk + +define Target/Description + Build firmware images for Allwinner D1 RISC-V boards +endef + +$(eval $(call BuildTarget)) diff --git a/target/linux/d1/base-files/etc/board.d/02_network b/target/linux/d1/base-files/etc/board.d/02_network new file mode 100644 index 0000000000..df48b431af --- /dev/null +++ b/target/linux/d1/base-files/etc/board.d/02_network @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Copyright (C) 2013-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +*) + ucidef_set_interface_lan 'eth0' + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/d1/base-files/etc/inittab b/target/linux/d1/base-files/etc/inittab new file mode 100644 index 0000000000..be81ab3e23 --- /dev/null +++ b/target/linux/d1/base-files/etc/inittab @@ -0,0 +1,5 @@ +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +tts/0::askfirst:/usr/libexec/login.sh +ttyS0::askfirst:/usr/libexec/login.sh +tty1::askfirst:/usr/libexec/login.sh diff --git a/target/linux/d1/config-6.1 b/target/linux/d1/config-6.1 new file mode 100644 index 0000000000..ef2112f706 --- /dev/null +++ b/target/linux/d1/config-6.1 @@ -0,0 +1,396 @@ +CONFIG_64BIT=y +# CONFIG_AHCI_SUNXI is not set +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_RV64I=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_SUNXI=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_ASN1=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_CC_NO_ARRAY_BOUNDS=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLZ_TAB=y +CONFIG_CMODEL_MEDANY=y +# CONFIG_CMODEL_MEDLOW is not set +CONFIG_COMMON_CLK=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_COMPAT_BRK=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y +CONFIG_COREDUMP=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_CPU_ISOLATION=y +CONFIG_CPU_RMAP=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRYPTO_DEV_ALLWINNER=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DMADEVICES=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_SUN6I=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DWMAC_GENERIC=y +CONFIG_DWMAC_SUN8I=y +CONFIG_DWMAC_SUNXI=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EFI=y +CONFIG_EFIVAR_FS=m +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_COCO_SECRET is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# CONFIG_EFI_DISABLE_RUNTIME is not set +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_GENERIC_STUB=y +CONFIG_EFI_PARAMS_FROM_FDT=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_ZBOOT is not set +CONFIG_ELF_CORE=y +# CONFIG_ERRATA_SIFIVE is not set +CONFIG_ERRATA_THEAD=y +CONFIG_ERRATA_THEAD_CMO=y +CONFIG_ERRATA_THEAD_PBMT=y +CONFIG_EXT4_FS=y +CONFIG_EXTCON=y +CONFIG_FAILOVER=y +CONFIG_FHANDLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_FONT_SUPPORT=y +CONFIG_FPU=y +CONFIG_FRAME_POINTER=y +CONFIG_FRAME_WARN=2048 +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FWNODE_MDIO=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IOREMAP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GLOB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_PCF857X=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HID=y +CONFIG_HID_GENERIC=y +CONFIG_HVC_DRIVER=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_MV64XXX=y +CONFIG_I2C_OCORES=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +CONFIG_IOMMU_API=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set +CONFIG_IOMMU_DEFAULT_DMA_STRICT=y +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IO_URING=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +# CONFIG_KEYBOARD_SUN4I_LRADC is not set +# CONFIG_LEDS_PWM_MULTICOLOR is not set +# CONFIG_LEDS_SUN50I_A100 is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBFDT=y +CONFIG_LOCALVERSION_AUTO=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MDIO_BUS=y +CONFIG_MDIO_BUS_MUX=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_SUN4I is not set +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_AXP20X=y +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_SUN4I_GPADC is not set +CONFIG_MFD_SUN6I_PRCM=y +CONFIG_MFD_SYSCON=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_SUNXI=y +CONFIG_MMIOWB=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +# CONFIG_MUSB_PIO_ONLY is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_VENDOR_ALLWINNER=y +CONFIG_NLS=y +# CONFIG_NONPORTABLE is not set +CONFIG_NOP_USB_XCEIV=y +CONFIG_NR_CPUS=8 +CONFIG_NVMEM=y +CONFIG_NVMEM_SUNXI_SID=y +CONFIG_NVMEM_SYSFS=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_DMA_DEFAULT_COHERENT=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IOMMU=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OID_REGISTRY=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xff60000000000000 +CONFIG_PAGE_POOL=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +# CONFIG_PAGE_TABLE_CHECK is not set +CONFIG_PANIC_TIMEOUT=0 +CONFIG_PCPU_DEV_REFCNT=y +CONFIG_PGTABLE_LEVELS=5 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PHY_SUN4I_USB=y +CONFIG_PHY_SUN50I_USB3=y +# CONFIG_PHY_SUN6I_MIPI_DPHY is not set +# CONFIG_PHY_SUN9I_USB is not set +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SUN20I_D1=y +# CONFIG_PINCTRL_SUN4I_A10 is not set +# CONFIG_PINCTRL_SUN50I_A100 is not set +# CONFIG_PINCTRL_SUN50I_A100_R is not set +# CONFIG_PINCTRL_SUN50I_A64 is not set +# CONFIG_PINCTRL_SUN50I_A64_R is not set +# CONFIG_PINCTRL_SUN50I_H5 is not set +# CONFIG_PINCTRL_SUN50I_H6 is not set +# CONFIG_PINCTRL_SUN50I_H616 is not set +# CONFIG_PINCTRL_SUN50I_H616_R is not set +# CONFIG_PINCTRL_SUN50I_H6_R is not set +# CONFIG_PINCTRL_SUN5I is not set +# CONFIG_PINCTRL_SUN6I_A31 is not set +# CONFIG_PINCTRL_SUN6I_A31_R is not set +# CONFIG_PINCTRL_SUN8I_A23 is not set +# CONFIG_PINCTRL_SUN8I_A23_R is not set +# CONFIG_PINCTRL_SUN8I_A33 is not set +# CONFIG_PINCTRL_SUN8I_A83T is not set +# CONFIG_PINCTRL_SUN8I_A83T_R is not set +# CONFIG_PINCTRL_SUN8I_H3 is not set +# CONFIG_PINCTRL_SUN8I_H3_R is not set +# CONFIG_PINCTRL_SUN8I_V3S is not set +# CONFIG_PINCTRL_SUN9I_A80 is not set +# CONFIG_PINCTRL_SUN9I_A80_R is not set +CONFIG_PINCTRL_SUNXI=y +CONFIG_PORTABLE=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PREEMPT_NONE_BUILD=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PWM=y +# CONFIG_PWM_CLK is not set +# CONFIG_PWM_SIFIVE is not set +# CONFIG_PWM_SUN4I is not set +# CONFIG_PWM_SUN8I_V536 is not set +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_XILINX is not set +CONFIG_RATIONAL=y +CONFIG_RCU_TRACE=y +CONFIG_REALTEK_PHY=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_IRQ=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_AXP20X is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_SUN20I=y +# CONFIG_RESET_ATTACK_MITIGATION is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y +CONFIG_RESET_SUNXI=y +CONFIG_RISCV=y +CONFIG_RISCV_ALTERNATIVE=y +CONFIG_RISCV_ALTERNATIVE_EARLY=y +CONFIG_RISCV_BOOT_SPINWAIT=y +CONFIG_RISCV_DMA_NONCOHERENT=y +CONFIG_RISCV_INTC=y +CONFIG_RISCV_ISA_C=y +CONFIG_RISCV_ISA_SVPBMT=y +CONFIG_RISCV_ISA_ZICBOM=y +CONFIG_RISCV_SBI=y +CONFIG_RISCV_SBI_V01=y +CONFIG_RISCV_TIMER=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_EFI is not set +CONFIG_RTC_DRV_GOLDFISH=y +CONFIG_RTC_DRV_SUN6I=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCHED_DEBUG=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SG_POOL=y +CONFIG_SIFIVE_PLIC=y +CONFIG_SLUB_DEBUG=y +CONFIG_SMP=y +# CONFIG_SND_SUN20I_CODEC is not set +# CONFIG_SND_SUN4I_I2S is not set +# CONFIG_SND_SUN50I_DMIC is not set +CONFIG_SOCK_RX_QUEUE_MAPPING=y +# CONFIG_SOC_MICROCHIP_POLARFIRE is not set +# CONFIG_SOC_SIFIVE is not set +# CONFIG_SOC_STARFIVE is not set +# CONFIG_SOC_VIRT is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +# CONFIG_SPI_SUN4I is not set +CONFIG_SPI_SUN6I=y +CONFIG_SRCU=y +CONFIG_STACKDEPOT=y +CONFIG_STACKTRACE=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +CONFIG_SUN20I_D1_CCU=y +CONFIG_SUN20I_D1_R_CCU=y +# CONFIG_SUN4I_EMAC is not set +CONFIG_SUN4I_TIMER=y +CONFIG_SUN50I_IOMMU=y +CONFIG_SUN6I_MSGBOX=y +CONFIG_SUN6I_RTC_CCU=y +CONFIG_SUN8I_DE2_CCU=y +# CONFIG_SUN8I_R_CCU is not set +# CONFIG_SUN8I_THERMAL is not set +CONFIG_SUNXI_CCU=y +# CONFIG_SUNXI_RSB is not set +CONFIG_SUNXI_SRAM=y +CONFIG_SUNXI_WATCHDOG=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSFB_SIMPLEFB is not set +CONFIG_SYSFS_SYSCALL=y +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TOOLCHAIN_HAS_ZICBOM=y +CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y +CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y +CONFIG_TRACE_CLOCK=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_TUNE_GENERIC=y +# CONFIG_UACCE is not set +CONFIG_UCS2_STRING=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_HID=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_HOST=y +CONFIG_USB_MUSB_SUNXI=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_PHY=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_VHOST_MENU is not set +# CONFIG_VIRTIO_MENU is not set +CONFIG_VMAP_STACK=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA32=y diff --git a/target/linux/d1/image/Config.in b/target/linux/d1/image/Config.in new file mode 100644 index 0000000000..92169c8eb2 --- /dev/null +++ b/target/linux/d1/image/Config.in @@ -0,0 +1,5 @@ +config D1_SD_BOOT_PARTSIZE + int "Boot (SD Card) filesystem partition size (in MB)" + depends on TARGET_d1 + default 32 + diff --git a/target/linux/d1/image/Makefile b/target/linux/d1/image/Makefile new file mode 100644 index 0000000000..aadf1807e7 --- /dev/null +++ b/target/linux/d1/image/Makefile @@ -0,0 +1,94 @@ +# +# Copyright (C) 2023 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +FAT32_BLOCK_SIZE=1024 +FAT32_BLOCKS=$(shell echo $$(($(CONFIG_D1_SD_BOOT_PARTSIZE)*1024*1024/$(FAT32_BLOCK_SIZE)))) + +KERNEL_LOADADDR:=0x40200000 + +define Build/riscv-sdcard + rm -f $@.boot #$(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img + mkfs.fat $@.boot -C $(FAT32_BLOCKS) + + mcopy -i $@.boot $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-boot.scr ::boot.scr + mcopy -i $@.boot $(DTS_DIR)/$(DEVICE_DTS).dtb ::dtb + mcopy -i $@.boot $(IMAGE_KERNEL) ::Image + + ./gen_d1_sdcard_img.sh \ + $@ \ + $@.boot \ + $(IMAGE_ROOTFS) \ + $(CONFIG_D1_SD_BOOT_PARTSIZE) \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) \ + $(STAGING_DIR_IMAGE)/$(DEVICE_NAME)-u-boot-sunxi-with-spl.bin +endef + +define Device/Default + PROFILES := Default + KERNEL_NAME := Image + KERNEL := kernel-bin + IMAGES := sdcard.img.gz + IMAGE/sdcard.img.gz := riscv-sdcard | append-metadata | gzip +endef + +define Device/FitImageGzip + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/FitImage + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | fit none $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/dongshan_nezha_stu + $(call Device/Default) + DEVICE_VENDOR := Dongshan + DEVICE_MODEL := Nezha STU devkit + DEVICE_DTS := allwinner/sun20i-d1-dongshan-nezha-stu + UBOOT := dongshan_nezha_stu +endef +TARGET_DEVICES += dongshan_nezha_stu + +define Device/lichee_rv_dock + $(call Device/Default) + DEVICE_VENDOR := Sipeed + DEVICE_MODEL := LicheePi RV (dock) + DEVICE_DTS := allwinner/sun20i-d1-lichee-rv-dock + DEVICE_PACKAGES += kmod-rtl8723bs + UBOOT := lichee_rv_dock +endef +TARGET_DEVICES += lichee_rv_dock + +define Device/mangopi_mq_pro + $(call Device/Default) + DEVICE_VENDOR := MangoPi + DEVICE_MODEL := MQ Pro + DEVICE_DTS := allwinner/sun20i-d1-mangopi-mq-pro + DEVICE_PACKAGES += kmod-rtl8723bs + UBOOT := mangopi_mq_pro +endef +TARGET_DEVICES += mangopi_mq_pro + +define Device/nezha + $(call Device/Default) + DEVICE_VENDOR := Nezha + DEVICE_MODEL := D1 + DEVICE_DTS := allwinner/sun20i-d1-nezha + UBOOT := nezha +endef +TARGET_DEVICES += nezha + +define Image/Build + $(call Image/Build/$(1),$(1)) +endef + +$(eval $(call BuildImage)) diff --git a/target/linux/d1/image/gen_d1_sdcard_img.sh b/target/linux/d1/image/gen_d1_sdcard_img.sh new file mode 100755 index 0000000000..197eea7a20 --- /dev/null +++ b/target/linux/d1/image/gen_d1_sdcard_img.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2013 OpenWrt.org + +set -ex +[ $# -eq 6 ] || { + echo "SYNTAX: $0 <file> <bootfs image> <rootfs image> <bootfs size> <rootfs size> <u-boot image>" + exit 1 +} + +OUTPUT="$1" +BOOTFS="$2" +ROOTFS="$3" +BOOTFSSIZE="$4" +ROOTFSSIZE="$5" +UBOOT="$6" + +ROOTFSPTOFFSET=$(($BOOTFSSIZE + 20 + 1)) + +head=4 +sect=63 + +set $(ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M@20M -t 83 -p ${ROOTFSSIZE}M@${ROOTFSPTOFFSET}M) + +BOOTOFFSET="$(($1 / 512))" +BOOTSIZE="$(($2 / 512))" +ROOTFSOFFSET="$(($3 / 512))" +ROOTFSSIZE="$(($4 / 512))" + +dd bs=512 if="$UBOOT" of="$OUTPUT" seek=256 conv=notrunc +dd bs=512 if="$BOOTFS" of="$OUTPUT" seek="$BOOTOFFSET" conv=notrunc +dd bs=512 if="$ROOTFS" of="$OUTPUT" seek="$ROOTFSOFFSET" conv=notrunc diff --git a/target/linux/d1/patches-6.1/0001-dt-bindings-net-bluetooth-realtek-Add-RTL8723DS.patch b/target/linux/d1/patches-6.1/0001-dt-bindings-net-bluetooth-realtek-Add-RTL8723DS.patch new file mode 100644 index 0000000000..6636cddde6 --- /dev/null +++ b/target/linux/d1/patches-6.1/0001-dt-bindings-net-bluetooth-realtek-Add-RTL8723DS.patch @@ -0,0 +1,32 @@ +From e663d510ae6a81694a8e9e1ce07bb80dd6b77558 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 24 Jul 2022 17:12:07 -0500 +Subject: [PATCH 001/117] dt-bindings: net: bluetooth: realtek: Add RTL8723DS + +RTL8723DS is another version of the RTL8723 WiFi + Bluetooth chip. It is +already supported by the hci_uart/btrtl driver. Document the compatible. + +Series-to: Marcel Holtmann <marcel@holtmann.org> +Series-to: Johan Hedberg <johan.hedberg@gmail.com> +Series-to: Luiz Augusto von Dentz <luiz.dentz@gmail.com> +Series-to: David S. Miller <davem@davemloft.net> +Series-to: Eric Dumazet <edumazet@google.com> +Series-to: Jakub Kicinski <kuba@kernel.org> +Series-to: Paolo Abeni <pabeni@redhat.com> +Series-cc: linux-bluetooth@vger.kernel.org + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + Documentation/devicetree/bindings/net/realtek-bluetooth.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/net/realtek-bluetooth.yaml ++++ b/Documentation/devicetree/bindings/net/realtek-bluetooth.yaml +@@ -20,6 +20,7 @@ properties: + enum: + - realtek,rtl8723bs-bt + - realtek,rtl8723cs-bt ++ - realtek,rtl8723ds-bt + - realtek,rtl8822cs-bt + + device-wake-gpios: diff --git a/target/linux/d1/patches-6.1/0002-clk-sunxi-ng-mp-Avoid-computing-the-rate-twice.patch b/target/linux/d1/patches-6.1/0002-clk-sunxi-ng-mp-Avoid-computing-the-rate-twice.patch new file mode 100644 index 0000000000..22d4885e29 --- /dev/null +++ b/target/linux/d1/patches-6.1/0002-clk-sunxi-ng-mp-Avoid-computing-the-rate-twice.patch @@ -0,0 +1,51 @@ +From 74492b9ecd874496578693d9985649665b560308 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 20:08:49 -0500 +Subject: [PATCH 002/117] clk: sunxi-ng: mp: Avoid computing the rate twice + +ccu_mp_find_best() already computes a best_rate at the same time as the +best m and p factors. Return it so the caller does not need to duplicate +the division. + +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/clk/sunxi-ng/ccu_mp.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/clk/sunxi-ng/ccu_mp.c ++++ b/drivers/clk/sunxi-ng/ccu_mp.c +@@ -10,9 +10,9 @@ + #include "ccu_gate.h" + #include "ccu_mp.h" + +-static void ccu_mp_find_best(unsigned long parent, unsigned long rate, +- unsigned int max_m, unsigned int max_p, +- unsigned int *m, unsigned int *p) ++static unsigned long ccu_mp_find_best(unsigned long parent, unsigned long rate, ++ unsigned int max_m, unsigned int max_p, ++ unsigned int *m, unsigned int *p) + { + unsigned long best_rate = 0; + unsigned int best_m = 0, best_p = 0; +@@ -35,6 +35,8 @@ static void ccu_mp_find_best(unsigned lo + + *m = best_m; + *p = best_p; ++ ++ return best_rate; + } + + static unsigned long ccu_mp_find_best_with_parent_adj(struct clk_hw *hw, +@@ -109,8 +111,7 @@ static unsigned long ccu_mp_round_rate(s + max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); + + if (!clk_hw_can_set_rate_parent(&cmp->common.hw)) { +- ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p); +- rate = *parent_rate / p / m; ++ rate = ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p); + } else { + rate = ccu_mp_find_best_with_parent_adj(hw, parent_rate, rate, + max_m, max_p); diff --git a/target/linux/d1/patches-6.1/0003-dt-bindings-net-sun8i-emac-Add-phy-supply-property.patch b/target/linux/d1/patches-6.1/0003-dt-bindings-net-sun8i-emac-Add-phy-supply-property.patch new file mode 100644 index 0000000000..ec3f553b51 --- /dev/null +++ b/target/linux/d1/patches-6.1/0003-dt-bindings-net-sun8i-emac-Add-phy-supply-property.patch @@ -0,0 +1,22 @@ +From 7185f7b424dfd9082bf0859a60b98a2dbd784ed6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Mon, 5 Sep 2022 16:45:44 -0500 +Subject: [PATCH 003/117] dt-bindings: net: sun8i-emac: Add phy-supply property + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml ++++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +@@ -40,6 +40,9 @@ properties: + clock-names: + const: stmmaceth + ++ phy-supply: ++ description: PHY regulator ++ + syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: diff --git a/target/linux/d1/patches-6.1/0004-dt-bindings-net-sun8i-emac-Add-properties-from-dwmac.patch b/target/linux/d1/patches-6.1/0004-dt-bindings-net-sun8i-emac-Add-properties-from-dwmac.patch new file mode 100644 index 0000000000..9ac335ae3e --- /dev/null +++ b/target/linux/d1/patches-6.1/0004-dt-bindings-net-sun8i-emac-Add-properties-from-dwmac.patch @@ -0,0 +1,32 @@ +From d20bb97fac77e4d88424043627c769427fc0d35e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Mon, 5 Sep 2022 16:46:34 -0500 +Subject: [PATCH 004/117] dt-bindings: net: sun8i-emac: Add properties from + dwmac binding + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml ++++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +@@ -40,6 +40,9 @@ properties: + clock-names: + const: stmmaceth + ++ resets: true ++ reset-names: true ++ + phy-supply: + description: PHY regulator + +@@ -49,6 +52,8 @@ properties: + Phandle to the device containing the EMAC or GMAC clock + register + ++ mdio: true ++ + required: + - compatible + - reg diff --git a/target/linux/d1/patches-6.1/0005-dt-bindings-display-sun8i-a83t-dw-hdmi-Remove-phy-ce.patch b/target/linux/d1/patches-6.1/0005-dt-bindings-display-sun8i-a83t-dw-hdmi-Remove-phy-ce.patch new file mode 100644 index 0000000000..402f291674 --- /dev/null +++ b/target/linux/d1/patches-6.1/0005-dt-bindings-display-sun8i-a83t-dw-hdmi-Remove-phy-ce.patch @@ -0,0 +1,28 @@ +From c99d1e681dc460892004054a314fa7f929f43490 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 13 Aug 2022 10:45:59 -0500 +Subject: [PATCH 005/117] dt-bindings: display: sun8i-a83t-dw-hdmi: Remove + #phy-cells + +This device is not a PHY, and none of the nodes using this schema +contain a #phy-cells property. Likely this was a copy/paste error +introduced during the YAML conversion. + +Fixes: f5a98bfe7b37 ("dt-bindings: display: Convert Allwinner display pipeline to schemas") +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml | 3 --- + 1 file changed, 3 deletions(-) + +--- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml +@@ -20,9 +20,6 @@ maintainers: + - Maxime Ripard <mripard@kernel.org> + + properties: +- "#phy-cells": +- const: 0 +- + compatible: + oneOf: + - const: allwinner,sun8i-a83t-dw-hdmi diff --git a/target/linux/d1/patches-6.1/0006-dt-bindings-display-Add-D1-HDMI-compatibles.patch b/target/linux/d1/patches-6.1/0006-dt-bindings-display-Add-D1-HDMI-compatibles.patch new file mode 100644 index 0000000000..b62e45c09f --- /dev/null +++ b/target/linux/d1/patches-6.1/0006-dt-bindings-display-Add-D1-HDMI-compatibles.patch @@ -0,0 +1,34 @@ +From e214b79d45cccdd0cfe839e54da2b3c82b6c6be4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 31 Mar 2022 23:43:15 -0500 +Subject: [PATCH 006/117] dt-bindings: display: Add D1 HDMI compatibles + +Allwinner D1 contains a DesignWare HDMI controller with some changes in +platform integration, and a new HDMI PHY. Add their compatibles. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml | 1 + + .../bindings/display/allwinner,sun8i-a83t-hdmi-phy.yaml | 1 + + 2 files changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-dw-hdmi.yaml +@@ -29,6 +29,7 @@ properties: + - enum: + - allwinner,sun8i-h3-dw-hdmi + - allwinner,sun8i-r40-dw-hdmi ++ - allwinner,sun20i-d1-dw-hdmi + - allwinner,sun50i-a64-dw-hdmi + - const: allwinner,sun8i-a83t-dw-hdmi + +--- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-hdmi-phy.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-hdmi-phy.yaml +@@ -19,6 +19,7 @@ properties: + - allwinner,sun8i-a83t-hdmi-phy + - allwinner,sun8i-h3-hdmi-phy + - allwinner,sun8i-r40-hdmi-phy ++ - allwinner,sun20i-d1-hdmi-phy + - allwinner,sun50i-a64-hdmi-phy + - allwinner,sun50i-h6-hdmi-phy + diff --git a/target/linux/d1/patches-6.1/0007-drm-sun4i-Add-support-for-D1-HDMI.patch b/target/linux/d1/patches-6.1/0007-drm-sun4i-Add-support-for-D1-HDMI.patch new file mode 100644 index 0000000000..b55c3a3f20 --- /dev/null +++ b/target/linux/d1/patches-6.1/0007-drm-sun4i-Add-support-for-D1-HDMI.patch @@ -0,0 +1,52 @@ +From 75dc74ecc1bf5e270659c6c78877053b50e6ae19 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 30 Mar 2022 21:24:21 -0500 +Subject: [PATCH 007/117] drm/sun4i: Add support for D1 HDMI + +D1's HDMI controller contains some platform integration changes. +It now has no external TMDS clock. The controller also supports HDCP +without an external clock or reset. + +While the maximum HDMI frequency is not explicity stated, the BSP PHY +driver provides PLL configurations only up to 297 MHz, so use that as +the max frequency. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +@@ -133,7 +133,7 @@ static int sun8i_dw_hdmi_bind(struct dev + return dev_err_probe(dev, PTR_ERR(hdmi->rst_ctrl), + "Could not get ctrl reset control\n"); + +- hdmi->clk_tmds = devm_clk_get(dev, "tmds"); ++ hdmi->clk_tmds = devm_clk_get_optional(dev, "tmds"); + if (IS_ERR(hdmi->clk_tmds)) + return dev_err_probe(dev, PTR_ERR(hdmi->clk_tmds), + "Couldn't get the tmds clock\n"); +@@ -246,6 +246,11 @@ static const struct sun8i_dw_hdmi_quirks + .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, + }; + ++static const struct sun8i_dw_hdmi_quirks sun20i_d1_quirks = { ++ .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, ++ .use_drm_infoframe = true, ++}; ++ + static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { + .mode_valid = sun8i_dw_hdmi_mode_valid_h6, + .use_drm_infoframe = true, +@@ -257,6 +262,10 @@ static const struct of_device_id sun8i_d + .data = &sun8i_a83t_quirks, + }, + { ++ .compatible = "allwinner,sun20i-d1-dw-hdmi", ++ .data = &sun20i_d1_quirks, ++ }, ++ { + .compatible = "allwinner,sun50i-h6-dw-hdmi", + .data = &sun50i_h6_quirks, + }, diff --git a/target/linux/d1/patches-6.1/0008-drm-sun4i-sun8i-hdmi-phy-Add-support-for-D1-PHY.patch b/target/linux/d1/patches-6.1/0008-drm-sun4i-sun8i-hdmi-phy-Add-support-for-D1-PHY.patch new file mode 100644 index 0000000000..e8007cc5c4 --- /dev/null +++ b/target/linux/d1/patches-6.1/0008-drm-sun4i-sun8i-hdmi-phy-Add-support-for-D1-PHY.patch @@ -0,0 +1,251 @@ +From 11f9765a8e6723bcb7243f6dbc48e6deaf17b097 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 3 Apr 2022 15:15:41 -0500 +Subject: [PATCH 008/117] drm/sun4i: sun8i-hdmi-phy: Add support for D1 PHY + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 169 +++++++++++++++++++++++++ + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 32 +++++ + 2 files changed, 201 insertions(+) + +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -145,6 +145,175 @@ + + #define SUN8I_HDMI_PHY_CEC_REG 0x003c + ++#define SUN20I_HDMI_PHY_CTL0_REG 0x0040 ++#define SUN20I_HDMI_PHY_CTL0_PLL_LOCK_MODE_MAN BIT(31) ++#define SUN20I_HDMI_PHY_CTL0_PLL_LOCK_MODE BIT(30) ++#define SUN20I_HDMI_PHY_CTL0_FIFO_WORKC_EN BIT(29) ++#define SUN20I_HDMI_PHY_CTL0_FIFO_AUTOSYNC_DIS BIT(28) ++#define SUN20I_HDMI_PHY_CTL0_ENTX GENMASK(27, 24) ++#define SUN20I_HDMI_PHY_CTL0_ENBI GENMASK(23, 20) ++#define SUN20I_HDMI_PHY_CTL0_ENLDO BIT(18) ++#define SUN20I_HDMI_PHY_CTL0_ENLDO_FS BIT(17) ++#define SUN20I_HDMI_PHY_CTL0_ENCK BIT(16) ++#define SUN20I_HDMI_PHY_CTL0_REG_PLR GENMASK(15, 12) ++#define SUN20I_HDMI_PHY_CTL0_REG_DEN GENMASK(11, 8) ++#define SUN20I_HDMI_PHY_CTL0_REG_CSMPS GENMASK(7, 6) ++#define SUN20I_HDMI_PHY_CTL0_REG_CK_TEST_SEL BIT(5) ++#define SUN20I_HDMI_PHY_CTL0_REG_CK_SEL BIT(4) ++#define SUN20I_HDMI_PHY_CTL0_HPD_EN BIT(2) ++#define SUN20I_HDMI_PHY_CTL0_SCL_EN BIT(1) ++#define SUN20I_HDMI_PHY_CTL0_SDA_EN BIT(0) ++ ++#define SUN20I_HDMI_PHY_CTL1_REG 0x0044 ++#define SUN20I_HDMI_PHY_CTL1_RXSENSE_MODE_MAN BIT(31) ++#define SUN20I_HDMI_PHY_CTL1_RXSENSE_MODE BIT(30) ++#define SUN20I_HDMI_PHY_CTL1_RES_S GENMASK(29, 28) ++#define SUN20I_HDMI_PHY_CTL1_RES_SCKTMDS BIT(27) ++#define SUN20I_HDMI_PHY_CTL1_REG_SWI BIT(26) ++#define SUN20I_HDMI_PHY_CTL1_REG_SVR GENMASK(25, 24) ++#define SUN20I_HDMI_PHY_CTL1_REG_BST2 GENMASK(21, 20) ++#define SUN20I_HDMI_PHY_CTL1_REG_BST1 GENMASK(19, 18) ++#define SUN20I_HDMI_PHY_CTL1_REG_BST0 GENMASK(17, 16) ++#define SUN20I_HDMI_PHY_CTL1_REG_SP2_3 GENMASK(15, 12) ++#define SUN20I_HDMI_PHY_CTL1_REG_SP2_2 GENMASK(11, 8) ++#define SUN20I_HDMI_PHY_CTL1_REG_SP2_1 GENMASK(7, 4) ++#define SUN20I_HDMI_PHY_CTL1_REG_SP2_0 GENMASK(3, 0) ++ ++#define SUN20I_HDMI_PHY_CTL2_REG 0x0048 ++#define SUN20I_HDMI_PHY_CTL2_HPDO_MODE_MAN BIT(31) ++#define SUN20I_HDMI_PHY_CTL2_HPDO_MODE BIT(30) ++#define SUN20I_HDMI_PHY_CTL2_REG_RESDI GENMASK(29, 24) ++#define SUN20I_HDMI_PHY_CTL2_REG_SP1_3 GENMASK(23, 19) ++#define SUN20I_HDMI_PHY_CTL2_REG_SP1_2 GENMASK(18, 14) ++#define SUN20I_HDMI_PHY_CTL2_REG_SP1_1 GENMASK(13, 9) ++#define SUN20I_HDMI_PHY_CTL2_REG_SP1_0 GENMASK(8, 4) ++#define SUN20I_HDMI_PHY_CTL2_REG_P2OPT GENMASK(3, 0) ++ ++#define SUN20I_HDMI_PHY_CTL3_REG 0x004c ++#define SUN20I_HDMI_PHY_CTL3_REG_P2_3 GENMASK(31, 28) ++#define SUN20I_HDMI_PHY_CTL3_REG_P2_2 GENMASK(27, 24) ++#define SUN20I_HDMI_PHY_CTL3_REG_P2_1 GENMASK(23, 20) ++#define SUN20I_HDMI_PHY_CTL3_REG_P2_0 GENMASK(19, 16) ++#define SUN20I_HDMI_PHY_CTL3_REG_MC3 GENMASK(15, 12) ++#define SUN20I_HDMI_PHY_CTL3_REG_MC2 GENMASK(11, 8) ++#define SUN20I_HDMI_PHY_CTL3_REG_MC1 GENMASK(7, 4) ++#define SUN20I_HDMI_PHY_CTL3_REG_MC0 GENMASK(3, 0) ++ ++#define SUN20I_HDMI_PHY_CTL4_REG 0x0050 ++#define SUN20I_HDMI_PHY_CTL4_REG_SLV GENMASK(31, 29) ++#define SUN20I_HDMI_PHY_CTL4_REG_P1_3 GENMASK(28, 24) ++#define SUN20I_HDMI_PHY_CTL4_REG_P1_2 GENMASK(20, 16) ++#define SUN20I_HDMI_PHY_CTL4_REG_P1_1 GENMASK(12, 8) ++#define SUN20I_HDMI_PHY_CTL4_REG_P1_0 GENMASK(4, 0) ++ ++#define SUN20I_HDMI_PHY_CTL5_REG 0x0054 ++#define SUN20I_HDMI_PHY_CTL5_REG_P1OPT GENMASK(19, 16) ++#define SUN20I_HDMI_PHY_CTL5_REG_CKPDLYOPT BIT(12) ++#define SUN20I_HDMI_PHY_CTL5_REG_CALSW BIT(11) ++#define SUN20I_HDMI_PHY_CTL5_ENRESCK BIT(10) ++#define SUN20I_HDMI_PHY_CTL5_ENRES BIT(9) ++#define SUN20I_HDMI_PHY_CTL5_ENRCAL BIT(8) ++#define SUN20I_HDMI_PHY_CTL5_ENP2S GENMASK(7, 4) ++#define SUN20I_HDMI_PHY_CTL5_ENIB BIT(1) ++#define SUN20I_HDMI_PHY_CTL5_ENCALOG BIT(0) ++ ++#define SUN20I_HDMI_PLL_CTL0_REG 0x0058 ++#define SUN20I_HDMI_PLL_CTL0_CKO_SEL GENMASK(31, 30) ++#define SUN20I_HDMI_PLL_CTL0_BYPASS_PPLL BIT(29) ++#define SUN20I_HDMI_PLL_CTL0_ENVBS BIT(28) ++#define SUN20I_HDMI_PLL_CTL0_SLV GENMASK(26, 24) ++#define SUN20I_HDMI_PLL_CTL0_BCR BIT(23) ++#define SUN20I_HDMI_PLL_CTL0_BYPASS_CLRDPTH BIT(22) ++#define SUN20I_HDMI_PLL_CTL0_CLR_DPTH GENMASK(21, 20) ++#define SUN20I_HDMI_PLL_CTL0_CUTFB BIT(18) ++#define SUN20I_HDMI_PLL_CTL0_DIV2_CKBIT BIT(17) ++#define SUN20I_HDMI_PLL_CTL0_DIV2_CKTMDS BIT(16) ++#define SUN20I_HDMI_PLL_CTL0_DIV_PRE GENMASK(15, 12) ++#define SUN20I_HDMI_PLL_CTL0_DIVX1 BIT(10) ++#define SUN20I_HDMI_PLL_CTL0_SDRVEN BIT(9) ++#define SUN20I_HDMI_PLL_CTL0_VCORANGE BIT(8) ++#define SUN20I_HDMI_PLL_CTL0_N_CNTRL GENMASK(7, 6) ++#define SUN20I_HDMI_PLL_CTL0_GMP_CNTRL GENMASK(5, 4) ++#define SUN20I_HDMI_PLL_CTL0_PROP_CNTRL GENMASK(2, 0) ++ ++#define SUN20I_HDMI_PLL_CTL1_REG 0x005c ++#define SUN20I_HDMI_PLL_CTL1_CTRL_MODLE_CLKSRC BIT(31) ++#define SUN20I_HDMI_PLL_CTL1_PCNT_N GENMASK(27, 20) ++#define SUN20I_HDMI_PLL_CTL1_PCNT_EN BIT(19) ++#define SUN20I_HDMI_PLL_CTL1_SDM_EN BIT(18) ++#define SUN20I_HDMI_PLL_CTL1_PIXEL_REP GENMASK(17, 16) ++#define SUN20I_HDMI_PLL_CTL1_PWRON BIT(12) ++#define SUN20I_HDMI_PLL_CTL1_RESET BIT(11) ++#define SUN20I_HDMI_PLL_CTL1_SCKREF BIT(10) ++#define SUN20I_HDMI_PLL_CTL1_SCKFB BIT(9) ++#define SUN20I_HDMI_PLL_CTL1_DRV_ANA BIT(8) ++#define SUN20I_HDMI_PLL_CTL1_FAST_TECH BIT(7) ++#define SUN20I_HDMI_PLL_CTL1_GEAR_SHIFT BIT(6) ++#define SUN20I_HDMI_PLL_CTL1_REF_CNTRL GENMASK(5, 4) ++#define SUN20I_HDMI_PLL_CTL1_INT_CNTRL GENMASK(2, 0) ++ ++#define SUN20I_HDMI_AFIFO_CFG_REG 0x0060 ++#define SUN20I_HDMI_AFIFO_CFG_AFIFO_ERROR BIT(0) ++#define SUN20I_HDMI_AFIFO_CFG_AFIFO_ERROR_DET BIT(1) ++ ++#define SUN20I_HDMI_MODULATOR_CFG0_REG 0x0064 ++#define SUN20I_HDMI_MODULATOR_CFG1_REG 0x0068 ++ ++#define SUN20I_HDMI_INDEB_CTRL_REG 0x006c ++#define SUN20I_HDMI_INDEB_CTRL_HPDI_DEBUGMODE BIT(29) ++#define SUN20I_HDMI_INDEB_CTRL_HPDI_DEBUG BIT(28) ++#define SUN20I_HDMI_INDEB_CTRL_SDAI_DEBUGMODE BIT(25) ++#define SUN20I_HDMI_INDEB_CTRL_SDAI_DEBUG BIT(24) ++#define SUN20I_HDMI_INDEB_CTRL_SCLI_DEBUGMODE BIT(21) ++#define SUN20I_HDMI_INDEB_CTRL_SCLI_DEBUG BIT(20) ++#define SUN20I_HDMI_INDEB_CTRL_CECI_DEBUGMODE BIT(17) ++#define SUN20I_HDMI_INDEB_CTRL_CECI_DEBUG BIT(16) ++#define SUN20I_HDMI_INDEB_CTRL_TXDATA_DEBUGMODE GENMASK(1, 0) ++ ++#define SUN20I_HDMI_INDBG_TXD0_REG 0x0070 ++#define SUN20I_HDMI_INDBG_TXD1_REG 0x0074 ++#define SUN20I_HDMI_INDBG_TXD2_REG 0x0078 ++#define SUN20I_HDMI_INDBG_TXD3_REG 0x007c ++ ++#define SUN20I_HDMI_PLL_STS_REG 0x0080 ++#define SUN20I_HDMI_PLL_STS_PHY_CDETPCK_STATUS BIT(31) ++#define SUN20I_HDMI_PLL_STS_PHY_CDETP_STATUS GENMASK(30, 28) ++#define SUN20I_HDMI_PLL_STS_PHY_CDETNCK_STATUS BIT(27) ++#define SUN20I_HDMI_PLL_STS_PHY_CDETN_STATUS GENMASK(26, 24) ++#define SUN20I_HDMI_PLL_STS_PHY_HPDO_STATUS BIT(23) ++#define SUN20I_HDMI_PLL_STS_PHY_SCLO_STATUS BIT(22) ++#define SUN20I_HDMI_PLL_STS_PHY_SDAO_STATUS BIT(21) ++#define SUN20I_HDMI_PLL_STS_PHY_CECO_STATUS BIT(20) ++#define SUN20I_HDMI_PLL_STS_PHY_COUT2D_STATUS BIT(17) ++#define SUN20I_HDMI_PLL_STS_PHY_RCALEND2D_STS BIT(16) ++#define SUN20I_HDMI_PLL_STS_PHY_RESDO2D_STATUS GENMASK(13, 8) ++#define SUN20I_HDMI_PLL_STS_PLL_LOCK_STATUS BIT(4) ++#define SUN20I_HDMI_PLL_STS_RXSENSE_DLY_STATUS BIT(1) ++#define SUN20I_HDMI_PLL_STS_TX_READY_DLY_STATUS BIT(0) ++ ++#define SUN20I_HDMI_PRBS_CTL_REG 0x0084 ++#define SUN20I_HDMI_PRBS_SEED_GEN_REG 0x0088 ++#define SUN20I_HDMI_PRBS_SEED_CHK_REG 0x008c ++#define SUN20I_HDMI_PRBS_SEED_NUM_REG 0x0090 ++#define SUN20I_HDMI_PRBS_CYCLE_NUM_REG 0x0094 ++ ++#define SUN20I_HDMI_PLL_ODLY_REG 0x0098 ++#define SUN20I_HDMI_PLL_ODLY_RXSENSE_DLY_RESET BIT(31) ++#define SUN20I_HDMI_PLL_ODLY_RXSENSE_DLY_COUNT GENMASK(30, 16) ++#define SUN20I_HDMI_PLL_ODLY_TX_READY_DLY_RESET BIT(15) ++#define SUN20I_HDMI_PLL_ODLY_TX_READY_DLY_COUNT GENMASK(14, 0) ++ ++#define SUN20I_HDMI_PHY_CTL6_REG 0x009c ++#define SUN20I_HDMI_PHY_CTL6_SWITCH_CLKCH_DATA BIT(31) ++#define SUN20I_HDMI_PHY_CTL6_EN_CKDAT BIT(30) ++#define SUN20I_HDMI_PHY_CTL6_CLK_GREATE2_340M GENMASK(29, 20) ++#define SUN20I_HDMI_PHY_CTL6_CLK_GREATE1_340M GENMASK(19, 10) ++#define SUN20I_HDMI_PHY_CTL6_CLK_GREATE0_340M GENMASK(9, 0) ++ ++#define SUN20I_HDMI_PHY_CTL7_REG 0x00a0 ++#define SUN20I_HDMI_PHY_CTL7_CLK_LOW_340M GENMASK(21, 12) ++#define SUN20I_HDMI_PHY_CTL7_CLK_GREATE3_340M GENMASK(9, 0) ++ + struct sun8i_hdmi_phy; + + struct sun8i_hdmi_phy_variant { +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -398,6 +398,28 @@ static const struct dw_hdmi_phy_ops sun8 + .setup_hpd = dw_hdmi_phy_setup_hpd, + }; + ++static int sun20i_d1_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, ++ const struct drm_display_mode *mode) ++{ ++ struct sun8i_hdmi_phy *phy = data; ++ ++ return 0; ++} ++ ++static void sun20i_d1_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) ++{ ++ struct sun8i_hdmi_phy *phy = data; ++} ++ ++static const struct dw_hdmi_phy_ops sun20i_d1_hdmi_phy_ops = { ++ .init = sun20i_d1_hdmi_phy_config, ++ .disable = sun20i_d1_hdmi_phy_disable, ++ .read_hpd = dw_hdmi_phy_read_hpd, ++ .update_hpd = dw_hdmi_phy_update_hpd, ++ .setup_hpd = dw_hdmi_phy_setup_hpd, ++}; ++ + static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy) + { + /* enable read access to HDMI controller */ +@@ -576,6 +598,7 @@ void sun8i_hdmi_phy_set_ops(struct sun8i + const struct sun8i_hdmi_phy_variant *variant = phy->variant; + + if (variant->phy_ops) { ++ plat_data->phy_force_vendor = true; + plat_data->phy_ops = variant->phy_ops; + plat_data->phy_name = "sun8i_dw_hdmi_phy"; + plat_data->phy_data = phy; +@@ -612,6 +635,11 @@ static const struct sun8i_hdmi_phy_varia + .phy_init = &sun8i_hdmi_phy_init_h3, + }; + ++static const struct sun8i_hdmi_phy_variant sun20i_d1_hdmi_phy = { ++ .phy_ops = &sun20i_d1_hdmi_phy_ops, ++ .phy_init = &sun50i_hdmi_phy_init_h6, ++}; ++ + static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { + .has_phy_clk = true, + .phy_ops = &sun8i_h3_hdmi_phy_ops, +@@ -639,6 +667,10 @@ static const struct of_device_id sun8i_h + .data = &sun8i_r40_hdmi_phy, + }, + { ++ .compatible = "allwinner,sun20i-d1-hdmi-phy", ++ .data = &sun20i_d1_hdmi_phy, ++ }, ++ { + .compatible = "allwinner,sun50i-a64-hdmi-phy", + .data = &sun50i_a64_hdmi_phy, + }, diff --git a/target/linux/d1/patches-6.1/0009-drm-sun4i-Copy-in-BSP-code-for-D1-HDMI-PHY.patch b/target/linux/d1/patches-6.1/0009-drm-sun4i-Copy-in-BSP-code-for-D1-HDMI-PHY.patch new file mode 100644 index 0000000000..85c81d5057 --- /dev/null +++ b/target/linux/d1/patches-6.1/0009-drm-sun4i-Copy-in-BSP-code-for-D1-HDMI-PHY.patch @@ -0,0 +1,621 @@ +From 7ea7d4abfd537230da58533803a2d0257addace8 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 30 Mar 2022 00:46:07 -0500 +Subject: [PATCH 009/117] drm/sun4i: Copy in BSP code for D1 HDMI PHY + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/aw_phy.h | 411 +++++++++++++++++++++++++ + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 1 + + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 156 ++++++++++ + 3 files changed, 568 insertions(+) + create mode 100644 drivers/gpu/drm/sun4i/aw_phy.h + +--- /dev/null ++++ b/drivers/gpu/drm/sun4i/aw_phy.h +@@ -0,0 +1,411 @@ ++/* ++ * Allwinner SoCs hdmi2.0 driver. ++ * ++ * Copyright (C) 2016 Allwinner. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef AW_PHY_H_ ++#define AW_PHY_H_ ++ ++#define AW_PHY_TIMEOUT 1000 ++#define LOCK_TIMEOUT 100 ++ ++/* allwinner phy register offset */ ++#define HDMI_PHY_CTL0 0x40 ++#define HDMI_PHY_CTL1 0x44 ++#define HDMI_PHY_CTL2 0x48 ++#define HDMI_PHY_CTL3 0x4C ++#define HDMI_PHY_CTL4 0x50 ++#define HDMI_PHY_CTL5 0x54 ++#define HDMI_PLL_CTL0 0x58 ++#define HDMI_PLL_CTL1 0x5C ++#define HDMI_AFIFO_CFG 0x60 ++#define HDMI_MODULATOR_CFG0 0x64 ++#define HDMI_MODULATOR_CFG1 0x68 ++#define HDMI_PHY_INDEB_CTRL 0x6C ++#define HDMI_PHY_INDBG_TXD0 0x70 ++#define HDMI_PHY_INDBG_TXD1 0x74 ++#define HDMI_PHY_INDBG_TXD2 0x78 ++#define HDMI_PHY_INDBG_TXD3 0x7C ++#define HDMI_PHY_PLL_STS 0x80 ++#define HDMI_PRBS_CTL 0x84 ++#define HDMI_PRBS_SEED_GEN 0x88 ++#define HDMI_PRBS_SEED_CHK 0x8C ++#define HDMI_PRBS_SEED_NUM 0x90 ++#define HDMI_PRBS_CYCLE_NUM 0x94 ++#define HDMI_PHY_PLL_ODLY_CFG 0x98 ++#define HDMI_PHY_CTL6 0x9C ++#define HDMI_PHY_CTL7 0xA0 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 sda_en :1; // Default: 0; ++ u32 scl_en :1; // Default: 0; ++ u32 hpd_en :1; // Default: 0; ++ u32 res0 :1; // Default: 0; ++ u32 reg_ck_sel :1; // Default: 1; ++ u32 reg_ck_test_sel :1; // Default: 1; ++ u32 reg_csmps :2; // Default: 0; ++ u32 reg_den :4; // Default: F; ++ u32 reg_plr :4; // Default: 0; ++ u32 enck :1; // Default: 1; ++ u32 enldo_fs :1; // Default: 1; ++ u32 enldo :1; // Default: 1; ++ u32 res1 :1; // Default: 1; ++ u32 enbi :4; // Default: F; ++ u32 entx :4; // Default: F; ++ u32 async_fifo_autosync_disable :1; // Default: 0; ++ u32 async_fifo_workc_enable :1; // Default: 1; ++ u32 phy_pll_lock_mode :1; // Default: 1; ++ u32 phy_pll_lock_mode_man :1; // Default: 1; ++ } bits; ++} HDMI_PHY_CTL0_t; //=========================== 0x0040 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 reg_sp2_0 : 4 ; // Default: 0; ++ u32 reg_sp2_1 : 4 ; // Default: 0; ++ u32 reg_sp2_2 : 4 ; // Default: 0; ++ u32 reg_sp2_3 : 4 ; // Default: 0; ++ u32 reg_bst0 : 2 ; // Default: 3; ++ u32 reg_bst1 : 2 ; // Default: 3; ++ u32 reg_bst2 : 2 ; // Default: 3; ++ u32 res0 : 2 ; // Default: 0; ++ u32 reg_svr : 2 ; // Default: 2; ++ u32 reg_swi : 1 ; // Default: 0; ++ u32 res_scktmds : 1 ; // Default: 0; ++ u32 res_res_s : 2 ; // Default: 3; ++ u32 phy_rxsense_mode : 1 ; // Default: 0; ++ u32 res_rxsense_mode_man : 1 ; // Default: 0; ++ } bits; ++} HDMI_PHY_CTL1_t; //===================================================== 0x0044 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 reg_p2opt : 4 ; // Default: 0; ++ u32 reg_sp1_0 : 5 ; // Default: 0; ++ u32 reg_sp1_1 : 5 ; // Default: 0; ++ u32 reg_sp1_2 : 5 ; // Default: 0; ++ u32 reg_sp1_3 : 5 ; // Default: 0; ++ u32 reg_resdi : 6 ; // Default: 18; ++ u32 phy_hpdo_mode : 1 ; // Default: 0; ++ u32 phy_hpdo_mode_man : 1 ; // Default: 0; ++ } bits; ++} HDMI_PHY_CTL2_t; //===================================================== 0x0048 ++ ++ ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 reg_mc0 : 4 ; // Default: F; ++ u32 reg_mc1 : 4 ; // Default: F; ++ u32 reg_mc2 : 4 ; // Default: F; ++ u32 reg_mc3 : 4 ; // Default: F; ++ u32 reg_p2_0 : 4 ; // Default: F; ++ u32 reg_p2_1 : 4 ; // Default: F; ++ u32 reg_p2_2 : 4 ; // Default: F; ++ u32 reg_p2_3 : 4 ; // Default: F; ++ } bits; ++} HDMI_PHY_CTL3_t; //===================================================== 0x004C ++ ++ ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 reg_p1_0 : 5 ; // Default: 0x10; ++ u32 res0 : 3 ; // Default: 0; ++ u32 reg_p1_1 : 5 ; // Default: 0x10; ++ u32 res1 : 3 ; // Default: 0; ++ u32 reg_p1_2 : 5 ; // Default: 0x10; ++ u32 res2 : 3 ; // Default: 0; ++ u32 reg_p1_3 : 5 ; // Default: 0x10; ++ u32 reg_slv : 3 ; // Default: 0; ++ } bits; ++} HDMI_PHY_CTL4_t; //===================================================== 0x0050 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 encalog : 1 ; // Default: 0x1; ++ u32 enib : 1 ; // Default: 0x1; ++ u32 res0 : 2 ; // Default: 0; ++ u32 enp2s : 4 ; // Default: 0xF; ++ u32 enrcal : 1 ; // Default: 0x1; ++ u32 enres : 1 ; // Default: 1; ++ u32 enresck : 1 ; // Default: 1; ++ u32 reg_calsw : 1 ; // Default: 0; ++ u32 reg_ckpdlyopt : 1 ; // Default: 0; ++ u32 res1 : 3 ; // Default: 0; ++ u32 reg_p1opt : 4 ; // Default: 0; ++ u32 res2 : 12 ; // Default: 0; ++ } bits; ++} HDMI_PHY_CTL5_t; //===================================================== 0x0054 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prop_cntrl : 3 ; // Default: 0x7; ++ u32 res0 : 1 ; // Default: 0; ++ u32 gmp_cntrl : 2 ; // Default: 1; ++ u32 n_cntrl : 2 ; // Default: 0; ++ u32 vcorange : 1 ; // Default: 0; ++ u32 sdrven : 1 ; // Default: 0; ++ u32 divx1 : 1 ; // Default: 0; ++ u32 res1 : 1 ; // Default: 0; ++ u32 div_pre : 4 ; // Default: 0; ++ u32 div2_cktmds : 1 ; // Default: 1; ++ u32 div2_ckbit : 1 ; // Default: 1; ++ u32 cutfb : 1 ; // Default: 0; ++ u32 res2 : 1 ; // Default: 0; ++ u32 clr_dpth : 2 ; // Default: 0; ++ u32 bypass_clrdpth : 1 ; // Default: 0; ++ u32 bcr : 1 ; // Default: 0; ++ u32 slv : 3 ; // Default: 4; ++ u32 res3 : 1 ; // Default: 0; ++ u32 envbs : 1 ; // Default: 0; ++ u32 bypass_ppll : 1 ; // Default: 0; ++ u32 cko_sel : 2 ; // Default: 0; ++ } bits; ++} HDMI_PLL_CTL0_t; //===================================================== 0x0058 ++ ++ ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 int_cntrl : 3 ; // Default: 0x0; ++ u32 res0 : 1 ; // Default: 0; ++ u32 ref_cntrl : 2 ; // Default: 3; ++ u32 gear_shift : 1 ; // Default: 0; ++ u32 fast_tech : 1 ; // Default: 0; ++ u32 drv_ana : 1 ; // Default: 1; ++ u32 sckfb : 1 ; // Default: 0; ++ u32 sckref : 1 ; // Default: 0; ++ u32 reset : 1 ; // Default: 0; ++ u32 pwron : 1 ; // Default: 0; ++ u32 res1 : 3 ; // Default: 0; ++ u32 pixel_rep : 2 ; // Default: 0; ++ u32 sdm_en : 1 ; // Default: 0; ++ u32 pcnt_en : 1 ; // Default: 0; ++ u32 pcnt_n : 8 ; // Default: 0xE; ++ u32 res2 : 3 ; // Default: 0; ++ u32 ctrl_modle_clksrc : 1 ; // Default: 0; ++ } bits; ++} HDMI_PLL_CTL1_t; //===================================================== 0x005C ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 hdmi_afifo_error : 1 ; // Default: 0x0; ++ u32 hdmi_afifo_error_det : 1 ; // Default: 0x0; ++ u32 res0 : 30 ; // Default: 0; ++ } bits; ++} HDMI_AFIFO_CFG_t; //===================================================== 0x0060 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 fnpll_mash_en : 1 ; // Default: 0x0; ++ u32 fnpll_mash_mod : 2 ; // Default: 0x0; ++ u32 fnpll_mash_stp : 9 ; // Default: 0x0; ++ u32 fnpll_mash_m12 : 1 ; // Default: 0x0; ++ u32 fnpll_mash_frq : 2 ; // Default: 0x0; ++ u32 fnpll_mash_bot : 17 ; // Default: 0x0; ++ } bits; ++} HDMI_MODULATOR_CFG0_t; //===================================================== 0x0064 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 fnpll_mash_dth : 1 ; // Default: 0x0; ++ u32 fnpll_mash_fen : 1 ; // Default: 0x0; ++ u32 fnpll_mash_frc : 17 ; // Default: 0x0; ++ u32 fnpll_mash_fnv : 8 ; // Default: 0x0; ++ u32 res0 : 5 ; // Default: 0x0; ++ } bits; ++} HDMI_MODULATOR_CFG1_t; //===================================================== 0x0068 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 txdata_debugmode : 2 ; // Default: 0x0; ++ u32 res0 : 14 ; // Default: 0x0; ++ u32 ceci_debug : 1 ; // Default: 0x0; ++ u32 ceci_debugmode : 1 ; // Default: 0x0; ++ u32 res1 : 2 ; // Default: 0x0; ++ u32 sdai_debug : 1 ; // Default: 0x0; ++ u32 sdai_debugmode : 1 ; // Default: 0x0; ++ u32 res2 : 2 ; // Default: 0x0; ++ u32 scli_debug : 1 ; // Default: 0x0; ++ u32 scli_debugmode : 1 ; // Default: 0x0; ++ u32 res3 : 2 ; // Default: 0x0; ++ u32 hpdi_debug : 1 ; // Default: 0x0; ++ u32 hpdi_debugmode : 1 ; // Default: 0x0; ++ u32 res4 : 2 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_INDBG_CTRL_t; //================================================== 0x006C ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 txdata0_debug_data : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_INDBG_TXD0_t; //================================================== 0x0070 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 txdata1_debug_data : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_INDBG_TXD1_t; //================================================== 0x0074 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 txdata2_debug_data : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_INDBG_TXD2_t; //================================================== 0x0078 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 txdata3_debug_data : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_INDBG_TXD3_t; //================================================== 0x007C ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 tx_ready_dly_status : 1 ; // Default: 0x0; ++ u32 rxsense_dly_status : 1 ; // Default: 0x0; ++ u32 res0 : 2 ; // Default: 0x0; ++ u32 pll_lock_status : 1 ; // Default: 0x0; ++ u32 res1 : 3 ; // Default: 0x0; ++ u32 phy_resdo2d_status : 6 ; // Default: 0x0; ++ u32 res2 : 2 ; // Default: 0x0; ++ u32 phy_rcalend2d_status : 1 ; // Default: 0x0; ++ u32 phy_cout2d_status : 1 ; // Default: 0x0; ++ u32 res3 : 2 ; // Default: 0x0; ++ u32 phy_ceco_status : 1 ; // Default: 0x0; ++ u32 phy_sdao_status : 1 ; // Default: 0x0; ++ u32 phy_sclo_status : 1 ; // Default: 0x0; ++ u32 phy_hpdo_status : 1 ; // Default: 0x0; ++ u32 phy_cdetn_status : 3 ; // Default: 0x0; ++ u32 phy_cdetnck_status : 1 ; // Default: 0x0; ++ u32 phy_cdetp_status : 3 ; // Default: 0x0; ++ u32 phy_cdetpck_status : 1 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_PLL_STS_t; //===================================================== 0x0080 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prbs_en : 1 ; // Default: 0x0; ++ u32 prbs_start : 1 ; // Default: 0x0; ++ u32 prbs_seq_gen : 1 ; // Default: 0x0; ++ u32 prbs_seq_chk : 1 ; // Default: 0x0; ++ u32 prbs_mode : 4 ; // Default: 0x0; ++ u32 prbs_type : 2 ; // Default: 0x0; ++ u32 prbs_clk_pol : 1 ; // Default: 0x0; ++ u32 res0 : 21 ; // Default: 0x0; ++ } bits; ++} HDMI_PRBS_CTL_t; //===================================================== 0x0084 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prbs_seed_gen : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PRBS_SEED_GEN_t; //================================================= 0x0088 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prbs_seed_chk : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PRBS_SEED_CHK_t; //================================================= 0x008C ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prbs_seed_num : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PRBS_SEED_NUM_t; //================================================= 0x0090 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 prbs_cycle_num : 32 ; // Default: 0x0; ++ } bits; ++} HDMI_PRBS_CYCLE_NUM_t; //================================================= 0x0094 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 tx_ready_dly_count : 15 ; // Default: 0x0; ++ u32 tx_ready_dly_reset : 1 ; // Default: 0x0; ++ u32 rxsense_dly_count : 15 ; // Default: 0x0; ++ u32 rxsense_dly_reset : 1 ; // Default: 0x0; ++ } bits; ++} HDMI_PHY_PLL_ODLY_CFG_t; //================================================= 0x0098 ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 clk_greate0_340m : 10 ; // Default: 0x3FF; ++ u32 clk_greate1_340m : 10 ; // Default: 0x3FF; ++ u32 clk_greate2_340m : 10 ; // Default: 0x3FF; ++ u32 en_ckdat : 1 ; // Default: 0x3FF; ++ u32 switch_clkch_data_corresponding : 1 ; // Default: 0x3FF; ++ } bits; ++} HDMI_PHY_CTL6_t; //========================================================= 0x009C ++ ++typedef union { ++ u32 dwval; ++ struct { ++ u32 clk_greate3_340m : 10 ; // Default: 0x0; ++ u32 res0 : 2 ; // Default: 0x3FF; ++ u32 clk_low_340m : 10 ; // Default: 0x3FF; ++ u32 res1 : 10 ; // Default: 0x3FF; ++ } bits; ++} HDMI_PHY_CTL7_t; //========================================================= 0x00A0 ++ ++struct __aw_phy_reg_t { ++ u32 res[16]; /* 0x0 ~ 0x3c */ ++ HDMI_PHY_CTL0_t phy_ctl0; /* 0x0040 */ ++ HDMI_PHY_CTL1_t phy_ctl1; /* 0x0044 */ ++ HDMI_PHY_CTL2_t phy_ctl2; /* 0x0048 */ ++ HDMI_PHY_CTL3_t phy_ctl3; /* 0x004c */ ++ HDMI_PHY_CTL4_t phy_ctl4; /* 0x0050 */ ++ HDMI_PHY_CTL5_t phy_ctl5; /* 0x0054 */ ++ HDMI_PLL_CTL0_t pll_ctl0; /* 0x0058 */ ++ HDMI_PLL_CTL1_t pll_ctl1; /* 0x005c */ ++ HDMI_AFIFO_CFG_t afifo_cfg; /* 0x0060 */ ++ HDMI_MODULATOR_CFG0_t modulator_cfg0; /* 0x0064 */ ++ HDMI_MODULATOR_CFG1_t modulator_cfg1; /* 0x0068 */ ++ HDMI_PHY_INDBG_CTRL_t phy_indbg_ctrl; /* 0x006c */ ++ HDMI_PHY_INDBG_TXD0_t phy_indbg_txd0; /* 0x0070 */ ++ HDMI_PHY_INDBG_TXD1_t phy_indbg_txd1; /* 0x0074 */ ++ HDMI_PHY_INDBG_TXD2_t phy_indbg_txd2; /* 0x0078 */ ++ HDMI_PHY_INDBG_TXD3_t phy_indbg_txd3; /* 0x007c */ ++ HDMI_PHY_PLL_STS_t phy_pll_sts; /* 0x0080 */ ++ HDMI_PRBS_CTL_t prbs_ctl; /* 0x0084 */ ++ HDMI_PRBS_SEED_GEN_t prbs_seed_gen; /* 0x0088 */ ++ HDMI_PRBS_SEED_CHK_t prbs_seed_chk; /* 0x008c */ ++ HDMI_PRBS_SEED_NUM_t prbs_seed_num; /* 0x0090 */ ++ HDMI_PRBS_CYCLE_NUM_t prbs_cycle_num; /* 0x0094 */ ++ HDMI_PHY_PLL_ODLY_CFG_t phy_pll_odly_cfg; /* 0x0098 */ ++ HDMI_PHY_CTL6_t phy_ctl6; /* 0x009c */ ++ HDMI_PHY_CTL7_t phy_ctl7; /* 0x00A0 */ ++}; ++ ++#endif /* AW_PHY_H_ */ +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -334,6 +334,7 @@ struct sun8i_hdmi_phy { + struct clk *clk_pll1; + struct device *dev; + unsigned int rcal; ++ void __iomem *base; + struct regmap *regs; + struct reset_control *rst_phy; + const struct sun8i_hdmi_phy_variant *variant; +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -9,6 +9,8 @@ + + #include "sun8i_dw_hdmi.h" + ++#include "aw_phy.h" ++ + /* + * Address can be actually any value. Here is set to same value as + * it is set in BSP driver. +@@ -398,11 +400,164 @@ static const struct dw_hdmi_phy_ops sun8 + .setup_hpd = dw_hdmi_phy_setup_hpd, + }; + ++static int sun20i_d1_hdmi_phy_enable(volatile struct __aw_phy_reg_t __iomem *phy_base) ++{ ++ int i = 0, status = 0; ++ ++ pr_info("enter %s\n", __func__); ++ ++ //enib -> enldo -> enrcal -> encalog -> enbi[3:0] -> enck -> enp2s[3:0] -> enres -> enresck -> entx[3:0] ++ phy_base->phy_ctl4.bits.reg_slv = 4; //low power voltage 1.08V, default is 3, set 4 as well as pll_ctl0 bit [24:26] ++ phy_base->phy_ctl5.bits.enib = 1; ++ phy_base->phy_ctl0.bits.enldo = 1; ++ phy_base->phy_ctl0.bits.enldo_fs = 1; ++ phy_base->phy_ctl5.bits.enrcal = 1; ++ ++ phy_base->phy_ctl5.bits.encalog = 1; ++ ++ for (i = 0; i < AW_PHY_TIMEOUT; i++) { ++ udelay(5); ++ status = phy_base->phy_pll_sts.bits.phy_rcalend2d_status; ++ if (status & 0x1) { ++ pr_info("[%s]:phy_rcalend2d_status\n", __func__); ++ break; ++ } ++ } ++ if ((i == AW_PHY_TIMEOUT) && !status) { ++ pr_err("phy_rcalend2d_status Timeout !\n"); ++ return -1; ++ } ++ ++ phy_base->phy_ctl0.bits.enbi = 0xF; ++ for (i = 0; i < AW_PHY_TIMEOUT; i++) { ++ udelay(5); ++ status = phy_base->phy_pll_sts.bits.pll_lock_status; ++ if (status & 0x1) { ++ pr_info("[%s]:pll_lock_status\n", __func__); ++ break; ++ } ++ } ++ if ((i == AW_PHY_TIMEOUT) && !status) { ++ pr_err("pll_lock_status Timeout! status = 0x%x\n", status); ++ return -1; ++ } ++ ++ phy_base->phy_ctl0.bits.enck = 1; ++ phy_base->phy_ctl5.bits.enp2s = 0xF; ++ phy_base->phy_ctl5.bits.enres = 1; ++ phy_base->phy_ctl5.bits.enresck = 1; ++ phy_base->phy_ctl0.bits.entx = 0xF; ++ ++ for (i = 0; i < AW_PHY_TIMEOUT; i++) { ++ udelay(5); ++ status = phy_base->phy_pll_sts.bits.tx_ready_dly_status; ++ if (status & 0x1) { ++ pr_info("[%s]:tx_ready_status\n", __func__); ++ break; ++ } ++ } ++ if ((i == AW_PHY_TIMEOUT) && !status) { ++ pr_err("tx_ready_status Timeout ! status = 0x%x\n", status); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static int sun20i_d1_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct sun8i_hdmi_phy *phy = data; ++ volatile struct __aw_phy_reg_t __iomem *phy_base = phy->base; ++ int ret; ++ ++ pr_info("enter %s\n", __func__); ++ ++ /* enable all channel */ ++ phy_base->phy_ctl5.bits.reg_p1opt = 0xF; ++ ++ // phy_reset ++ phy_base->phy_ctl0.bits.entx = 0; ++ phy_base->phy_ctl5.bits.enresck = 0; ++ phy_base->phy_ctl5.bits.enres = 0; ++ phy_base->phy_ctl5.bits.enp2s = 0; ++ phy_base->phy_ctl0.bits.enck = 0; ++ phy_base->phy_ctl0.bits.enbi = 0; ++ phy_base->phy_ctl5.bits.encalog = 0; ++ phy_base->phy_ctl5.bits.enrcal = 0; ++ phy_base->phy_ctl0.bits.enldo_fs = 0; ++ phy_base->phy_ctl0.bits.enldo = 0; ++ phy_base->phy_ctl5.bits.enib = 0; ++ phy_base->pll_ctl1.bits.reset = 1; ++ phy_base->pll_ctl1.bits.pwron = 0; ++ phy_base->pll_ctl0.bits.envbs = 0; ++ ++ // phy_set_mpll ++ phy_base->pll_ctl0.bits.cko_sel = 0x3; ++ phy_base->pll_ctl0.bits.bypass_ppll = 0x1; ++ phy_base->pll_ctl1.bits.drv_ana = 1; ++ phy_base->pll_ctl1.bits.ctrl_modle_clksrc = 0x0; //0: PLL_video 1: MPLL ++ phy_base->pll_ctl1.bits.sdm_en = 0x0; //mpll sdm jitter is very large, not used for the time being ++ phy_base->pll_ctl1.bits.sckref = 0; //default value is 1 ++ phy_base->pll_ctl0.bits.slv = 4; ++ phy_base->pll_ctl0.bits.prop_cntrl = 7; //default value 7 ++ phy_base->pll_ctl0.bits.gmp_cntrl = 3; //default value 1 ++ phy_base->pll_ctl1.bits.ref_cntrl = 0; ++ phy_base->pll_ctl0.bits.vcorange = 1; ++ ++ // phy_set_div ++ phy_base->pll_ctl0.bits.div_pre = 0; //div7 = n+1 ++ phy_base->pll_ctl1.bits.pcnt_en = 0; ++ phy_base->pll_ctl1.bits.pcnt_n = 1; //div6 = 1 (pcnt_en=0) [div6 = n (pcnt_en = 1) note that some multiples are problematic] 4-256 ++ phy_base->pll_ctl1.bits.pixel_rep = 0; //div5 = n+1 ++ phy_base->pll_ctl0.bits.bypass_clrdpth = 0; ++ phy_base->pll_ctl0.bits.clr_dpth = 0; //div4 = 1 (bypass_clrdpth = 0) ++ //00: 2 01: 2.5 10: 3 11: 4 ++ phy_base->pll_ctl0.bits.n_cntrl = 1; //div ++ phy_base->pll_ctl0.bits.div2_ckbit = 0; //div1 = n+1 ++ phy_base->pll_ctl0.bits.div2_cktmds = 0; //div2 = n+1 ++ phy_base->pll_ctl0.bits.bcr = 0; //div3 0: [1:10] 1: [1:40] ++ phy_base->pll_ctl1.bits.pwron = 1; ++ phy_base->pll_ctl1.bits.reset = 0; ++ ++ // configure phy ++ /* config values taken from table */ ++ phy_base->phy_ctl1.dwval = ((phy_base->phy_ctl1.dwval & 0xFFC0FFFF) | /* config->phy_ctl1 */ 0x0); ++ phy_base->phy_ctl2.dwval = ((phy_base->phy_ctl2.dwval & 0xFF000000) | /* config->phy_ctl2 */ 0x0); ++ phy_base->phy_ctl3.dwval = ((phy_base->phy_ctl3.dwval & 0xFFFF0000) | /* config->phy_ctl3 */ 0xFFFF); ++ phy_base->phy_ctl4.dwval = ((phy_base->phy_ctl4.dwval & 0xE0000000) | /* config->phy_ctl4 */ 0xC0D0D0D); ++ //phy_base->pll_ctl0.dwval |= config->pll_ctl0; ++ //phy_base->pll_ctl1.dwval |= config->pll_ctl1; ++ ++ // phy_set_clk ++ phy_base->phy_ctl6.bits.switch_clkch_data_corresponding = 0; ++ phy_base->phy_ctl6.bits.clk_greate0_340m = 0x3FF; ++ phy_base->phy_ctl6.bits.clk_greate1_340m = 0x3FF; ++ phy_base->phy_ctl6.bits.clk_greate2_340m = 0x0; ++ phy_base->phy_ctl7.bits.clk_greate3_340m = 0x0; ++ phy_base->phy_ctl7.bits.clk_low_340m = 0x3E0; ++ phy_base->phy_ctl6.bits.en_ckdat = 1; //default value is 0 ++ ++ // phy_base->phy_ctl2.bits.reg_resdi = 0x18; ++ // phy_base->phy_ctl4.bits.reg_slv = 3; //low power voltage 1.08V, default value is 3 ++ ++ phy_base->phy_ctl1.bits.res_scktmds = 0; // ++ phy_base->phy_ctl0.bits.reg_csmps = 2; ++ phy_base->phy_ctl0.bits.reg_ck_test_sel = 0; //? ++ phy_base->phy_ctl0.bits.reg_ck_sel = 1; ++ phy_base->phy_indbg_ctrl.bits.txdata_debugmode = 0; ++ ++ // phy_enable ++ ret = sun20i_d1_hdmi_phy_enable(phy_base); ++ if (ret) ++ return ret; ++ ++ phy_base->phy_ctl0.bits.sda_en = 1; ++ phy_base->phy_ctl0.bits.scl_en = 1; ++ phy_base->phy_ctl0.bits.hpd_en = 1; ++ phy_base->phy_ctl0.bits.reg_den = 0xF; ++ phy_base->pll_ctl0.bits.envbs = 1; + + return 0; + } +@@ -720,6 +875,7 @@ static int sun8i_hdmi_phy_probe(struct p + return dev_err_probe(dev, PTR_ERR(regs), + "Couldn't map the HDMI PHY registers\n"); + ++ phy->base = regs; + phy->regs = devm_regmap_init_mmio(dev, regs, + &sun8i_hdmi_phy_regmap_config); + if (IS_ERR(phy->regs)) diff --git a/target/linux/d1/patches-6.1/0010-riscv-mm-Use-IOMMU-for-DMA-when-available.patch b/target/linux/d1/patches-6.1/0010-riscv-mm-Use-IOMMU-for-DMA-when-available.patch new file mode 100644 index 0000000000..18dfa573e3 --- /dev/null +++ b/target/linux/d1/patches-6.1/0010-riscv-mm-Use-IOMMU-for-DMA-when-available.patch @@ -0,0 +1,30 @@ +From 02a412de18479449c87ed7a332e3fe33d2eff3a4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 27 Apr 2022 18:47:53 -0500 +Subject: [PATCH 010/117] riscv: mm: Use IOMMU for DMA when available + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/mm/dma-noncoherent.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/riscv/mm/dma-noncoherent.c ++++ b/arch/riscv/mm/dma-noncoherent.c +@@ -7,6 +7,7 @@ + + #include <linux/dma-direct.h> + #include <linux/dma-map-ops.h> ++#include <linux/iommu.h> + #include <linux/mm.h> + #include <asm/cacheflush.h> + +@@ -70,6 +71,9 @@ void arch_setup_dma_ops(struct device *d + dev_driver_string(dev), dev_name(dev)); + + dev->dma_coherent = coherent; ++ ++ if (iommu) ++ iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1); + } + + void riscv_noncoherent_supported(void) diff --git a/target/linux/d1/patches-6.1/0011-genirq-Add-support-for-oneshot-safe-threaded-EOIs.patch b/target/linux/d1/patches-6.1/0011-genirq-Add-support-for-oneshot-safe-threaded-EOIs.patch new file mode 100644 index 0000000000..d8dd2878d1 --- /dev/null +++ b/target/linux/d1/patches-6.1/0011-genirq-Add-support-for-oneshot-safe-threaded-EOIs.patch @@ -0,0 +1,124 @@ +From ee6459d60f24d91052f0288155f44e6a7f991050 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 7 May 2022 18:34:25 -0500 +Subject: [PATCH 011/117] genirq: Add support for oneshot-safe threaded EOIs + +irqchips can use the combination of flags IRQCHIP_ONESHOT_SAFE | +IRQCHIP_EOI_THREADED to elide mask operations. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + kernel/irq/chip.c | 36 +++++++++++++++++------------------- + kernel/irq/internals.h | 2 +- + kernel/irq/manage.c | 12 ++++++------ + 3 files changed, 24 insertions(+), 26 deletions(-) + +--- a/kernel/irq/chip.c ++++ b/kernel/irq/chip.c +@@ -439,16 +439,6 @@ void unmask_irq(struct irq_desc *desc) + } + } + +-void unmask_threaded_irq(struct irq_desc *desc) +-{ +- struct irq_chip *chip = desc->irq_data.chip; +- +- if (chip->flags & IRQCHIP_EOI_THREADED) +- chip->irq_eoi(&desc->irq_data); +- +- unmask_irq(desc); +-} +- + /* + * handle_nested_irq - Handle a nested irq from a irq thread + * @irq: the interrupt number +@@ -656,25 +646,33 @@ out_unlock: + } + EXPORT_SYMBOL_GPL(handle_level_irq); + +-static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) ++void unmask_eoi_threaded_irq(struct irq_desc *desc) + { +- if (!(desc->istate & IRQS_ONESHOT)) { ++ struct irq_chip *chip = desc->irq_data.chip; ++ ++ if (desc->istate & IRQS_ONESHOT) ++ unmask_irq(desc); ++ ++ if (chip->flags & IRQCHIP_EOI_THREADED) + chip->irq_eoi(&desc->irq_data); ++} ++ ++static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) ++{ ++ /* Do not send EOI if the thread will do it for us. */ ++ if ((chip->flags & IRQCHIP_EOI_THREADED) && desc->threads_oneshot) + return; +- } ++ + /* + * We need to unmask in the following cases: + * - Oneshot irq which did not wake the thread (caused by a + * spurious interrupt or a primary handler handling it + * completely). + */ +- if (!irqd_irq_disabled(&desc->irq_data) && +- irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) { +- chip->irq_eoi(&desc->irq_data); ++ if ((desc->istate & IRQS_ONESHOT) && !desc->threads_oneshot) + unmask_irq(desc); +- } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) { +- chip->irq_eoi(&desc->irq_data); +- } ++ ++ chip->irq_eoi(&desc->irq_data); + } + + /** +--- a/kernel/irq/internals.h ++++ b/kernel/irq/internals.h +@@ -93,7 +93,7 @@ extern void irq_percpu_enable(struct irq + extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu); + extern void mask_irq(struct irq_desc *desc); + extern void unmask_irq(struct irq_desc *desc); +-extern void unmask_threaded_irq(struct irq_desc *desc); ++extern void unmask_eoi_threaded_irq(struct irq_desc *desc); + + #ifdef CONFIG_SPARSE_IRQ + static inline void irq_mark_irq(unsigned int irq) { } +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -1074,9 +1074,9 @@ static int irq_wait_for_interrupt(struct + static void irq_finalize_oneshot(struct irq_desc *desc, + struct irqaction *action) + { +- if (!(desc->istate & IRQS_ONESHOT) || +- action->handler == irq_forced_secondary_handler) ++ if (action->handler == irq_forced_secondary_handler) + return; ++ + again: + chip_bus_lock(desc); + raw_spin_lock_irq(&desc->lock); +@@ -1112,9 +1112,8 @@ again: + + desc->threads_oneshot &= ~action->thread_mask; + +- if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && +- irqd_irq_masked(&desc->irq_data)) +- unmask_threaded_irq(desc); ++ if (!desc->threads_oneshot) ++ unmask_eoi_threaded_irq(desc); + + out_unlock: + raw_spin_unlock_irq(&desc->lock); +@@ -1662,7 +1661,8 @@ __setup_irq(unsigned int irq, struct irq + * !ONESHOT irqs the thread mask is 0 so we can avoid a + * conditional in irq_wake_thread(). + */ +- if (new->flags & IRQF_ONESHOT) { ++ if ((new->flags & IRQF_ONESHOT) || ++ (desc->irq_data.chip->flags & (IRQCHIP_ONESHOT_SAFE | IRQCHIP_EOI_THREADED)) == (IRQCHIP_ONESHOT_SAFE | IRQCHIP_EOI_THREADED)) { + /* + * Unlikely to have 32 resp 64 irqs sharing one line, + * but who knows. diff --git a/target/linux/d1/patches-6.1/0012-irqchip-sifive-plic-Enable-oneshot-safe-threaded-EOI.patch b/target/linux/d1/patches-6.1/0012-irqchip-sifive-plic-Enable-oneshot-safe-threaded-EOI.patch new file mode 100644 index 0000000000..429a5d6824 --- /dev/null +++ b/target/linux/d1/patches-6.1/0012-irqchip-sifive-plic-Enable-oneshot-safe-threaded-EOI.patch @@ -0,0 +1,24 @@ +From 1fbe96ec05c41b313b4e7cc4b39b191b4a3f7540 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 7 May 2022 18:38:34 -0500 +Subject: [PATCH 012/117] irqchip/sifive-plic: Enable oneshot-safe threaded + EOIs + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/irqchip/irq-sifive-plic.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -201,7 +201,9 @@ static struct irq_chip plic_chip = { + .irq_set_affinity = plic_set_affinity, + #endif + .irq_set_type = plic_irq_set_type, +- .flags = IRQCHIP_AFFINITY_PRE_STARTUP, ++ .flags = IRQCHIP_ONESHOT_SAFE | ++ IRQCHIP_EOI_THREADED | ++ IRQCHIP_AFFINITY_PRE_STARTUP, + }; + + static int plic_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/target/linux/d1/patches-6.1/0013-irqchip-sifive-plic-Support-wake-IRQs.patch b/target/linux/d1/patches-6.1/0013-irqchip-sifive-plic-Support-wake-IRQs.patch new file mode 100644 index 0000000000..e9033b7d66 --- /dev/null +++ b/target/linux/d1/patches-6.1/0013-irqchip-sifive-plic-Support-wake-IRQs.patch @@ -0,0 +1,32 @@ +From d6cf6473b0aaec455e48bccefe318a98a87b789f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 28 May 2022 19:04:56 -0500 +Subject: [PATCH 013/117] irqchip/sifive-plic: Support wake IRQs + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/irqchip/irq-sifive-plic.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/irqchip/irq-sifive-plic.c ++++ b/drivers/irqchip/irq-sifive-plic.c +@@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = + .irq_set_affinity = plic_set_affinity, + #endif + .irq_set_type = plic_irq_set_type, +- .flags = IRQCHIP_AFFINITY_PRE_STARTUP, ++ .flags = IRQCHIP_SKIP_SET_WAKE | ++ IRQCHIP_AFFINITY_PRE_STARTUP, + }; + + static struct irq_chip plic_chip = { +@@ -201,7 +202,8 @@ static struct irq_chip plic_chip = { + .irq_set_affinity = plic_set_affinity, + #endif + .irq_set_type = plic_irq_set_type, +- .flags = IRQCHIP_ONESHOT_SAFE | ++ .flags = IRQCHIP_SKIP_SET_WAKE | ++ IRQCHIP_ONESHOT_SAFE | + IRQCHIP_EOI_THREADED | + IRQCHIP_AFFINITY_PRE_STARTUP, + }; diff --git a/target/linux/d1/patches-6.1/0014-mmc-sunxi-mmc-Correct-the-maximum-segment-size.patch b/target/linux/d1/patches-6.1/0014-mmc-sunxi-mmc-Correct-the-maximum-segment-size.patch new file mode 100644 index 0000000000..7e8098a2cf --- /dev/null +++ b/target/linux/d1/patches-6.1/0014-mmc-sunxi-mmc-Correct-the-maximum-segment-size.patch @@ -0,0 +1,65 @@ +From 0e871e791a2530562851109346affa1c0d9987e0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:15:56 -0500 +Subject: [PATCH 014/117] mmc: sunxi-mmc: Correct the maximum segment size + +According to the DMA descriptor documentation, the lowest two bits of +the size field are ignored, so the size must be rounded up to a multiple +of 4 bytes. Furthermore, 0 is not a valid buffer size; setting the size +to 0 will cause that DMA descriptor to be ignored. + +Together, these restrictions limit the maximum DMA segment size to 4 +less than the power-of-two width of the size field. + +Series-to: Ulf Hansson <ulf.hansson@linaro.org> +Series-to: linux-mmc@vger.kernel.org + +Fixes: 3cbcb16095f9 ("mmc: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs") +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/mmc/host/sunxi-mmc.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/mmc/host/sunxi-mmc.c ++++ b/drivers/mmc/host/sunxi-mmc.c +@@ -214,6 +214,9 @@ + #define SDXC_IDMAC_DES0_CES BIT(30) /* card error summary */ + #define SDXC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */ + ++/* Buffer size must be a multiple of 4 bytes. */ ++#define SDXC_IDMAC_SIZE_ALIGN 4 ++ + #define SDXC_CLK_400K 0 + #define SDXC_CLK_25M 1 + #define SDXC_CLK_50M 2 +@@ -361,17 +364,15 @@ static void sunxi_mmc_init_idma_des(stru + { + struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu; + dma_addr_t next_desc = host->sg_dma; +- int i, max_len = (1 << host->cfg->idma_des_size_bits); ++ int i; + + for (i = 0; i < data->sg_len; i++) { + pdes[i].config = cpu_to_le32(SDXC_IDMAC_DES0_CH | + SDXC_IDMAC_DES0_OWN | + SDXC_IDMAC_DES0_DIC); + +- if (data->sg[i].length == max_len) +- pdes[i].buf_size = 0; /* 0 == max_len */ +- else +- pdes[i].buf_size = cpu_to_le32(data->sg[i].length); ++ pdes[i].buf_size = cpu_to_le32(ALIGN(data->sg[i].length, ++ SDXC_IDMAC_SIZE_ALIGN)); + + next_desc += sizeof(struct sunxi_idma_des); + pdes[i].buf_addr_ptr1 = +@@ -1421,7 +1422,8 @@ static int sunxi_mmc_probe(struct platfo + mmc->max_blk_count = 8192; + mmc->max_blk_size = 4096; + mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des); +- mmc->max_seg_size = (1 << host->cfg->idma_des_size_bits); ++ mmc->max_seg_size = (1 << host->cfg->idma_des_size_bits) - ++ SDXC_IDMAC_SIZE_ALIGN; + mmc->max_req_size = mmc->max_seg_size * mmc->max_segs; + /* 400kHz ~ 52MHz */ + mmc->f_min = 400000; diff --git a/target/linux/d1/patches-6.1/0015-dt-bindings-display-Add-bindings-for-ClockworkPi-CWD.patch b/target/linux/d1/patches-6.1/0015-dt-bindings-display-Add-bindings-for-ClockworkPi-CWD.patch new file mode 100644 index 0000000000..665c55058c --- /dev/null +++ b/target/linux/d1/patches-6.1/0015-dt-bindings-display-Add-bindings-for-ClockworkPi-CWD.patch @@ -0,0 +1,82 @@ +From a8e905fb3fd0d26f724646275b72a7363b2f03d8 Mon Sep 17 00:00:00 2001 +From: Max Fierke <max@maxfierke.com> +Date: Wed, 1 Jun 2022 00:17:47 -0500 +Subject: [PATCH 015/117] dt-bindings: display: Add bindings for ClockworkPi + CWD686 + +The CWD686 is a 6.86" IPS LCD panel used as the primary +display in the ClockworkPi DevTerm portable (all cores) + +Signed-off-by: Max Fierke <max@maxfierke.com> +Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../display/panel/clockwork,cwd686.yaml | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/panel/clockwork,cwd686.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/clockwork,cwd686.yaml +@@ -0,0 +1,62 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/clockwork,cwd686.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Clockwork CWD686 6.86" IPS LCD panel ++ ++maintainers: ++ - Max Fierke <max@maxfierke.com> ++ ++description: | ++ The Clockwork CWD686 is a 6.86" ICNL9707-based IPS LCD panel used within the ++ Clockwork DevTerm series of portable devices. The panel has a 480x1280 ++ resolution and uses 24 bit RGB per pixel. ++ ++allOf: ++ - $ref: panel-common.yaml# ++ ++properties: ++ compatible: ++ const: clockwork,cwd686 ++ ++ reg: ++ description: DSI virtual channel used by that screen ++ maxItems: 1 ++ ++ reset-gpios: true ++ rotation: true ++ backlight: true ++ iovcc-supply: true ++ vci-supply: true ++ ++required: ++ - compatible ++ - reg ++ - backlight ++ - reset-gpios ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include <dt-bindings/gpio/gpio.h> ++ ++ backlight: backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ dsi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ panel@0 { ++ compatible = "clockwork,cwd686"; ++ reg = <0>; ++ backlight = <&backlight>; ++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; ++ rotation = <90>; ++ }; ++ }; diff --git a/target/linux/d1/patches-6.1/0016-dt-bindings-display-Add-Sitronix-ST7701s-panel-bindi.patch b/target/linux/d1/patches-6.1/0016-dt-bindings-display-Add-Sitronix-ST7701s-panel-bindi.patch new file mode 100644 index 0000000000..85d8421f62 --- /dev/null +++ b/target/linux/d1/patches-6.1/0016-dt-bindings-display-Add-Sitronix-ST7701s-panel-bindi.patch @@ -0,0 +1,47 @@ +From d290546a88694dde6d2f64a973cd62ff2c69e27e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 12 Aug 2022 01:59:35 -0500 +Subject: [PATCH 016/117] dt-bindings: display: Add Sitronix ST7701s panel + binding + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../display/panel/sitronix,st7701s.yaml | 32 +++++++++++++++++++ + 1 file changed, 32 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/panel/sitronix,st7701s.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7701s.yaml +@@ -0,0 +1,32 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/sitronix,st7701s.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sitronix ST7701 based LCD panels ++ ++maintainers: ++ - Samuel Holland <samuel@sholland.org> ++ ++description: | ++ Panel used on Lichee RV 86 Panel ++ ++allOf: ++ - $ref: panel-common.yaml# ++ - $ref: /schemas/spi/spi-peripheral-props.yaml# ++ ++properties: ++ compatible: ++ items: ++ - const: sitronix,st7701s ++ ++ backlight: true ++ ++ reset-gpios: true ++ ++required: ++ - compatible ++ - reset-gpios ++ ++unevaluatedProperties: false diff --git a/target/linux/d1/patches-6.1/0017-drm-panel-Add-driver-for-ST7701s-DPI-LCD-panel.patch b/target/linux/d1/patches-6.1/0017-drm-panel-Add-driver-for-ST7701s-DPI-LCD-panel.patch new file mode 100644 index 0000000000..535478cf9e --- /dev/null +++ b/target/linux/d1/patches-6.1/0017-drm-panel-Add-driver-for-ST7701s-DPI-LCD-panel.patch @@ -0,0 +1,487 @@ +From 9d9b8bd567c30a821c82c27035243536c5234542 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 29 Mar 2022 22:47:57 -0500 +Subject: [PATCH 017/117] drm/panel: Add driver for ST7701s DPI LCD panel + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/Kconfig | 8 + + drivers/gpu/drm/panel/Makefile | 1 + + .../gpu/drm/panel/panel-sitronix-st7701s.c | 444 ++++++++++++++++++ + 3 files changed, 453 insertions(+) + create mode 100644 drivers/gpu/drm/panel/panel-sitronix-st7701s.c + +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -608,6 +608,14 @@ config DRM_PANEL_SITRONIX_ST7701 + ST7701 controller for 480X864 LCD panels with MIPI/RGB/SPI + system interfaces. + ++config DRM_PANEL_SITRONIX_ST7701S ++ tristate "Sitronix ST7701s panel driver" ++ depends on OF ++ depends on BACKLIGHT_CLASS_DEVICE ++ help ++ Say Y here if you want to enable support for the Sitronix ++ ST7701s controller with a SPI interface. ++ + config DRM_PANEL_SITRONIX_ST7703 + tristate "Sitronix ST7703 based MIPI touchscreen panels" + depends on OF +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -61,6 +61,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01 + obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o + obj-$(CONFIG_DRM_PANEL_SHARP_LS060T1SX01) += panel-sharp-ls060t1sx01.o + obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o ++obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701S) += panel-sitronix-st7701s.o + obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o + obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o + obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-sitronix-st7701s.c +@@ -0,0 +1,444 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2017 Free Electrons ++ */ ++ ++#include <linux/delay.h> ++#include <linux/gpio/consumer.h> ++#include <linux/module.h> ++#include <linux/spi/spi.h> ++ ++#include <video/mipi_display.h> ++ ++#include <drm/drm_device.h> ++#include <drm/drm_modes.h> ++#include <drm/drm_panel.h> ++ ++struct st7701s { ++ struct drm_panel panel; ++ struct gpio_desc *reset; ++ struct spi_device *spi; ++}; ++ ++enum { ++ ST7789V_COMMAND = 0 << 8, ++ ST7789V_DATA = 1 << 8, ++}; ++ ++#define LCD_WRITE_COMMAND(x) (ST7789V_COMMAND | (x)) ++#define LCD_WRITE_DATA(x) (ST7789V_DATA | (x)) ++ ++static const u16 st7701s_init_sequence_1[] = { ++ LCD_WRITE_COMMAND(0xFF), ++ LCD_WRITE_DATA(0x77), ++ LCD_WRITE_DATA(0x01), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x10), ++ ++ LCD_WRITE_COMMAND(0xC0), ++ LCD_WRITE_DATA(0x3B), ++ LCD_WRITE_DATA(0x00), ++ ++ LCD_WRITE_COMMAND(0xC1), ++ LCD_WRITE_DATA(0x0D), ++ LCD_WRITE_DATA(0x02), ++ ++ LCD_WRITE_COMMAND(0xC2), ++ LCD_WRITE_DATA(0x21), ++ LCD_WRITE_DATA(0x08), ++ ++ // RGB Interface Setting ++ // LCD_WRITE_COMMAND(0xC3), ++ // LCD_WRITE_DATA(0x02), ++ ++ LCD_WRITE_COMMAND(0xCD), ++ LCD_WRITE_DATA(0x18),//0F 08-OK D0-D18 ++ ++ LCD_WRITE_COMMAND(0xB0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x18), ++ LCD_WRITE_DATA(0x0E), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x06), ++ LCD_WRITE_DATA(0x07), ++ LCD_WRITE_DATA(0x08), ++ LCD_WRITE_DATA(0x07), ++ LCD_WRITE_DATA(0x22), ++ LCD_WRITE_DATA(0x04), ++ LCD_WRITE_DATA(0x12), ++ LCD_WRITE_DATA(0x0F), ++ LCD_WRITE_DATA(0xAA), ++ LCD_WRITE_DATA(0x31), ++ LCD_WRITE_DATA(0x18), ++ ++ LCD_WRITE_COMMAND(0xB1), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x19), ++ LCD_WRITE_DATA(0x0E), ++ LCD_WRITE_DATA(0x12), ++ LCD_WRITE_DATA(0x07), ++ LCD_WRITE_DATA(0x08), ++ LCD_WRITE_DATA(0x08), ++ LCD_WRITE_DATA(0x08), ++ LCD_WRITE_DATA(0x22), ++ LCD_WRITE_DATA(0x04), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0xA9), ++ LCD_WRITE_DATA(0x32), ++ LCD_WRITE_DATA(0x18), ++ ++ LCD_WRITE_COMMAND(0xFF), ++ LCD_WRITE_DATA(0x77), ++ LCD_WRITE_DATA(0x01), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x11), ++ ++ LCD_WRITE_COMMAND(0xB0), ++ LCD_WRITE_DATA(0x60), ++ ++ LCD_WRITE_COMMAND(0xB1), ++ LCD_WRITE_DATA(0x30), ++ ++ LCD_WRITE_COMMAND(0xB2), ++ LCD_WRITE_DATA(0x87), ++ ++ LCD_WRITE_COMMAND(0xB3), ++ LCD_WRITE_DATA(0x80), ++ ++ LCD_WRITE_COMMAND(0xB5), ++ LCD_WRITE_DATA(0x49), ++ ++ LCD_WRITE_COMMAND(0xB7), ++ LCD_WRITE_DATA(0x85), ++ ++ LCD_WRITE_COMMAND(0xB8), ++ LCD_WRITE_DATA(0x21), ++ ++ LCD_WRITE_COMMAND(0xC1), ++ LCD_WRITE_DATA(0x78), ++ ++ LCD_WRITE_COMMAND(0xC2), ++ LCD_WRITE_DATA(0x78), ++}; ++ ++static const u16 st7701s_init_sequence_2[] = { ++ LCD_WRITE_COMMAND(0xE0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x1B), ++ LCD_WRITE_DATA(0x02), ++ ++ LCD_WRITE_COMMAND(0xE1), ++ LCD_WRITE_DATA(0x08), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x07), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x44), ++ LCD_WRITE_DATA(0x44), ++ ++ LCD_WRITE_COMMAND(0xE2), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x44), ++ LCD_WRITE_DATA(0x44), ++ LCD_WRITE_DATA(0xED), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0xEC), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ ++ LCD_WRITE_COMMAND(0xE3), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x11), ++ ++ LCD_WRITE_COMMAND(0xE4), ++ LCD_WRITE_DATA(0x44), ++ LCD_WRITE_DATA(0x44), ++ ++ LCD_WRITE_COMMAND(0xE5), ++ LCD_WRITE_DATA(0x0A), ++ LCD_WRITE_DATA(0xE9), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x0C), ++ LCD_WRITE_DATA(0xEB), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x0E), ++ LCD_WRITE_DATA(0xED), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x10), ++ LCD_WRITE_DATA(0xEF), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ ++ LCD_WRITE_COMMAND(0xE6), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x11), ++ LCD_WRITE_DATA(0x11), ++ ++ LCD_WRITE_COMMAND(0xE7), ++ LCD_WRITE_DATA(0x44), ++ LCD_WRITE_DATA(0x44), ++ ++ LCD_WRITE_COMMAND(0xE8), ++ LCD_WRITE_DATA(0x09), ++ LCD_WRITE_DATA(0xE8), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x0B), ++ LCD_WRITE_DATA(0xEA), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x0D), ++ LCD_WRITE_DATA(0xEC), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ LCD_WRITE_DATA(0x0F), ++ LCD_WRITE_DATA(0xEE), ++ LCD_WRITE_DATA(0xD8), ++ LCD_WRITE_DATA(0xA0), ++ ++ LCD_WRITE_COMMAND(0xEB), ++ LCD_WRITE_DATA(0x02), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0xE4), ++ LCD_WRITE_DATA(0xE4), ++ LCD_WRITE_DATA(0x88), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x40), ++ ++ LCD_WRITE_COMMAND(0xEC), ++ LCD_WRITE_DATA(0x3C), ++ LCD_WRITE_DATA(0x00), ++ ++ LCD_WRITE_COMMAND(0xED), ++ LCD_WRITE_DATA(0xAB), ++ LCD_WRITE_DATA(0x89), ++ LCD_WRITE_DATA(0x76), ++ LCD_WRITE_DATA(0x54), ++ LCD_WRITE_DATA(0x02), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0xFF), ++ LCD_WRITE_DATA(0x20), ++ LCD_WRITE_DATA(0x45), ++ LCD_WRITE_DATA(0x67), ++ LCD_WRITE_DATA(0x98), ++ LCD_WRITE_DATA(0xBA), ++ ++ LCD_WRITE_COMMAND(0xFF), ++ LCD_WRITE_DATA(0x77), ++ LCD_WRITE_DATA(0x01), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ LCD_WRITE_DATA(0x00), ++ ++ LCD_WRITE_COMMAND(MIPI_DCS_SET_PIXEL_FORMAT), ++ LCD_WRITE_DATA(0x66), ++ ++ LCD_WRITE_COMMAND(MIPI_DCS_SET_ADDRESS_MODE), ++ LCD_WRITE_DATA(0x00), ++ ++ LCD_WRITE_COMMAND(MIPI_DCS_ENTER_INVERT_MODE), ++ ++ LCD_WRITE_COMMAND(MIPI_DCS_EXIT_SLEEP_MODE), ++}; ++ ++static const u16 st7701s_enable_sequence[] = { ++ LCD_WRITE_COMMAND(MIPI_DCS_SET_DISPLAY_ON), ++}; ++ ++static const u16 st7701s_disable_sequence[] = { ++ LCD_WRITE_COMMAND(MIPI_DCS_SET_DISPLAY_OFF), ++}; ++ ++static inline struct st7701s *panel_to_st7701s(struct drm_panel *panel) ++{ ++ return container_of(panel, struct st7701s, panel); ++} ++ ++static int st7701s_spi_write(struct st7701s *ctx, const u16 *data, size_t size) ++{ ++ struct spi_transfer xfer = { }; ++ struct spi_message msg; ++ ++ spi_message_init(&msg); ++ ++ xfer.tx_buf = data; ++ xfer.bits_per_word = 9; ++ xfer.len = size; ++ ++ spi_message_add_tail(&xfer, &msg); ++ return spi_sync(ctx->spi, &msg); ++} ++ ++static const struct drm_display_mode default_mode = { ++ .clock = 19800, ++ .hdisplay = 480, ++ .hsync_start = 480 + 60, ++ .hsync_end = 480 + 60 + 12, ++ .htotal = 480 + 60 + 12 + 60, ++ .vdisplay = 480, ++ .vsync_start = 480 + 18, ++ .vsync_end = 480 + 18 + 4, ++ .vtotal = 480 + 18 + 4 + 18, ++}; ++ ++static int st7701s_get_modes(struct drm_panel *panel, ++ struct drm_connector *connector) ++{ ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, &default_mode); ++ if (!mode) ++ return -ENOMEM; ++ ++ drm_mode_set_name(mode); ++ ++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ drm_mode_probed_add(connector, mode); ++ ++ connector->display_info.width_mm = 70; ++ connector->display_info.height_mm = 72; ++ ++ return 1; ++} ++ ++static int st7701s_prepare(struct drm_panel *panel) ++{ ++ struct st7701s *ctx = panel_to_st7701s(panel); ++ ++ gpiod_set_value_cansleep(ctx->reset, 1); ++ msleep(20); ++ ++ gpiod_set_value_cansleep(ctx->reset, 0); ++ msleep(20); ++ ++ st7701s_spi_write(ctx, st7701s_init_sequence_1, ++ sizeof(st7701s_init_sequence_1)); ++ msleep(20); ++ ++ st7701s_spi_write(ctx, st7701s_init_sequence_2, ++ sizeof(st7701s_init_sequence_2)); ++ msleep(120); ++ ++ return 0; ++} ++ ++static int st7701s_enable(struct drm_panel *panel) ++{ ++ struct st7701s *ctx = panel_to_st7701s(panel); ++ ++ st7701s_spi_write(ctx, st7701s_enable_sequence, ++ sizeof(st7701s_enable_sequence)); ++ msleep(20); ++ ++ return 0; ++} ++ ++static int st7701s_disable(struct drm_panel *panel) ++{ ++ struct st7701s *ctx = panel_to_st7701s(panel); ++ ++ st7701s_spi_write(ctx, st7701s_disable_sequence, ++ sizeof(st7701s_disable_sequence)); ++ ++ return 0; ++} ++ ++static int st7701s_unprepare(struct drm_panel *panel) ++{ ++ return 0; ++} ++ ++static const struct drm_panel_funcs st7701s_drm_funcs = { ++ .disable = st7701s_disable, ++ .enable = st7701s_enable, ++ .get_modes = st7701s_get_modes, ++ .prepare = st7701s_prepare, ++ .unprepare = st7701s_unprepare, ++}; ++ ++static int st7701s_probe(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct st7701s *ctx; ++ int ret; ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ spi_set_drvdata(spi, ctx); ++ ctx->spi = spi; ++ ++ ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(ctx->reset)) { ++ dev_err(&spi->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(ctx->reset); ++ } ++ ++ drm_panel_init(&ctx->panel, dev, &st7701s_drm_funcs, ++ DRM_MODE_CONNECTOR_DPI); ++ ++ ret = drm_panel_of_backlight(&ctx->panel); ++ if (ret) ++ return ret; ++ ++ drm_panel_add(&ctx->panel); ++ ++ return 0; ++} ++ ++static void st7701s_remove(struct spi_device *spi) ++{ ++ struct st7701s *ctx = spi_get_drvdata(spi); ++ ++ drm_panel_remove(&ctx->panel); ++} ++ ++static const struct of_device_id st7701s_of_match[] = { ++ { .compatible = "sitronix,st7701s" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, st7701s_of_match); ++ ++static const struct spi_device_id st7701s_ids[] = { ++ { "st7701s" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(spi, st7701s_ids); ++ ++static struct spi_driver st7701s_driver = { ++ .probe = st7701s_probe, ++ .remove = st7701s_remove, ++ .driver = { ++ .name = "st7701s", ++ .of_match_table = st7701s_of_match, ++ }, ++}; ++module_spi_driver(st7701s_driver); ++ ++MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); ++MODULE_DESCRIPTION("Sitronix ST7701s LCD Driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/d1/patches-6.1/0018-nvmem-sunxi_sid-Drop-the-workaround-on-A64.patch b/target/linux/d1/patches-6.1/0018-nvmem-sunxi_sid-Drop-the-workaround-on-A64.patch new file mode 100644 index 0000000000..1db6899a19 --- /dev/null +++ b/target/linux/d1/patches-6.1/0018-nvmem-sunxi_sid-Drop-the-workaround-on-A64.patch @@ -0,0 +1,42 @@ +From db71abf941d25b92b2117780d3771197417d1c81 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 31 Jul 2022 20:34:20 -0500 +Subject: [PATCH 018/117] nvmem: sunxi_sid: Drop the workaround on A64 + +Now that the SRAM readout code is fixed by using 32-bit accesses, it +always returns the same values as register readout, so the A64 variant +no longer needs the workaround. This makes the D1 variant structure +redundant, so remove it. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/nvmem/sunxi_sid.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/drivers/nvmem/sunxi_sid.c ++++ b/drivers/nvmem/sunxi_sid.c +@@ -196,15 +196,9 @@ static const struct sunxi_sid_cfg sun8i_ + .need_register_readout = true, + }; + +-static const struct sunxi_sid_cfg sun20i_d1_cfg = { +- .value_offset = 0x200, +- .size = 0x100, +-}; +- + static const struct sunxi_sid_cfg sun50i_a64_cfg = { + .value_offset = 0x200, + .size = 0x100, +- .need_register_readout = true, + }; + + static const struct sunxi_sid_cfg sun50i_h6_cfg = { +@@ -217,7 +211,7 @@ static const struct of_device_id sunxi_s + { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg }, + { .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg }, +- { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg }, ++ { .compatible = "allwinner,sun20i-d1-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg }, diff --git a/target/linux/d1/patches-6.1/0019-dt-bindings-nvmem-Allow-bit-offsets-greater-than-a-b.patch b/target/linux/d1/patches-6.1/0019-dt-bindings-nvmem-Allow-bit-offsets-greater-than-a-b.patch new file mode 100644 index 0000000000..ee4a7f742b --- /dev/null +++ b/target/linux/d1/patches-6.1/0019-dt-bindings-nvmem-Allow-bit-offsets-greater-than-a-b.patch @@ -0,0 +1,30 @@ +From d03341ef7acb64803ade6b173d24f49ffa6149a3 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 2 Aug 2022 00:29:32 -0500 +Subject: [PATCH 019/117] dt-bindings: nvmem: Allow bit offsets greater than a + byte + +Some NVMEM devices contain cells which do not start at a multiple of the +device's stride. However, the "reg" property of a cell must be aligned +to its provider device's stride. + +These cells can be represented in the DT using the "bits" property if +that property allows offsets up to the full stride. 63 is chosen +assuming that NVMEM devices will not have strides larger than 8 bytes. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + Documentation/devicetree/bindings/nvmem/nvmem.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml ++++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml +@@ -53,7 +53,7 @@ patternProperties: + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - minimum: 0 +- maximum: 7 ++ maximum: 63 + description: + Offset in bit within the address range specified by reg. + - minimum: 1 diff --git a/target/linux/d1/patches-6.1/0020-regulator-dt-bindings-Add-Allwinner-D1-LDOs.patch b/target/linux/d1/patches-6.1/0020-regulator-dt-bindings-Add-Allwinner-D1-LDOs.patch new file mode 100644 index 0000000000..0e59af2f38 --- /dev/null +++ b/target/linux/d1/patches-6.1/0020-regulator-dt-bindings-Add-Allwinner-D1-LDOs.patch @@ -0,0 +1,156 @@ +From f666d95c1443854555044d3d4b52c463cf845ccc Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 17 Jul 2022 20:33:40 -0500 +Subject: [PATCH 020/117] regulator: dt-bindings: Add Allwinner D1 LDOs + +The Allwinner D1 SoC contains two pairs of in-package LDOs. One pair is +for general purpose use. LDOA generally powers the board's 1.8 V rail. +LDOB generally powers the in-package DRAM, where applicable. + +The other pair of LDOs powers the analog power domains inside the SoC, +including the audio codec, thermal sensor, and ADCs. These LDOs require +a 0.9 V bandgap voltage reference. The calibration value for the voltage +reference is stored in an eFuse, accessed via an NVMEM cell. + +Neither LDO control register is in its own MMIO range; instead, each +regulator device relies on a regmap/syscon exported by its parent. + +Series-changes: 2 + - Remove syscon property from bindings + - Update binding examples to fix warnings and provide context + +Series-changes: 3 + - Add "reg" property to bindings + - Add "unevaluatedProperties: true" to regulator nodes + - Minor changes to regulator node name patterns + - Remove system-ldos example (now added in patch 3) + +Series-changes: 4 + - Fix the order of the maintainer/description sections + - Replace unevaluatedProperties with "additionalProperties: false" + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../allwinner,sun20i-d1-analog-ldos.yaml | 74 +++++++++++++++++++ + .../allwinner,sun20i-d1-system-ldos.yaml | 37 ++++++++++ + 2 files changed, 111 insertions(+) + create mode 100644 Documentation/devicetree/bindings/regulator/allwinner,sun20i-d1-analog-ldos.yaml + create mode 100644 Documentation/devicetree/bindings/regulator/allwinner,sun20i-d1-system-ldos.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/regulator/allwinner,sun20i-d1-analog-ldos.yaml +@@ -0,0 +1,74 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/regulator/allwinner,sun20i-d1-analog-ldos.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Allwinner D1 Analog LDOs ++ ++maintainers: ++ - Samuel Holland <samuel@sholland.org> ++ ++description: ++ Allwinner D1 contains a set of LDOs which are designed to supply analog power ++ inside and outside the SoC. They are controlled by a register within the audio ++ codec MMIO space, but which is not part of the audio codec clock/reset domain. ++ ++properties: ++ compatible: ++ enum: ++ - allwinner,sun20i-d1-analog-ldos ++ ++ reg: ++ maxItems: 1 ++ ++ nvmem-cells: ++ items: ++ - description: NVMEM cell for the calibrated bandgap reference trim value ++ ++ nvmem-cell-names: ++ items: ++ - const: bg_trim ++ ++patternProperties: ++ "^(a|hp)ldo$": ++ type: object ++ $ref: regulator.yaml# ++ unevaluatedProperties: false ++ ++required: ++ - compatible ++ - reg ++ - nvmem-cells ++ - nvmem-cell-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ audio-codec@2030000 { ++ compatible = "simple-mfd", "syscon"; ++ reg = <0x2030000 0x1000>; ++ ranges; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ regulators@2030348 { ++ compatible = "allwinner,sun20i-d1-analog-ldos"; ++ reg = <0x2030348 0x4>; ++ nvmem-cells = <&bg_trim>; ++ nvmem-cell-names = "bg_trim"; ++ ++ reg_aldo: aldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ reg_hpldo: hpldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ }; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/regulator/allwinner,sun20i-d1-system-ldos.yaml +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/regulator/allwinner,sun20i-d1-system-ldos.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Allwinner D1 System LDOs ++ ++maintainers: ++ - Samuel Holland <samuel@sholland.org> ++ ++description: ++ Allwinner D1 contains a pair of general-purpose LDOs which are designed to ++ supply power inside and outside the SoC. They are controlled by a register ++ within the system control MMIO space. ++ ++properties: ++ compatible: ++ enum: ++ - allwinner,sun20i-d1-system-ldos ++ ++ reg: ++ maxItems: 1 ++ ++patternProperties: ++ "^ldo[ab]$": ++ type: object ++ $ref: regulator.yaml# ++ unevaluatedProperties: false ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++... diff --git a/target/linux/d1/patches-6.1/0021-regulator-sun20i-Add-support-for-Allwinner-D1-LDOs.patch b/target/linux/d1/patches-6.1/0021-regulator-sun20i-Add-support-for-Allwinner-D1-LDOs.patch new file mode 100644 index 0000000000..7a5b2a0e74 --- /dev/null +++ b/target/linux/d1/patches-6.1/0021-regulator-sun20i-Add-support-for-Allwinner-D1-LDOs.patch @@ -0,0 +1,294 @@ +From ad842bfb2eb10a75050dd69145ca59de982eb0e9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 17 Jul 2022 11:46:52 -0500 +Subject: [PATCH 021/117] regulator: sun20i: Add support for Allwinner D1 LDOs + +D1 contains two pairs of LDOs. Since they have similar bindings, and +they always exist together, put them in a single driver. + +The analog LDOs are relatively boring, with a single linear range. Their +one quirk is that a bandgap reference must be calibrated for them to +produce the correct voltage. + +The system LDOs have the complication that their voltage step is not an +integer, so a custom .list_voltage is needed to get the rounding right. + +Series-changes: 2 + - Use decimal numbers for .n_voltages instead of field widths + - Get the regmap from the parent device instead of a property/phandle + +Series-changes: 3 + - Adjust control flow in sun20i_regulator_get_regmap() for clarity + +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Tested-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/regulator/Kconfig | 8 + + drivers/regulator/Makefile | 1 + + drivers/regulator/sun20i-regulator.c | 232 +++++++++++++++++++++++++++ + 3 files changed, 241 insertions(+) + create mode 100644 drivers/regulator/sun20i-regulator.c + +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -1280,6 +1280,14 @@ config REGULATOR_STW481X_VMMC + This driver supports the internal VMMC regulator in the STw481x + PMIC chips. + ++config REGULATOR_SUN20I ++ tristate "Allwinner D1 internal LDOs" ++ depends on ARCH_SUNXI || COMPILE_TEST ++ depends on MFD_SYSCON && NVMEM ++ default ARCH_SUNXI ++ help ++ This driver supports the internal LDOs in the Allwinner D1 SoC. ++ + config REGULATOR_SY7636A + tristate "Silergy SY7636A voltage regulator" + depends on MFD_SY7636A +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -150,6 +150,7 @@ obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += + obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o + obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o + obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o ++obj-$(CONFIG_REGULATOR_SUN20I) += sun20i-regulator.o + obj-$(CONFIG_REGULATOR_SY7636A) += sy7636a-regulator.o + obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o + obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o +--- /dev/null ++++ b/drivers/regulator/sun20i-regulator.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// ++// Copyright (c) 2021-2022 Samuel Holland <samuel@sholland.org> ++// ++ ++#include <linux/mfd/syscon.h> ++#include <linux/module.h> ++#include <linux/nvmem-consumer.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/regulator/driver.h> ++ ++#define SUN20I_POWER_REG 0x348 ++ ++#define SUN20I_SYS_LDO_CTRL_REG 0x150 ++ ++struct sun20i_regulator_data { ++ int (*init)(struct device *dev, ++ struct regmap *regmap); ++ const struct regulator_desc *descs; ++ unsigned int ndescs; ++}; ++ ++static int sun20i_d1_analog_ldos_init(struct device *dev, struct regmap *regmap) ++{ ++ u8 bg_trim; ++ int ret; ++ ++ ret = nvmem_cell_read_u8(dev, "bg_trim", &bg_trim); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to get bg_trim value\n"); ++ ++ /* The default value corresponds to 900 mV. */ ++ if (!bg_trim) ++ bg_trim = 0x19; ++ ++ return regmap_update_bits(regmap, SUN20I_POWER_REG, ++ GENMASK(7, 0), bg_trim); ++} ++ ++static const struct regulator_ops sun20i_d1_analog_ldo_ops = { ++ .list_voltage = regulator_list_voltage_linear, ++ .map_voltage = regulator_map_voltage_linear, ++ .set_voltage_sel = regulator_set_voltage_sel_regmap, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++}; ++ ++static const struct regulator_desc sun20i_d1_analog_ldo_descs[] = { ++ { ++ .name = "aldo", ++ .supply_name = "vdd33", ++ .of_match = "aldo", ++ .ops = &sun20i_d1_analog_ldo_ops, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .n_voltages = 8, ++ .min_uV = 1650000, ++ .uV_step = 50000, ++ .vsel_reg = SUN20I_POWER_REG, ++ .vsel_mask = GENMASK(14, 12), ++ .enable_reg = SUN20I_POWER_REG, ++ .enable_mask = BIT(31), ++ }, ++ { ++ .name = "hpldo", ++ .supply_name = "hpldoin", ++ .of_match = "hpldo", ++ .ops = &sun20i_d1_analog_ldo_ops, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .n_voltages = 8, ++ .min_uV = 1650000, ++ .uV_step = 50000, ++ .vsel_reg = SUN20I_POWER_REG, ++ .vsel_mask = GENMASK(10, 8), ++ .enable_reg = SUN20I_POWER_REG, ++ .enable_mask = BIT(30), ++ }, ++}; ++ ++static const struct sun20i_regulator_data sun20i_d1_analog_ldos = { ++ .init = sun20i_d1_analog_ldos_init, ++ .descs = sun20i_d1_analog_ldo_descs, ++ .ndescs = ARRAY_SIZE(sun20i_d1_analog_ldo_descs), ++}; ++ ++/* regulator_list_voltage_linear() modified for the non-integral uV_step. */ ++static int sun20i_d1_system_ldo_list_voltage(struct regulator_dev *rdev, ++ unsigned int selector) ++{ ++ const struct regulator_desc *desc = rdev->desc; ++ unsigned int uV; ++ ++ if (selector >= desc->n_voltages) ++ return -EINVAL; ++ ++ uV = desc->min_uV + (desc->uV_step * selector); ++ ++ /* Produce correctly-rounded absolute voltages. */ ++ return uV + ((selector + 1 + (desc->min_uV % 4)) / 3); ++} ++ ++static const struct regulator_ops sun20i_d1_system_ldo_ops = { ++ .list_voltage = sun20i_d1_system_ldo_list_voltage, ++ .map_voltage = regulator_map_voltage_ascend, ++ .set_voltage_sel = regulator_set_voltage_sel_regmap, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++}; ++ ++static const struct regulator_desc sun20i_d1_system_ldo_descs[] = { ++ { ++ .name = "ldoa", ++ .supply_name = "ldo-in", ++ .of_match = "ldoa", ++ .ops = &sun20i_d1_system_ldo_ops, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .n_voltages = 32, ++ .min_uV = 1600000, ++ .uV_step = 13333, /* repeating */ ++ .vsel_reg = SUN20I_SYS_LDO_CTRL_REG, ++ .vsel_mask = GENMASK(7, 0), ++ }, ++ { ++ .name = "ldob", ++ .supply_name = "ldo-in", ++ .of_match = "ldob", ++ .ops = &sun20i_d1_system_ldo_ops, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .n_voltages = 64, ++ .min_uV = 1166666, ++ .uV_step = 13333, /* repeating */ ++ .vsel_reg = SUN20I_SYS_LDO_CTRL_REG, ++ .vsel_mask = GENMASK(15, 8), ++ }, ++}; ++ ++static const struct sun20i_regulator_data sun20i_d1_system_ldos = { ++ .descs = sun20i_d1_system_ldo_descs, ++ .ndescs = ARRAY_SIZE(sun20i_d1_system_ldo_descs), ++}; ++ ++static const struct of_device_id sun20i_regulator_of_match[] = { ++ { ++ .compatible = "allwinner,sun20i-d1-analog-ldos", ++ .data = &sun20i_d1_analog_ldos, ++ }, ++ { ++ .compatible = "allwinner,sun20i-d1-system-ldos", ++ .data = &sun20i_d1_system_ldos, ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sun20i_regulator_of_match); ++ ++static struct regmap *sun20i_regulator_get_regmap(struct device *dev) ++{ ++ struct regmap *regmap; ++ ++ /* ++ * First try the syscon interface. The system control device is not ++ * compatible with "syscon", so fall back to getting the regmap from ++ * its platform device. This is ugly, but required for devicetree ++ * backward compatibility. ++ */ ++ regmap = syscon_node_to_regmap(dev->parent->of_node); ++ if (!IS_ERR(regmap)) ++ return regmap; ++ ++ regmap = dev_get_regmap(dev->parent, NULL); ++ if (regmap) ++ return regmap; ++ ++ return ERR_PTR(-EPROBE_DEFER); ++} ++ ++static int sun20i_regulator_probe(struct platform_device *pdev) ++{ ++ const struct sun20i_regulator_data *data; ++ struct device *dev = &pdev->dev; ++ struct regulator_config config; ++ struct regmap *regmap; ++ int ret; ++ ++ data = of_device_get_match_data(dev); ++ if (!data) ++ return -EINVAL; ++ ++ regmap = sun20i_regulator_get_regmap(dev); ++ if (IS_ERR(regmap)) ++ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to get regmap\n"); ++ ++ if (data->init) { ++ ret = data->init(dev, regmap); ++ if (ret) ++ return ret; ++ } ++ ++ config = (struct regulator_config) { ++ .dev = dev, ++ .regmap = regmap, ++ }; ++ ++ for (unsigned int i = 0; i < data->ndescs; ++i) { ++ const struct regulator_desc *desc = &data->descs[i]; ++ struct regulator_dev *rdev; ++ ++ rdev = devm_regulator_register(dev, desc, &config); ++ if (IS_ERR(rdev)) ++ return PTR_ERR(rdev); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver sun20i_regulator_driver = { ++ .probe = sun20i_regulator_probe, ++ .driver = { ++ .name = "sun20i-regulator", ++ .of_match_table = sun20i_regulator_of_match, ++ }, ++}; ++module_platform_driver(sun20i_regulator_driver); ++ ++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); ++MODULE_DESCRIPTION("Allwinner D1 internal LDO driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/d1/patches-6.1/0022-dt-bindings-sram-sunxi-sram-Add-optional-regulators-.patch b/target/linux/d1/patches-6.1/0022-dt-bindings-sram-sunxi-sram-Add-optional-regulators-.patch new file mode 100644 index 0000000000..9e24a75927 --- /dev/null +++ b/target/linux/d1/patches-6.1/0022-dt-bindings-sram-sunxi-sram-Add-optional-regulators-.patch @@ -0,0 +1,68 @@ +From 52c6979628d596018e9259767bff4def25e449dc Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Mon, 1 Aug 2022 23:57:19 -0500 +Subject: [PATCH 022/117] dt-bindings: sram: sunxi-sram: Add optional + regulators child + +Some sunxi SoCs have in-package regulators controlled by a register in +the system control MMIO block. Allow a child node for these regulators +in addition to SRAM child nodes. + +Commit-changes: 2 + - New patch for v2 + +Series-changes: 3 + - Require the regulators node to have a unit address + - Reference the regulator schema from the SRAM controller schema + - Move the system LDOs example to the SRAM controller schema + - Reorder the patches so the example passes validation + +Series-changes: 4 + - Remove unevaluatedProperties from regulators schema reference + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../allwinner,sun4i-a10-system-control.yaml | 28 +++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml ++++ b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml +@@ -56,6 +56,9 @@ properties: + ranges: true + + patternProperties: ++ "^regulators@[0-9a-f]+$": ++ $ref: /schemas/regulator/allwinner,sun20i-d1-system-ldos.yaml# ++ + "^sram@[a-z0-9]+": + type: object + +@@ -130,3 +133,28 @@ examples: + }; + }; + }; ++ ++ - | ++ syscon@3000000 { ++ compatible = "allwinner,sun20i-d1-system-control"; ++ reg = <0x3000000 0x1000>; ++ ranges; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ regulators@3000150 { ++ compatible = "allwinner,sun20i-d1-system-ldos"; ++ reg = <0x3000150 0x4>; ++ ++ reg_ldoa: ldoa { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ reg_ldob: ldob { ++ regulator-name = "vcc-dram"; ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ }; ++ }; ++ }; diff --git a/target/linux/d1/patches-6.1/0023-soc-sunxi-sram-Only-iterate-over-SRAM-children.patch b/target/linux/d1/patches-6.1/0023-soc-sunxi-sram-Only-iterate-over-SRAM-children.patch new file mode 100644 index 0000000000..4544cb3c38 --- /dev/null +++ b/target/linux/d1/patches-6.1/0023-soc-sunxi-sram-Only-iterate-over-SRAM-children.patch @@ -0,0 +1,50 @@ +From 1946ff7ee38c994ae3eb9968c5b51695c0df2cf7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 2 Aug 2022 00:01:21 -0500 +Subject: [PATCH 023/117] soc: sunxi: sram: Only iterate over SRAM children + +Now that a "regulators" child is accepted by the controller binding, the +debugfs show routine must be explicitly limited to "sram" children. + +Series-to: Liam Girdwood <lgirdwood@gmail.com> +Series-to: Mark Brown <broonie@kernel.org> +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> +Series-to: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org> +Series-to: Rob Herring <robh+dt@kernel.org> + +Commit-changes: 2 + - New patch for v2 + +Series-version: 4 + +Cover-letter: +regulator: Add support for Allwinner D1 LDOs +This series adds bindings and a driver for the two pairs of LDOs +inside the Allwinner D1 SoC. + +A binding and driver change is required for the SRAM controller, to +accept the regulators device as its child node. The new example in the +SRAM controller binding uses the compatible string added in this series: +https://lore.kernel.org/lkml/20220815041248.53268-1-samuel@sholland.org/ +END + +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Tested-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/soc/sunxi/sunxi_sram.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/soc/sunxi/sunxi_sram.c ++++ b/drivers/soc/sunxi/sunxi_sram.c +@@ -120,6 +120,9 @@ static int sunxi_sram_show(struct seq_fi + seq_puts(s, "--------------------\n\n"); + + for_each_child_of_node(sram_dev->of_node, sram_node) { ++ if (!of_node_name_eq(sram_node, "sram")) ++ continue; ++ + sram_addr_p = of_get_address(sram_node, 0, NULL, NULL); + + seq_printf(s, "sram@%08x\n", diff --git a/target/linux/d1/patches-6.1/0024-MAINTAINERS-Match-the-sun20i-family-of-Allwinner-SoC.patch b/target/linux/d1/patches-6.1/0024-MAINTAINERS-Match-the-sun20i-family-of-Allwinner-SoC.patch new file mode 100644 index 0000000000..442e9865b6 --- /dev/null +++ b/target/linux/d1/patches-6.1/0024-MAINTAINERS-Match-the-sun20i-family-of-Allwinner-SoC.patch @@ -0,0 +1,26 @@ +From 25727569379b42593b55cfb743b7eff4cfa1cce2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Aug 2022 23:45:50 -0500 +Subject: [PATCH 024/117] MAINTAINERS: Match the sun20i family of Allwinner + SoCs + +Allwinner sunxi SoCs with a RISC-V CPU use the sun20i designator. Match +that pattern in addition to the designators for 32 and 64-bit ARM SoCs. + +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + MAINTAINERS | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1828,7 +1828,7 @@ F: drivers/pinctrl/sunxi/ + F: drivers/soc/sunxi/ + N: allwinner + N: sun[x456789]i +-N: sun50i ++N: sun[25]0i + + ARM/Amlogic Meson SoC CLOCK FRAMEWORK + M: Neil Armstrong <neil.armstrong@linaro.org> diff --git a/target/linux/d1/patches-6.1/0025-dt-bindings-riscv-Add-T-HEAD-C906-and-C910-compatibl.patch b/target/linux/d1/patches-6.1/0025-dt-bindings-riscv-Add-T-HEAD-C906-and-C910-compatibl.patch new file mode 100644 index 0000000000..357cc1e419 --- /dev/null +++ b/target/linux/d1/patches-6.1/0025-dt-bindings-riscv-Add-T-HEAD-C906-and-C910-compatibl.patch @@ -0,0 +1,27 @@ +From 4ae663dbc373f5690581cee16d3667693eb9d73e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 16 May 2021 14:05:17 -0500 +Subject: [PATCH 025/117] dt-bindings: riscv: Add T-HEAD C906 and C910 + compatibles + +The C906 and C910 are RISC-V CPU cores from T-HEAD Semiconductor. +Notably, the C906 core is used in the Allwinner D1 SoC. + +Acked-by: Rob Herring <robh@kernel.org> +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + Documentation/devicetree/bindings/riscv/cpus.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/riscv/cpus.yaml ++++ b/Documentation/devicetree/bindings/riscv/cpus.yaml +@@ -39,6 +39,8 @@ properties: + - sifive,u5 + - sifive,u7 + - canaan,k210 ++ - thead,c906 ++ - thead,c910 + - const: riscv + - items: + - enum: diff --git a/target/linux/d1/patches-6.1/0026-dt-bindings-vendor-prefixes-Add-Allwinner-D1-board-v.patch b/target/linux/d1/patches-6.1/0026-dt-bindings-vendor-prefixes-Add-Allwinner-D1-board-v.patch new file mode 100644 index 0000000000..ca4d7c4295 --- /dev/null +++ b/target/linux/d1/patches-6.1/0026-dt-bindings-vendor-prefixes-Add-Allwinner-D1-board-v.patch @@ -0,0 +1,42 @@ +From d0c24deb787a95515d355eea68e0402bfec77f75 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 17 Jul 2022 14:42:05 -0500 +Subject: [PATCH 026/117] dt-bindings: vendor-prefixes: Add Allwinner D1 board + vendors + +Some boards using the Allwinner D1 SoC are made by vendors not +previously documented. + +Clockwork Tech LLC (https://www.clockworkpi.com/) manufactures the +ClockworkPi and DevTerm boards. + +Beijing Widora Technology Co., Ltd. (https://mangopi.cc/) manufactures +the MangoPi family of boards. + +Acked-by: Rob Herring <robh@kernel.org> +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + Documentation/devicetree/bindings/vendor-prefixes.yaml | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -260,6 +260,8 @@ patternProperties: + description: Cirrus Logic, Inc. + "^cisco,.*": + description: Cisco Systems, Inc. ++ "^clockwork,.*": ++ description: Clockwork Tech LLC + "^cloudengines,.*": + description: Cloud Engines, Inc. + "^cnm,.*": +@@ -1424,6 +1426,8 @@ patternProperties: + description: Shenzhen whwave Electronics, Inc. + "^wi2wi,.*": + description: Wi2Wi, Inc. ++ "^widora,.*": ++ description: Beijing Widora Technology Co., Ltd. + "^wiligear,.*": + description: Wiligear, Ltd. + "^willsemi,.*": diff --git a/target/linux/d1/patches-6.1/0027-dt-bindings-riscv-Add-Allwinner-D1-board-compatibles.patch b/target/linux/d1/patches-6.1/0027-dt-bindings-riscv-Add-Allwinner-D1-board-compatibles.patch new file mode 100644 index 0000000000..6fd802e68b --- /dev/null +++ b/target/linux/d1/patches-6.1/0027-dt-bindings-riscv-Add-Allwinner-D1-board-compatibles.patch @@ -0,0 +1,85 @@ +From 4d7c04f210dd401f3560a7f53c78d6e058d182e2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 29 Jun 2022 00:26:39 -0500 +Subject: [PATCH 027/117] dt-bindings: riscv: Add Allwinner D1 board + compatibles + +Several SoMs and boards are available that feature the Allwinner D1 SoC. +Document their compatible strings. + +Acked-by: Rob Herring <robh@kernel.org> +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Tested-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../devicetree/bindings/riscv/sunxi.yaml | 64 +++++++++++++++++++ + 1 file changed, 64 insertions(+) + create mode 100644 Documentation/devicetree/bindings/riscv/sunxi.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/riscv/sunxi.yaml +@@ -0,0 +1,64 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/riscv/sunxi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Allwinner RISC-V SoC-based boards ++ ++maintainers: ++ - Chen-Yu Tsai <wens@csie.org> ++ - Jernej Skrabec <jernej.skrabec@gmail.com> ++ - Samuel Holland <samuel@sholland.org> ++ ++description: ++ Allwinner RISC-V SoC-based boards ++ ++properties: ++ $nodename: ++ const: '/' ++ compatible: ++ oneOf: ++ - description: Dongshan Nezha STU SoM ++ items: ++ - const: 100ask,dongshan-nezha-stu ++ - const: allwinner,sun20i-d1 ++ ++ - description: D1 Nezha board ++ items: ++ - const: allwinner,d1-nezha ++ - const: allwinner,sun20i-d1 ++ ++ - description: ClockworkPi R-01 SoM and v3.14 board ++ items: ++ - const: clockwork,r-01-clockworkpi-v3.14 ++ - const: allwinner,sun20i-d1 ++ ++ - description: ClockworkPi R-01 SoM, v3.14 board, and DevTerm expansion ++ items: ++ - const: clockwork,r-01-devterm-v3.14 ++ - const: clockwork,r-01-clockworkpi-v3.14 ++ - const: allwinner,sun20i-d1 ++ ++ - description: Lichee RV SoM ++ items: ++ - const: sipeed,lichee-rv ++ - const: allwinner,sun20i-d1 ++ ++ - description: Carrier boards for the Lichee RV SoM ++ items: ++ - enum: ++ - sipeed,lichee-rv-86-panel-480p ++ - sipeed,lichee-rv-86-panel-720p ++ - sipeed,lichee-rv-dock ++ - const: sipeed,lichee-rv ++ - const: allwinner,sun20i-d1 ++ ++ - description: MangoPi MQ Pro board ++ items: ++ - const: widora,mangopi-mq-pro ++ - const: allwinner,sun20i-d1 ++ ++additionalProperties: true ++ ++... diff --git a/target/linux/d1/patches-6.1/0028-riscv-dts-allwinner-Add-the-D1-SoC-base-devicetree.patch b/target/linux/d1/patches-6.1/0028-riscv-dts-allwinner-Add-the-D1-SoC-base-devicetree.patch new file mode 100644 index 0000000000..6f41449594 --- /dev/null +++ b/target/linux/d1/patches-6.1/0028-riscv-dts-allwinner-Add-the-D1-SoC-base-devicetree.patch @@ -0,0 +1,936 @@ +From 20d565fb9324b0d2791d10cb65560eddd2ef526e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 28 Jun 2022 23:20:33 -0500 +Subject: [PATCH 028/117] riscv: dts: allwinner: Add the D1 SoC base devicetree + +D1 is a SoC containing a single-core T-HEAD Xuantie C906 CPU, as well as +one HiFi 4 DSP. The SoC is based on a design that additionally contained +a pair of Cortex A7's. For that reason, some peripherals are duplicated. + +This devicetree includes all of the peripherals that already have a +documented binding. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/Makefile | 1 + + arch/riscv/boot/dts/allwinner/Makefile | 1 + + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 900 +++++++++++++++++++ + 3 files changed, 902 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/Makefile + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi + +--- a/arch/riscv/boot/dts/Makefile ++++ b/arch/riscv/boot/dts/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++subdir-y += allwinner + subdir-y += sifive + subdir-y += starfive + subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -0,0 +1 @@ ++# SPDX-License-Identifier: GPL-2.0 +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -0,0 +1,900 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org> ++ ++#include <dt-bindings/clock/sun6i-rtc.h> ++#include <dt-bindings/clock/sun8i-de2.h> ++#include <dt-bindings/clock/sun8i-tcon-top.h> ++#include <dt-bindings/clock/sun20i-d1-ccu.h> ++#include <dt-bindings/clock/sun20i-d1-r-ccu.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/reset/sun8i-de2.h> ++#include <dt-bindings/reset/sun20i-d1-ccu.h> ++#include <dt-bindings/reset/sun20i-d1-r-ccu.h> ++#include <dt-bindings/thermal/thermal.h> ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ cpus { ++ timebase-frequency = <24000000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "thead,c906", "riscv"; ++ device_type = "cpu"; ++ reg = <0>; ++ clocks = <&ccu CLK_RISCV>; ++ clock-frequency = <24000000>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <256>; ++ d-cache-size = <32768>; ++ i-cache-block-size = <64>; ++ i-cache-sets = <128>; ++ i-cache-size = <32768>; ++ mmu-type = "riscv,sv39"; ++ riscv,isa = "rv64imafdc"; ++ #cooling-cells = <2>; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ }; ++ ++ de: display-engine { ++ compatible = "allwinner,sun20i-d1-display-engine"; ++ allwinner,pipelines = <&mixer0>, <&mixer1>; ++ status = "disabled"; ++ }; ++ ++ osc24M: osc24M-clk { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ clock-output-names = "osc24M"; ++ #clock-cells = <0>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ ranges; ++ interrupt-parent = <&plic>; ++ dma-noncoherent; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ dsp_wdt: watchdog@1700400 { ++ compatible = "allwinner,sun20i-d1-wdt"; ++ reg = <0x1700400 0x20>; ++ interrupts = <138 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc24M>, <&rtc CLK_OSC32K>; ++ clock-names = "hosc", "losc"; ++ status = "reserved"; ++ }; ++ ++ pio: pinctrl@2000000 { ++ compatible = "allwinner,sun20i-d1-pinctrl"; ++ reg = <0x2000000 0x800>; ++ interrupts = <85 IRQ_TYPE_LEVEL_HIGH>, ++ <87 IRQ_TYPE_LEVEL_HIGH>, ++ <89 IRQ_TYPE_LEVEL_HIGH>, ++ <91 IRQ_TYPE_LEVEL_HIGH>, ++ <93 IRQ_TYPE_LEVEL_HIGH>, ++ <95 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_APB0>, ++ <&osc24M>, ++ <&rtc CLK_OSC32K>; ++ clock-names = "apb", "hosc", "losc"; ++ gpio-controller; ++ interrupt-controller; ++ #gpio-cells = <3>; ++ #interrupt-cells = <3>; ++ ++ /omit-if-no-ref/ ++ i2c0_pb10_pins: i2c0-pb10-pins { ++ pins = "PB10", "PB11"; ++ function = "i2c0"; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c2_pb0_pins: i2c2-pb0-pins { ++ pins = "PB0", "PB1"; ++ function = "i2c2"; ++ }; ++ ++ /omit-if-no-ref/ ++ lcd_rgb666_pins: lcd-rgb666-pins { ++ pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5", ++ "PD6", "PD7", "PD8", "PD9", "PD10", "PD11", ++ "PD12", "PD13", "PD14", "PD15", "PD16", "PD17", ++ "PD18", "PD19", "PD20", "PD21"; ++ function = "lcd0"; ++ }; ++ ++ /omit-if-no-ref/ ++ mmc0_pins: mmc0-pins { ++ pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; ++ function = "mmc0"; ++ }; ++ ++ /omit-if-no-ref/ ++ mmc1_pins: mmc1-pins { ++ pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5"; ++ function = "mmc1"; ++ }; ++ ++ /omit-if-no-ref/ ++ mmc2_pins: mmc2-pins { ++ pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7"; ++ function = "mmc2"; ++ }; ++ ++ /omit-if-no-ref/ ++ rgmii_pe_pins: rgmii-pe-pins { ++ pins = "PE0", "PE1", "PE2", "PE3", "PE4", ++ "PE5", "PE6", "PE7", "PE8", "PE9", ++ "PE11", "PE12", "PE13", "PE14", "PE15"; ++ function = "emac"; ++ }; ++ ++ /omit-if-no-ref/ ++ rmii_pe_pins: rmii-pe-pins { ++ pins = "PE0", "PE1", "PE2", "PE3", "PE4", ++ "PE5", "PE6", "PE7", "PE8", "PE9"; ++ function = "emac"; ++ }; ++ ++ /omit-if-no-ref/ ++ uart0_pb8_pins: uart0-pb8-pins { ++ pins = "PB8", "PB9"; ++ function = "uart0"; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1_pg6_pins: uart1-pg6-pins { ++ pins = "PG6", "PG7"; ++ function = "uart1"; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1_pg8_rts_cts_pins: uart1-pg8-rts-cts-pins { ++ pins = "PG8", "PG9"; ++ function = "uart1"; ++ }; ++ }; ++ ++ ccu: clock-controller@2001000 { ++ compatible = "allwinner,sun20i-d1-ccu"; ++ reg = <0x2001000 0x1000>; ++ clocks = <&osc24M>, ++ <&rtc CLK_OSC32K>, ++ <&rtc CLK_IOSC>; ++ clock-names = "hosc", "losc", "iosc"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ lradc: keys@2009800 { ++ compatible = "allwinner,sun20i-d1-lradc", ++ "allwinner,sun50i-r329-lradc"; ++ reg = <0x2009800 0x400>; ++ interrupts = <77 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_LRADC>; ++ resets = <&ccu RST_BUS_LRADC>; ++ status = "disabled"; ++ }; ++ ++ codec: audio-codec@2030000 { ++ compatible = "simple-mfd", "syscon"; ++ reg = <0x2030000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ regulators@2030348 { ++ compatible = "allwinner,sun20i-d1-analog-ldos"; ++ reg = <0x2030348 0x4>; ++ nvmem-cells = <&bg_trim>; ++ nvmem-cell-names = "bg_trim"; ++ ++ reg_aldo: aldo { ++ }; ++ ++ reg_hpldo: hpldo { ++ }; ++ }; ++ }; ++ ++ i2s0: i2s@2032000 { ++ compatible = "allwinner,sun20i-d1-i2s", ++ "allwinner,sun50i-r329-i2s"; ++ reg = <0x2032000 0x1000>; ++ interrupts = <42 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2S0>, ++ <&ccu CLK_I2S0>; ++ clock-names = "apb", "mod"; ++ resets = <&ccu RST_BUS_I2S0>; ++ dmas = <&dma 3>, <&dma 3>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ i2s1: i2s@2033000 { ++ compatible = "allwinner,sun20i-d1-i2s", ++ "allwinner,sun50i-r329-i2s"; ++ reg = <0x2033000 0x1000>; ++ interrupts = <43 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2S1>, ++ <&ccu CLK_I2S1>; ++ clock-names = "apb", "mod"; ++ resets = <&ccu RST_BUS_I2S1>; ++ dmas = <&dma 4>, <&dma 4>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ i2s2: i2s@2034000 { ++ compatible = "allwinner,sun20i-d1-i2s", ++ "allwinner,sun50i-r329-i2s"; ++ reg = <0x2034000 0x1000>; ++ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2S2>, ++ <&ccu CLK_I2S2>; ++ clock-names = "apb", "mod"; ++ resets = <&ccu RST_BUS_I2S2>; ++ dmas = <&dma 5>, <&dma 5>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #sound-dai-cells = <0>; ++ }; ++ ++ timer: timer@2050000 { ++ compatible = "allwinner,sun20i-d1-timer", ++ "allwinner,sun8i-a23-timer"; ++ reg = <0x2050000 0xa0>; ++ interrupts = <75 IRQ_TYPE_LEVEL_HIGH>, ++ <76 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc24M>; ++ }; ++ ++ wdt: watchdog@20500a0 { ++ compatible = "allwinner,sun20i-d1-wdt-reset", ++ "allwinner,sun20i-d1-wdt"; ++ reg = <0x20500a0 0x20>; ++ interrupts = <79 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc24M>, <&rtc CLK_OSC32K>; ++ clock-names = "hosc", "losc"; ++ status = "reserved"; ++ }; ++ ++ uart0: serial@2500000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2500000 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART0>; ++ resets = <&ccu RST_BUS_UART0>; ++ dmas = <&dma 14>, <&dma 14>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@2500400 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2500400 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART1>; ++ resets = <&ccu RST_BUS_UART1>; ++ dmas = <&dma 15>, <&dma 15>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@2500800 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2500800 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART2>; ++ resets = <&ccu RST_BUS_UART2>; ++ dmas = <&dma 16>, <&dma 16>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@2500c00 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2500c00 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART3>; ++ resets = <&ccu RST_BUS_UART3>; ++ dmas = <&dma 17>, <&dma 17>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@2501000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2501000 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART4>; ++ resets = <&ccu RST_BUS_UART4>; ++ dmas = <&dma 18>, <&dma 18>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@2501400 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x2501400 0x400>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_UART5>; ++ resets = <&ccu RST_BUS_UART5>; ++ dmas = <&dma 19>, <&dma 19>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@2502000 { ++ compatible = "allwinner,sun20i-d1-i2c", ++ "allwinner,sun8i-v536-i2c", ++ "allwinner,sun6i-a31-i2c"; ++ reg = <0x2502000 0x400>; ++ interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2C0>; ++ resets = <&ccu RST_BUS_I2C0>; ++ dmas = <&dma 43>, <&dma 43>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c1: i2c@2502400 { ++ compatible = "allwinner,sun20i-d1-i2c", ++ "allwinner,sun8i-v536-i2c", ++ "allwinner,sun6i-a31-i2c"; ++ reg = <0x2502400 0x400>; ++ interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2C1>; ++ resets = <&ccu RST_BUS_I2C1>; ++ dmas = <&dma 44>, <&dma 44>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c2: i2c@2502800 { ++ compatible = "allwinner,sun20i-d1-i2c", ++ "allwinner,sun8i-v536-i2c", ++ "allwinner,sun6i-a31-i2c"; ++ reg = <0x2502800 0x400>; ++ interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2C2>; ++ resets = <&ccu RST_BUS_I2C2>; ++ dmas = <&dma 45>, <&dma 45>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c3: i2c@2502c00 { ++ compatible = "allwinner,sun20i-d1-i2c", ++ "allwinner,sun8i-v536-i2c", ++ "allwinner,sun6i-a31-i2c"; ++ reg = <0x2502c00 0x400>; ++ interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_I2C3>; ++ resets = <&ccu RST_BUS_I2C3>; ++ dmas = <&dma 46>, <&dma 46>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ syscon: syscon@3000000 { ++ compatible = "allwinner,sun20i-d1-system-control"; ++ reg = <0x3000000 0x1000>; ++ ranges; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ regulators@3000150 { ++ compatible = "allwinner,sun20i-d1-system-ldos"; ++ reg = <0x3000150 0x4>; ++ ++ reg_ldoa: ldoa { ++ }; ++ ++ reg_ldob: ldob { ++ }; ++ }; ++ }; ++ ++ dma: dma-controller@3002000 { ++ compatible = "allwinner,sun20i-d1-dma"; ++ reg = <0x3002000 0x1000>; ++ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>; ++ clock-names = "bus", "mbus"; ++ resets = <&ccu RST_BUS_DMA>; ++ dma-channels = <16>; ++ dma-requests = <48>; ++ #dma-cells = <1>; ++ }; ++ ++ sid: efuse@3006000 { ++ compatible = "allwinner,sun20i-d1-sid"; ++ reg = <0x3006000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ths_calib: ths-calib@14 { ++ reg = <0x14 0x4>; ++ }; ++ ++ bg_trim: bg-trim@28 { ++ reg = <0x28 0x4>; ++ bits = <16 8>; ++ }; ++ }; ++ ++ mbus: dram-controller@3102000 { ++ compatible = "allwinner,sun20i-d1-mbus"; ++ reg = <0x3102000 0x1000>, ++ <0x3103000 0x1000>; ++ reg-names = "mbus", "dram"; ++ interrupts = <59 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_MBUS>, ++ <&ccu CLK_DRAM>, ++ <&ccu CLK_BUS_DRAM>; ++ clock-names = "mbus", "dram", "bus"; ++ dma-ranges = <0 0x40000000 0x80000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ #interconnect-cells = <1>; ++ }; ++ ++ mmc0: mmc@4020000 { ++ compatible = "allwinner,sun20i-d1-mmc"; ++ reg = <0x4020000 0x1000>; ++ interrupts = <56 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>; ++ clock-names = "ahb", "mmc"; ++ resets = <&ccu RST_BUS_MMC0>; ++ reset-names = "ahb"; ++ cap-sd-highspeed; ++ max-frequency = <150000000>; ++ no-mmc; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ mmc1: mmc@4021000 { ++ compatible = "allwinner,sun20i-d1-mmc"; ++ reg = <0x4021000 0x1000>; ++ interrupts = <57 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>; ++ clock-names = "ahb", "mmc"; ++ resets = <&ccu RST_BUS_MMC1>; ++ reset-names = "ahb"; ++ cap-sd-highspeed; ++ max-frequency = <150000000>; ++ no-mmc; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ mmc2: mmc@4022000 { ++ compatible = "allwinner,sun20i-d1-emmc", ++ "allwinner,sun50i-a100-emmc"; ++ reg = <0x4022000 0x1000>; ++ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>; ++ clock-names = "ahb", "mmc"; ++ resets = <&ccu RST_BUS_MMC2>; ++ reset-names = "ahb"; ++ cap-mmc-highspeed; ++ max-frequency = <150000000>; ++ mmc-ddr-1_8v; ++ mmc-ddr-3_3v; ++ no-sd; ++ no-sdio; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ usb_otg: usb@4100000 { ++ compatible = "allwinner,sun20i-d1-musb", ++ "allwinner,sun8i-a33-musb"; ++ reg = <0x4100000 0x400>; ++ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "mc"; ++ clocks = <&ccu CLK_BUS_OTG>; ++ resets = <&ccu RST_BUS_OTG>; ++ extcon = <&usbphy 0>; ++ phys = <&usbphy 0>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ usbphy: phy@4100400 { ++ compatible = "allwinner,sun20i-d1-usb-phy"; ++ reg = <0x4100400 0x100>, ++ <0x4101800 0x100>, ++ <0x4200800 0x100>; ++ reg-names = "phy_ctrl", ++ "pmu0", ++ "pmu1"; ++ clocks = <&osc24M>, ++ <&osc24M>; ++ clock-names = "usb0_phy", ++ "usb1_phy"; ++ resets = <&ccu RST_USB_PHY0>, ++ <&ccu RST_USB_PHY1>; ++ reset-names = "usb0_reset", ++ "usb1_reset"; ++ status = "disabled"; ++ #phy-cells = <1>; ++ }; ++ ++ ehci0: usb@4101000 { ++ compatible = "allwinner,sun20i-d1-ehci", ++ "generic-ehci"; ++ reg = <0x4101000 0x100>; ++ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_OHCI0>, ++ <&ccu CLK_BUS_EHCI0>, ++ <&ccu CLK_USB_OHCI0>; ++ resets = <&ccu RST_BUS_OHCI0>, ++ <&ccu RST_BUS_EHCI0>; ++ phys = <&usbphy 0>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ ohci0: usb@4101400 { ++ compatible = "allwinner,sun20i-d1-ohci", ++ "generic-ohci"; ++ reg = <0x4101400 0x100>; ++ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_OHCI0>, ++ <&ccu CLK_USB_OHCI0>; ++ resets = <&ccu RST_BUS_OHCI0>; ++ phys = <&usbphy 0>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ ehci1: usb@4200000 { ++ compatible = "allwinner,sun20i-d1-ehci", ++ "generic-ehci"; ++ reg = <0x4200000 0x100>; ++ interrupts = <49 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_OHCI1>, ++ <&ccu CLK_BUS_EHCI1>, ++ <&ccu CLK_USB_OHCI1>; ++ resets = <&ccu RST_BUS_OHCI1>, ++ <&ccu RST_BUS_EHCI1>; ++ phys = <&usbphy 1>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ ohci1: usb@4200400 { ++ compatible = "allwinner,sun20i-d1-ohci", ++ "generic-ohci"; ++ reg = <0x4200400 0x100>; ++ interrupts = <50 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_OHCI1>, ++ <&ccu CLK_USB_OHCI1>; ++ resets = <&ccu RST_BUS_OHCI1>; ++ phys = <&usbphy 1>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; ++ ++ emac: ethernet@4500000 { ++ compatible = "allwinner,sun20i-d1-emac", ++ "allwinner,sun50i-a64-emac"; ++ reg = <0x4500000 0x10000>; ++ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq"; ++ clocks = <&ccu CLK_BUS_EMAC>; ++ clock-names = "stmmaceth"; ++ resets = <&ccu RST_BUS_EMAC>; ++ reset-names = "stmmaceth"; ++ syscon = <&syscon>; ++ status = "disabled"; ++ ++ mdio: mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ }; ++ ++ display_clocks: clock-controller@5000000 { ++ compatible = "allwinner,sun20i-d1-de2-clk", ++ "allwinner,sun50i-h5-de2-clk"; ++ reg = <0x5000000 0x10000>; ++ clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_DE>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ mixer0: mixer@5100000 { ++ compatible = "allwinner,sun20i-d1-de2-mixer-0"; ++ reg = <0x5100000 0x100000>; ++ clocks = <&display_clocks CLK_BUS_MIXER0>, ++ <&display_clocks CLK_MIXER0>; ++ clock-names = "bus", "mod"; ++ resets = <&display_clocks RST_MIXER0>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mixer0_out: port@1 { ++ reg = <1>; ++ ++ mixer0_out_tcon_top_mixer0: endpoint { ++ remote-endpoint = <&tcon_top_mixer0_in_mixer0>; ++ }; ++ }; ++ }; ++ }; ++ ++ mixer1: mixer@5200000 { ++ compatible = "allwinner,sun20i-d1-de2-mixer-1"; ++ reg = <0x5200000 0x100000>; ++ clocks = <&display_clocks CLK_BUS_MIXER1>, ++ <&display_clocks CLK_MIXER1>; ++ clock-names = "bus", "mod"; ++ resets = <&display_clocks RST_MIXER1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mixer1_out: port@1 { ++ reg = <1>; ++ ++ mixer1_out_tcon_top_mixer1: endpoint { ++ remote-endpoint = <&tcon_top_mixer1_in_mixer1>; ++ }; ++ }; ++ }; ++ }; ++ ++ tcon_top: tcon-top@5460000 { ++ compatible = "allwinner,sun20i-d1-tcon-top"; ++ reg = <0x5460000 0x1000>; ++ clocks = <&ccu CLK_BUS_DPSS_TOP>, ++ <&ccu CLK_TCON_TV>, ++ <&ccu CLK_TVE>, ++ <&ccu CLK_TCON_LCD0>; ++ clock-names = "bus", "tcon-tv0", "tve0", "dsi"; ++ clock-output-names = "tcon-top-tv0", "tcon-top-dsi"; ++ resets = <&ccu RST_BUS_DPSS_TOP>; ++ #clock-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_top_mixer0_in: port@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_top_mixer0_in_mixer0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&mixer0_out_tcon_top_mixer0>; ++ }; ++ }; ++ ++ tcon_top_mixer0_out: port@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_top_mixer0_out_tcon_lcd0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&tcon_lcd0_in_tcon_top_mixer0>; ++ }; ++ ++ tcon_top_mixer0_out_tcon_tv0: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&tcon_tv0_in_tcon_top_mixer0>; ++ }; ++ }; ++ ++ tcon_top_mixer1_in: port@2 { ++ reg = <2>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_top_mixer1_in_mixer1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&mixer1_out_tcon_top_mixer1>; ++ }; ++ }; ++ ++ tcon_top_mixer1_out: port@3 { ++ reg = <3>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_top_mixer1_out_tcon_lcd0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&tcon_lcd0_in_tcon_top_mixer1>; ++ }; ++ ++ tcon_top_mixer1_out_tcon_tv0: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&tcon_tv0_in_tcon_top_mixer1>; ++ }; ++ }; ++ ++ tcon_top_hdmi_in: port@4 { ++ reg = <4>; ++ ++ tcon_top_hdmi_in_tcon_tv0: endpoint { ++ remote-endpoint = <&tcon_tv0_out_tcon_top_hdmi>; ++ }; ++ }; ++ ++ tcon_top_hdmi_out: port@5 { ++ reg = <5>; ++ }; ++ }; ++ }; ++ ++ tcon_lcd0: lcd-controller@5461000 { ++ compatible = "allwinner,sun20i-d1-tcon-lcd"; ++ reg = <0x5461000 0x1000>; ++ interrupts = <106 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_TCON_LCD0>, ++ <&ccu CLK_TCON_LCD0>; ++ clock-names = "ahb", "tcon-ch0"; ++ clock-output-names = "tcon-pixel-clock"; ++ resets = <&ccu RST_BUS_TCON_LCD0>, ++ <&ccu RST_BUS_LVDS0>; ++ reset-names = "lcd", "lvds"; ++ #clock-cells = <0>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_lcd0_in: port@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_lcd0_in_tcon_top_mixer0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&tcon_top_mixer0_out_tcon_lcd0>; ++ }; ++ ++ tcon_lcd0_in_tcon_top_mixer1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&tcon_top_mixer1_out_tcon_lcd0>; ++ }; ++ }; ++ ++ tcon_lcd0_out: port@1 { ++ reg = <1>; ++ }; ++ }; ++ }; ++ ++ tcon_tv0: lcd-controller@5470000 { ++ compatible = "allwinner,sun20i-d1-tcon-tv"; ++ reg = <0x5470000 0x1000>; ++ interrupts = <107 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_TCON_TV>, ++ <&tcon_top CLK_TCON_TOP_TV0>; ++ clock-names = "ahb", "tcon-ch1"; ++ resets = <&ccu RST_BUS_TCON_TV>; ++ reset-names = "lcd"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_tv0_in: port@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_tv0_in_tcon_top_mixer0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&tcon_top_mixer0_out_tcon_tv0>; ++ }; ++ ++ tcon_tv0_in_tcon_top_mixer1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&tcon_top_mixer1_out_tcon_tv0>; ++ }; ++ }; ++ ++ tcon_tv0_out: port@1 { ++ reg = <1>; ++ ++ tcon_tv0_out_tcon_top_hdmi: endpoint { ++ remote-endpoint = <&tcon_top_hdmi_in_tcon_tv0>; ++ }; ++ }; ++ }; ++ }; ++ ++ riscv_wdt: watchdog@6011000 { ++ compatible = "allwinner,sun20i-d1-wdt"; ++ reg = <0x6011000 0x20>; ++ interrupts = <147 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc24M>, <&rtc CLK_OSC32K>; ++ clock-names = "hosc", "losc"; ++ }; ++ ++ r_ccu: clock-controller@7010000 { ++ compatible = "allwinner,sun20i-d1-r-ccu"; ++ reg = <0x7010000 0x400>; ++ clocks = <&osc24M>, ++ <&rtc CLK_OSC32K>, ++ <&rtc CLK_IOSC>, ++ <&ccu CLK_PLL_PERIPH0_DIV3>; ++ clock-names = "hosc", "losc", "iosc", "pll-periph"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ rtc: rtc@7090000 { ++ compatible = "allwinner,sun20i-d1-rtc", ++ "allwinner,sun50i-r329-rtc"; ++ reg = <0x7090000 0x400>; ++ interrupts = <160 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&r_ccu CLK_BUS_R_RTC>, ++ <&osc24M>, ++ <&r_ccu CLK_R_AHB>; ++ clock-names = "bus", "hosc", "ahb"; ++ #clock-cells = <1>; ++ }; ++ ++ plic: interrupt-controller@10000000 { ++ compatible = "allwinner,sun20i-d1-plic", ++ "thead,c900-plic"; ++ reg = <0x10000000 0x4000000>; ++ interrupts-extended = <&cpu0_intc 11>, ++ <&cpu0_intc 9>; ++ interrupt-controller; ++ riscv,ndev = <176>; ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ }; ++ }; ++}; diff --git a/target/linux/d1/patches-6.1/0029-riscv-dts-allwinner-Add-Allwinner-D1-Nezha-devicetre.patch b/target/linux/d1/patches-6.1/0029-riscv-dts-allwinner-Add-Allwinner-D1-Nezha-devicetre.patch new file mode 100644 index 0000000000..aadc3138d4 --- /dev/null +++ b/target/linux/d1/patches-6.1/0029-riscv-dts-allwinner-Add-Allwinner-D1-Nezha-devicetre.patch @@ -0,0 +1,263 @@ +From 5da27190c54b7a51062786eb01246f6f4cf2ba98 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 28 Jun 2022 23:31:16 -0500 +Subject: [PATCH 029/117] riscv: dts: allwinner: Add Allwinner D1 Nezha + devicetree + +"D1 Nezha" is Allwinner's first-party development board for the D1 SoC. +It was shipped with 512M, 1G, or 2G of DDR3. It supports onboard audio, +HDMI, gigabit Ethernet, WiFi and Bluetooth, USB 2.0 host and OTG ports, +plus low-speed I/O from the SoC and a GPIO expander chip. + +Most other D1 boards copied the Nezha's power tree, with the 1.8V rail +powered by the SoCs internal LDOA, analog domains powered by ALDO, and +the rest of the board powered by always-on fixed regulators. Some (but +not all) boards also copied the PWM CPU regulator. To avoid duplication, +factor out the out the regulator references that are common across all +known boards. + +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Tested-by: Conor Dooley <conor.dooley@microchip.com> +Tested-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/Makefile | 1 + + .../sun20i-d1-common-regulators.dtsi | 51 ++++++ + .../boot/dts/allwinner/sun20i-d1-nezha.dts | 171 ++++++++++++++++++ + 3 files changed, 223 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts + +--- a/arch/riscv/boot/dts/allwinner/Makefile ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -1 +1,2 @@ + # SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-nezha.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org> ++ ++/ { ++ reg_vcc: vcc { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ reg_vcc_3v3: vcc-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <®_vcc>; ++ }; ++}; ++ ++&lradc { ++ vref-supply = <®_aldo>; ++}; ++ ++&pio { ++ vcc-pb-supply = <®_vcc_3v3>; ++ vcc-pc-supply = <®_vcc_3v3>; ++ vcc-pd-supply = <®_vcc_3v3>; ++ vcc-pe-supply = <®_vcc_3v3>; ++ vcc-pf-supply = <®_vcc_3v3>; ++ vcc-pg-supply = <®_vcc_3v3>; ++}; ++ ++®_aldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vdd33-supply = <®_vcc_3v3>; ++}; ++ ++®_hpldo { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ hpldoin-supply = <®_vcc_3v3>; ++}; ++ ++®_ldoa { ++ regulator-always-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ ldo-in-supply = <®_vcc_3v3>; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts +@@ -0,0 +1,171 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/input/input.h> ++ ++#include "sun20i-d1.dtsi" ++#include "sun20i-d1-common-regulators.dtsi" ++ ++/ { ++ model = "Allwinner D1 Nezha"; ++ compatible = "allwinner,d1-nezha", "allwinner,sun20i-d1"; ++ ++ aliases { ++ ethernet0 = &emac; ++ ethernet1 = &xr829; ++ mmc0 = &mmc0; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reg_usbvbus: usbvbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usbvbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&pio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */ ++ enable-active-high; ++ vin-supply = <®_vcc>; ++ }; ++ ++ /* ++ * This regulator is PWM-controlled, but the PWM controller is not ++ * yet supported, so fix the regulator to its default voltage. ++ */ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-cpu"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1100000>; ++ vin-supply = <®_vcc>; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */ ++ }; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_vdd_cpu>; ++}; ++ ++&ehci0 { ++ status = "okay"; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&emac { ++ pinctrl-0 = <&rgmii_pe_pins>; ++ pinctrl-names = "default"; ++ phy-handle = <&ext_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ phy-supply = <®_vcc_3v3>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ pinctrl-0 = <&i2c2_pb0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ pcf8574a: gpio@38 { ++ compatible = "nxp,pcf8574a"; ++ reg = <0x38>; ++ interrupt-parent = <&pio>; ++ interrupts = <1 2 IRQ_TYPE_LEVEL_LOW>; /* PB2 */ ++ interrupt-controller; ++ gpio-controller; ++ #gpio-cells = <2>; ++ #interrupt-cells = <2>; ++ }; ++}; ++ ++&lradc { ++ status = "okay"; ++ ++ button-160 { ++ label = "OK"; ++ linux,code = <KEY_OK>; ++ channel = <0>; ++ voltage = <160000>; ++ }; ++}; ++ ++&mdio { ++ ext_rgmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++}; ++ ++&mmc0 { ++ bus-width = <4>; ++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ ++ disable-wp; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ xr829: wifi@1 { ++ reg = <1>; ++ }; ++}; ++ ++&ohci0 { ++ status = "okay"; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pb8_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ uart-has-rtscts; ++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ /* XR829 bluetooth is connected here */ ++}; ++ ++&usb_otg { ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&usbphy { ++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */ ++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */ ++ usb0_vbus-supply = <®_usbvbus>; ++ usb1_vbus-supply = <®_vcc>; ++ status = "okay"; ++}; diff --git a/target/linux/d1/patches-6.1/0030-riscv-dts-allwinner-Add-Sipeed-Lichee-RV-devicetrees.patch b/target/linux/d1/patches-6.1/0030-riscv-dts-allwinner-Add-Sipeed-Lichee-RV-devicetrees.patch new file mode 100644 index 0000000000..73c486aed2 --- /dev/null +++ b/target/linux/d1/patches-6.1/0030-riscv-dts-allwinner-Add-Sipeed-Lichee-RV-devicetrees.patch @@ -0,0 +1,344 @@ +From 3bf76e93011425ed64a69c462b9959ed2a8ccf46 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 29 Jun 2022 00:13:50 -0500 +Subject: [PATCH 030/117] riscv: dts: allwinner: Add Sipeed Lichee RV + devicetrees + +Sipeed manufactures a "Lichee RV" system-on-module, which provides a +minimal working system on its own, as well as a few carrier boards. The +"Dock" board provides audio, USB, and WiFi. The "86 Panel" additionally +provides 100M Ethernet and a built-in display panel. + +The 86 Panel repurposes the USB ID and VBUS detection GPIOs for its RGB +panel interface, since the USB OTG port is inaccessible inside the case. + +Co-developed-by: Jisheng Zhang <jszhang@kernel.org> +Signed-off-by: Jisheng Zhang <jszhang@kernel.org> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/Makefile | 4 + + .../sun20i-d1-lichee-rv-86-panel-480p.dts | 29 ++++++ + .../sun20i-d1-lichee-rv-86-panel-720p.dts | 10 ++ + .../sun20i-d1-lichee-rv-86-panel.dtsi | 92 +++++++++++++++++++ + .../allwinner/sun20i-d1-lichee-rv-dock.dts | 74 +++++++++++++++ + .../dts/allwinner/sun20i-d1-lichee-rv.dts | 84 +++++++++++++++++ + 6 files changed, 293 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-480p.dts + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-720p.dts + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv.dts + +--- a/arch/riscv/boot/dts/allwinner/Makefile ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -1,2 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-480p.dtb ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-720p.dtb ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-dock.dtb ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-nezha.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-480p.dts +@@ -0,0 +1,29 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++#include "sun20i-d1-lichee-rv-86-panel.dtsi" ++ ++/ { ++ model = "Sipeed Lichee RV 86 Panel (480p)"; ++ compatible = "sipeed,lichee-rv-86-panel-480p", "sipeed,lichee-rv", ++ "allwinner,sun20i-d1"; ++}; ++ ++&i2c2 { ++ pinctrl-0 = <&i2c2_pb0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ touchscreen@48 { ++ compatible = "focaltech,ft6236"; ++ reg = <0x48>; ++ interrupt-parent = <&pio>; ++ interrupts = <6 14 IRQ_TYPE_LEVEL_LOW>; /* PG14 */ ++ iovcc-supply = <®_vcc_3v3>; ++ reset-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */ ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <480>; ++ vcc-supply = <®_vcc_3v3>; ++ wakeup-source; ++ }; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-720p.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++#include "sun20i-d1-lichee-rv-86-panel.dtsi" ++ ++/ { ++ model = "Sipeed Lichee RV 86 Panel (720p)"; ++ compatible = "sipeed,lichee-rv-86-panel-720p", "sipeed,lichee-rv", ++ "allwinner,sun20i-d1"; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi +@@ -0,0 +1,92 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++#include "sun20i-d1-lichee-rv.dts" ++ ++/ { ++ aliases { ++ ethernet0 = &emac; ++ ethernet1 = &xr829; ++ }; ++ ++ /* PC1 is repurposed as BT_WAKE_AP */ ++ /delete-node/ leds; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ clocks = <&ccu CLK_FANOUT1>; ++ clock-names = "ext_clock"; ++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */ ++ assigned-clocks = <&ccu CLK_FANOUT1>; ++ assigned-clock-rates = <32768>; ++ pinctrl-0 = <&clk_pg11_pin>; ++ pinctrl-names = "default"; ++ }; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&emac { ++ pinctrl-0 = <&rmii_pe_pins>; ++ pinctrl-names = "default"; ++ phy-handle = <&ext_rmii_phy>; ++ phy-mode = "rmii"; ++ phy-supply = <®_vcc_3v3>; ++ status = "okay"; ++}; ++ ++&mdio { ++ ext_rmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */ ++ }; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ xr829: wifi@1 { ++ reg = <1>; ++ }; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&pio { ++ clk_pg11_pin: clk-pg11-pin { ++ pins = "PG11"; ++ function = "clk"; ++ }; ++}; ++ ++&uart1 { ++ uart-has-rtscts; ++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ /* XR829 bluetooth is connected here */ ++}; ++ ++&usb_otg { ++ status = "disabled"; ++}; ++ ++&usbphy { ++ /* PD20 and PD21 are repurposed for the LCD panel */ ++ /delete-property/ usb0_id_det-gpios; ++ /delete-property/ usb0_vbus_det-gpios; ++ usb1_vbus-supply = <®_vcc>; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org> ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++#include <dt-bindings/input/input.h> ++ ++#include "sun20i-d1-lichee-rv.dts" ++ ++/ { ++ model = "Sipeed Lichee RV Dock"; ++ compatible = "sipeed,lichee-rv-dock", "sipeed,lichee-rv", ++ "allwinner,sun20i-d1"; ++ ++ aliases { ++ ethernet1 = &rtl8723ds; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */ ++ }; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&lradc { ++ status = "okay"; ++ ++ button-220 { ++ label = "OK"; ++ linux,code = <KEY_OK>; ++ channel = <0>; ++ voltage = <220000>; ++ }; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ rtl8723ds: wifi@1 { ++ reg = <1>; ++ }; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ uart-has-rtscts; ++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "realtek,rtl8723ds-bt"; ++ device-wake-gpios = <&pio 6 15 GPIO_ACTIVE_HIGH>; /* PG16 */ ++ enable-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18 */ ++ host-wake-gpios = <&pio 6 17 GPIO_ACTIVE_HIGH>; /* PG17 */ ++ }; ++}; ++ ++&usbphy { ++ usb1_vbus-supply = <®_vcc>; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv.dts +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org> ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/leds/common.h> ++ ++#include "sun20i-d1.dtsi" ++#include "sun20i-d1-common-regulators.dtsi" ++ ++/ { ++ model = "Sipeed Lichee RV"; ++ compatible = "sipeed,lichee-rv", "allwinner,sun20i-d1"; ++ ++ aliases { ++ mmc0 = &mmc0; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led-0 { ++ color = <LED_COLOR_ID_GREEN>; ++ function = LED_FUNCTION_STATUS; ++ gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>; /* PC1 */ ++ }; ++ }; ++ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-cpu"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <900000>; ++ vin-supply = <®_vcc>; ++ }; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_vdd_cpu>; ++}; ++ ++&ehci0 { ++ status = "okay"; ++}; ++ ++&mmc0 { ++ broken-cd; ++ bus-width = <4>; ++ disable-wp; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&ohci0 { ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pb8_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&usbphy { ++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */ ++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */ ++ usb0_vbus-supply = <®_vcc>; ++ status = "okay"; ++}; diff --git a/target/linux/d1/patches-6.1/0031-riscv-dts-allwinner-Add-MangoPi-MQ-Pro-devicetree.patch b/target/linux/d1/patches-6.1/0031-riscv-dts-allwinner-Add-MangoPi-MQ-Pro-devicetree.patch new file mode 100644 index 0000000000..54073136bf --- /dev/null +++ b/target/linux/d1/patches-6.1/0031-riscv-dts-allwinner-Add-MangoPi-MQ-Pro-devicetree.patch @@ -0,0 +1,159 @@ +From 3cf55c25453517960d72b56d1ba8f12840b1990e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 9 Jul 2022 17:43:17 -0500 +Subject: [PATCH 031/117] riscv: dts: allwinner: Add MangoPi MQ Pro devicetree + +The MangoPi MQ Pro is a tiny SBC with a layout compatible to the +Raspberry Pi Zero. It includes the Allwinner D1 SoC, 512M or 1G of DDR3, +and an RTL8723DS-based WiFi/Bluetooth module. + +The board also exposes GPIO Port E via a connector on the end of the +board, which can support either a camera or an RMII Ethernet PHY. The +additional regulators supply that connector. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/Makefile | 1 + + .../allwinner/sun20i-d1-mangopi-mq-pro.dts | 128 ++++++++++++++++++ + 2 files changed, 129 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-mangopi-mq-pro.dts + +--- a/arch/riscv/boot/dts/allwinner/Makefile ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -3,4 +3,5 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-li + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-720p.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-dock.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv.dtb ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-mangopi-mq-pro.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-nezha.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-mangopi-mq-pro.dts +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++#include "sun20i-d1.dtsi" ++#include "sun20i-d1-common-regulators.dtsi" ++ ++/ { ++ model = "MangoPi MQ Pro"; ++ compatible = "widora,mangopi-mq-pro", "allwinner,sun20i-d1"; ++ ++ aliases { ++ ethernet0 = &rtl8723ds; ++ mmc0 = &mmc0; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reg_avdd2v8: avdd2v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "avdd2v8"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ vin-supply = <®_vcc_3v3>; ++ }; ++ ++ reg_dvdd: dvdd { ++ compatible = "regulator-fixed"; ++ regulator-name = "dvdd"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ vin-supply = <®_vcc_3v3>; ++ }; ++ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-cpu"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1100000>; ++ vin-supply = <®_vcc>; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&pio 6 17 GPIO_ACTIVE_LOW>; /* PG17 */ ++ }; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_vdd_cpu>; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&mmc0 { ++ bus-width = <4>; ++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ ++ disable-wp; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ rtl8723ds: wifi@1 { ++ reg = <1>; ++ interrupt-parent = <&pio>; ++ interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 */ ++ interrupt-names = "host-wake"; ++ }; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&pio { ++ vcc-pe-supply = <®_avdd2v8>; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pb8_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ uart-has-rtscts; ++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "realtek,rtl8723ds-bt"; ++ device-wake-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18 */ ++ enable-gpios = <&pio 6 15 GPIO_ACTIVE_HIGH>; /* PG15 */ ++ host-wake-gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */ ++ }; ++}; ++ ++&usb_otg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&usbphy { ++ usb0_vbus-supply = <®_vcc>; ++ status = "okay"; ++}; diff --git a/target/linux/d1/patches-6.1/0032-riscv-dts-allwinner-Add-Dongshan-Nezha-STU-devicetre.patch b/target/linux/d1/patches-6.1/0032-riscv-dts-allwinner-Add-Dongshan-Nezha-STU-devicetre.patch new file mode 100644 index 0000000000..fe64eabd4e --- /dev/null +++ b/target/linux/d1/patches-6.1/0032-riscv-dts-allwinner-Add-Dongshan-Nezha-STU-devicetre.patch @@ -0,0 +1,146 @@ +From 1f26c90ac9cbb60ff315c552368a3bca16562e51 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 10 Jul 2022 11:24:42 -0500 +Subject: [PATCH 032/117] riscv: dts: allwinner: Add Dongshan Nezha STU + devicetree + +The 100ask Dongshan Nezha STU is a system-on-module that can be used +standalone or with a carrier board. The SoM provides gigabit Ethernet, +HDMI, a USB peripheral port, and WiFi/Bluetooth via an RTL8723DS chip. + +The "DIY" carrier board exposes almost every pin from the D1 SoC to 0.1" +headers, but contains no digital circuitry, so it does not have its own +devicetree. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/Makefile | 1 + + .../sun20i-d1-dongshan-nezha-stu.dts | 114 ++++++++++++++++++ + 2 files changed, 115 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-dongshan-nezha-stu.dts + +--- a/arch/riscv/boot/dts/allwinner/Makefile ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-dongshan-nezha-stu.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-480p.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-720p.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-dock.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-dongshan-nezha-stu.dts +@@ -0,0 +1,114 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/leds/common.h> ++ ++#include "sun20i-d1.dtsi" ++#include "sun20i-d1-common-regulators.dtsi" ++ ++/ { ++ model = "Dongshan Nezha STU"; ++ compatible = "100ask,dongshan-nezha-stu", "allwinner,sun20i-d1"; ++ ++ aliases { ++ ethernet0 = &emac; ++ mmc0 = &mmc0; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led-0 { ++ color = <LED_COLOR_ID_GREEN>; ++ function = LED_FUNCTION_STATUS; ++ gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>; /* PC1 */ ++ }; ++ }; ++ ++ reg_usbvbus: usbvbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usbvbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&pio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */ ++ enable-active-high; ++ vin-supply = <®_vcc>; ++ }; ++ ++ /* ++ * This regulator is PWM-controlled, but the PWM controller is not ++ * yet supported, so fix the regulator to its default voltage. ++ */ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-cpu"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1100000>; ++ vin-supply = <®_vcc>; ++ }; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_vdd_cpu>; ++}; ++ ++&ehci0 { ++ status = "okay"; ++}; ++ ++&emac { ++ pinctrl-0 = <&rgmii_pe_pins>; ++ pinctrl-names = "default"; ++ phy-handle = <&ext_rgmii_phy>; ++ phy-mode = "rgmii-id"; ++ phy-supply = <®_vcc_3v3>; ++ status = "okay"; ++}; ++ ++&mdio { ++ ext_rgmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; ++}; ++ ++&mmc0 { ++ broken-cd; ++ bus-width = <4>; ++ disable-wp; ++ vmmc-supply = <®_vcc_3v3>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&ohci0 { ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pb8_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "otg"; ++ status = "okay"; ++}; ++ ++&usbphy { ++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */ ++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */ ++ usb0_vbus-supply = <®_usbvbus>; ++ status = "okay"; ++}; diff --git a/target/linux/d1/patches-6.1/0033-riscv-dts-allwinner-Add-ClockworkPi-and-DevTerm-devi.patch b/target/linux/d1/patches-6.1/0033-riscv-dts-allwinner-Add-ClockworkPi-and-DevTerm-devi.patch new file mode 100644 index 0000000000..f9fcae026f --- /dev/null +++ b/target/linux/d1/patches-6.1/0033-riscv-dts-allwinner-Add-ClockworkPi-and-DevTerm-devi.patch @@ -0,0 +1,322 @@ +From 11f692c6b009f36b9a91d5ceb5998ae15e57f18c Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 10 Jul 2022 23:43:49 -0500 +Subject: [PATCH 033/117] riscv: dts: allwinner: Add ClockworkPi and DevTerm + devicetrees + +Clockwork Tech manufactures several SoMs for their RasPi CM3-compatible +"ClockworkPi" mainboard. Their R-01 SoM features the Allwinner D1 SoC. +The R-01 contains only the CPU, DRAM, and always-on voltage regulation; +it does not merit a separate devicetree. + +The ClockworkPi mainboard features analog audio, a MIPI-DSI panel, USB +host and peripheral ports, an Ampak AP6256 WiFi/Bluetooth module, and an +X-Powers AXP228 PMIC for managing a Li-ion battery. + +The DevTerm is a complete system which extends the ClockworkPi mainboard +with a pair of expansion boards. These expansion boards provide a fan, a +keyboard, speakers, and a thermal printer. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/Makefile | 2 + + .../allwinner/sun20i-d1-clockworkpi-v3.14.dts | 242 ++++++++++++++++++ + .../dts/allwinner/sun20i-d1-devterm-v3.14.dts | 37 +++ + 3 files changed, 281 insertions(+) + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts + create mode 100644 arch/riscv/boot/dts/allwinner/sun20i-d1-devterm-v3.14.dts + +--- a/arch/riscv/boot/dts/allwinner/Makefile ++++ b/arch/riscv/boot/dts/allwinner/Makefile +@@ -1,4 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-clockworkpi-v3.14.dtb ++dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-devterm-v3.14.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-dongshan-nezha-stu.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-480p.dtb + dtb-$(CONFIG_ARCH_SUNXI) += sun20i-d1-lichee-rv-86-panel-720p.dtb +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts +@@ -0,0 +1,242 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include <dt-bindings/gpio/gpio.h> ++ ++#include "sun20i-d1.dtsi" ++#include "sun20i-d1-common-regulators.dtsi" ++ ++/ { ++ model = "ClockworkPi v3.14 (R-01)"; ++ compatible = "clockwork,r-01-clockworkpi-v3.14", "allwinner,sun20i-d1"; ++ ++ aliases { ++ ethernet0 = &ap6256; ++ mmc0 = &mmc0; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ /* ++ * This regulator is PWM-controlled, but the PWM controller is not ++ * yet supported, so fix the regulator to its default voltage. ++ */ ++ reg_vdd_cpu: vdd-cpu { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd-cpu"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1100000>; ++ vin-supply = <®_vcc>; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>; /* PG11/GPIO3 */ ++ }; ++}; ++ ++&cpu0 { ++ cpu-supply = <®_vdd_cpu>; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ pinctrl-0 = <&i2c0_pb10_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ axp221: pmic@34 { ++ compatible = "x-powers,axp228", "x-powers,axp221"; ++ reg = <0x34>; ++ interrupt-parent = <&pio>; ++ interrupts = <4 9 IRQ_TYPE_LEVEL_LOW>; /* PE9/GPIO2 */ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ ac_power_supply: ac-power { ++ compatible = "x-powers,axp221-ac-power-supply"; ++ }; ++ ++ axp_adc: adc { ++ compatible = "x-powers,axp221-adc"; ++ #io-channel-cells = <1>; ++ }; ++ ++ battery_power_supply: battery-power { ++ compatible = "x-powers,axp221-battery-power-supply"; ++ }; ++ ++ regulators { ++ x-powers,dcdc-freq = <3000>; ++ ++ reg_dcdc1: dcdc1 { ++ regulator-name = "sys-3v3"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_dcdc3: dcdc3 { ++ regulator-name = "sys-1v8"; ++ regulator-always-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ reg_aldo1: aldo1 { ++ regulator-name = "aud-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_aldo2: aldo2 { ++ regulator-name = "disp-3v3"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_aldo3: aldo3 { ++ regulator-name = "vdd-wifi"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ /* DLDO1 and ELDO1-3 are connected in parallel. */ ++ reg_dldo1: dldo1 { ++ regulator-name = "vbat-wifi-a"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ /* DLDO2-DLDO4 are connected in parallel. */ ++ reg_dldo2: dldo2 { ++ regulator-name = "vcc-3v3-ext-a"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_dldo3: dldo3 { ++ regulator-name = "vcc-3v3-ext-b"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_dldo4: dldo4 { ++ regulator-name = "vcc-3v3-ext-c"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_eldo1: eldo1 { ++ regulator-name = "vbat-wifi-b"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_eldo2: eldo2 { ++ regulator-name = "vbat-wifi-c"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ reg_eldo3: eldo3 { ++ regulator-name = "vbat-wifi-d"; ++ regulator-always-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ }; ++ ++ usb_power_supply: usb-power { ++ compatible = "x-powers,axp221-usb-power-supply"; ++ status = "disabled"; ++ }; ++ }; ++}; ++ ++&mmc0 { ++ broken-cd; ++ bus-width = <4>; ++ disable-wp; ++ vmmc-supply = <®_dcdc1>; ++ vqmmc-supply = <®_vcc_3v3>; ++ pinctrl-0 = <&mmc0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ bus-width = <4>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ non-removable; ++ vmmc-supply = <®_dldo1>; ++ vqmmc-supply = <®_aldo3>; ++ pinctrl-0 = <&mmc1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ ap6256: wifi@1 { ++ compatible = "brcm,bcm43456-fmac", "brcm,bcm4329-fmac"; ++ reg = <1>; ++ interrupt-parent = <&pio>; ++ interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10/GPIO4 */ ++ interrupt-names = "host-wake"; ++ }; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&pio { ++ vcc-pg-supply = <®_ldoa>; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pb8_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ uart-has-rtscts; ++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "brcm,bcm4345c5"; ++ interrupt-parent = <&pio>; ++ interrupts = <6 17 IRQ_TYPE_LEVEL_HIGH>; /* PG17/GPIO6 */ ++ device-wakeup-gpios = <&pio 6 16 GPIO_ACTIVE_HIGH>; /* PG16/GPIO7 */ ++ shutdown-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18/GPIO5 */ ++ max-speed = <1500000>; ++ vbat-supply = <®_dldo1>; ++ vddio-supply = <®_aldo3>; ++ }; ++}; ++ ++&usb_otg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&usbphy { ++ usb0_vbus_power-supply = <&ac_power_supply>; ++ status = "okay"; ++}; +--- /dev/null ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-devterm-v3.14.dts +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: (GPL-2.0+ or MIT) ++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org> ++ ++/dts-v1/; ++ ++#include "sun20i-d1-clockworkpi-v3.14.dts" ++ ++/ { ++ model = "Clockwork DevTerm (R-01)"; ++ compatible = "clockwork,r-01-devterm-v3.14", ++ "clockwork,r-01-clockworkpi-v3.14", ++ "allwinner,sun20i-d1"; ++ ++ fan { ++ compatible = "gpio-fan"; ++ gpios = <&pio 3 10 GPIO_ACTIVE_HIGH>; /* PD10/GPIO41 */ ++ gpio-fan,speed-map = <0 0>, ++ <6000 1>; ++ #cooling-cells = <2>; ++ }; ++ ++ i2c-gpio-0 { ++ compatible = "i2c-gpio"; ++ sda-gpios = <&pio 3 14 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; /* PD14/GPIO44 */ ++ scl-gpios = <&pio 3 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; /* PD15/GPIO45 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ adc@54 { ++ compatible = "ti,adc101c"; ++ reg = <0x54>; ++ interrupt-parent = <&pio>; ++ interrupts = <4 12 IRQ_TYPE_LEVEL_LOW>; /* PE12/GPIO35 */ ++ vref-supply = <®_dldo2>; ++ }; ++ }; ++}; diff --git a/target/linux/d1/patches-6.1/0034-riscv-Add-the-Allwinner-SoC-family-Kconfig-option.patch b/target/linux/d1/patches-6.1/0034-riscv-Add-the-Allwinner-SoC-family-Kconfig-option.patch new file mode 100644 index 0000000000..b31537d150 --- /dev/null +++ b/target/linux/d1/patches-6.1/0034-riscv-Add-the-Allwinner-SoC-family-Kconfig-option.patch @@ -0,0 +1,44 @@ +From f648ec2a040efde432876ee04240cb71e4c24d6e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 16 May 2021 14:17:45 -0500 +Subject: [PATCH 034/117] riscv: Add the Allwinner SoC family Kconfig option + +Allwinner manufactures the sunxi family of application processors. This +includes the "sun8i" series of ARMv7 SoCs, the "sun50i" series of ARMv8 +SoCs, and now the "sun20i" series of 64-bit RISC-V SoCs. + +The first SoC in the sun20i series is D1, containing a single T-HEAD +C906 core. D1s is a low-pin-count variant of D1 with co-packaged DRAM. + +Most peripherals are shared across the entire chip family. In fact, the +ARMv7 T113 SoC is pin-compatible and almost entirely register-compatible +with the D1s. + +This means many existing device drivers can be reused. To facilitate +this reuse, name the symbol ARCH_SUNXI, since that is what the existing +drivers have as their dependency. + +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Tested-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/Kconfig.socs | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -1,5 +1,14 @@ + menu "SoC selection" + ++config ARCH_SUNXI ++ bool "Allwinner sun20i SoCs" ++ select ERRATA_THEAD if MMU && !XIP_KERNEL ++ select SIFIVE_PLIC ++ select SUN4I_TIMER ++ help ++ This enables support for Allwinner sun20i platform hardware, ++ including boards based on the D1 and D1s SoCs. ++ + config SOC_MICROCHIP_POLARFIRE + bool "Microchip PolarFire SoCs" + select MCHP_CLK_MPFS diff --git a/target/linux/d1/patches-6.1/0035-riscv-defconfig-Enable-the-Allwinner-D1-platform-and.patch b/target/linux/d1/patches-6.1/0035-riscv-defconfig-Enable-the-Allwinner-D1-platform-and.patch new file mode 100644 index 0000000000..2c172c8ad8 --- /dev/null +++ b/target/linux/d1/patches-6.1/0035-riscv-defconfig-Enable-the-Allwinner-D1-platform-and.patch @@ -0,0 +1,127 @@ +From 73f9cc8568b6b821107d5194fa868e922b159091 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Mon, 27 Jun 2022 01:33:05 -0500 +Subject: [PATCH 035/117] riscv: defconfig: Enable the Allwinner D1 platform + and drivers + +Now that several D1-based boards are supported, enable the platform in +our defconfig. Build in the drivers which are necessary to boot, such as +the pinctrl, MMC, RTC (which provides critical clocks), SPI (for flash), +and watchdog (which may be left enabled by the bootloader). Other common +onboard peripherals are enabled as modules. + +Cover-letter: +riscv: Allwinner D1 platform support +This series adds the Kconfig/defconfig plumbing and devicetrees for a +range of Allwinner D1-based boards. Many features are already enabled, +including USB, Ethernet, and WiFi. + +The SoC devicetree uses bindings from the following series which have +not yet been merged: +- SRAM controller: + https://lore.kernel.org/lkml/20220815041248.53268-1-samuel@sholland.org/ +- NVMEM cell bits property change: + https://lore.kernel.org/lkml/20220814173656.11856-1-samuel@sholland.org/ +- In-package LDO regulators: + https://lore.kernel.org/lkml/20220815043436.20170-1-samuel@sholland.org/ + +All three of these are required to set the correct I/O domain voltages +in the pin controller, which I would consider important to have in the +initial version of the devicetree. + +The SoC devicetree does contain one small hack to avoid a dependency on +the audio codec binding, since that is not ready yet: the codec node +uses a bare "simple-mfd", "syscon" compatible. +END + +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> +Series-to: linux-sunxi@lists.linux.dev +Series-to: Palmer Dabbelt <palmer@dabbelt.com> +Series-to: Paul Walmsley <paul.walmsley@sifive.com> +Series-to: Albert Ou <aou@eecs.berkeley.edu> +Series-to: linux-riscv@lists.infradead.org +Series-cc: Rob Herring <robh+dt@kernel.org> +Series-cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org> +Series-cc: devicetree@vger.kernel.org +Series-cc: linux-kernel@vger.kernel.org + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/configs/defconfig | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -25,6 +25,7 @@ CONFIG_BLK_DEV_INITRD=y + CONFIG_EXPERT=y + # CONFIG_SYSFS_SYSCALL is not set + CONFIG_PROFILING=y ++CONFIG_ARCH_SUNXI=y + CONFIG_SOC_MICROCHIP_POLARFIRE=y + CONFIG_SOC_SIFIVE=y + CONFIG_SOC_STARFIVE=y +@@ -118,22 +119,31 @@ CONFIG_VIRTIO_NET=y + CONFIG_MACB=y + CONFIG_E1000E=y + CONFIG_R8169=y ++CONFIG_STMMAC_ETH=m + CONFIG_MICROSEMI_PHY=y + CONFIG_INPUT_MOUSEDEV=y ++CONFIG_KEYBOARD_SUN4I_LRADC=m + CONFIG_SERIAL_8250=y + CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_DW=y + CONFIG_SERIAL_OF_PLATFORM=y + CONFIG_VIRTIO_CONSOLE=y + CONFIG_HW_RANDOM=y + CONFIG_HW_RANDOM_VIRTIO=y ++CONFIG_I2C_MV64XXX=m + CONFIG_SPI=y + CONFIG_SPI_SIFIVE=y ++CONFIG_SPI_SUN6I=y + # CONFIG_PTP_1588_CLOCK is not set +-CONFIG_GPIOLIB=y + CONFIG_GPIO_SIFIVE=y ++CONFIG_WATCHDOG=y ++CONFIG_SUNXI_WATCHDOG=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y + CONFIG_DRM=m + CONFIG_DRM_RADEON=m + CONFIG_DRM_NOUVEAU=m ++CONFIG_DRM_SUN4I=m + CONFIG_DRM_VIRTIO_GPU=m + CONFIG_FB=y + CONFIG_FRAMEBUFFER_CONSOLE=y +@@ -146,19 +156,30 @@ CONFIG_USB_OHCI_HCD=y + CONFIG_USB_OHCI_HCD_PLATFORM=y + CONFIG_USB_STORAGE=y + CONFIG_USB_UAS=y ++CONFIG_USB_MUSB_HDRC=m ++CONFIG_USB_MUSB_SUNXI=m ++CONFIG_NOP_USB_XCEIV=m + CONFIG_MMC=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_CADENCE=y + CONFIG_MMC_SPI=y ++CONFIG_MMC_SUNXI=y + CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_SUN6I=y ++CONFIG_DMADEVICES=y ++CONFIG_DMA_SUN6I=m + CONFIG_VIRTIO_PCI=y + CONFIG_VIRTIO_BALLOON=y + CONFIG_VIRTIO_INPUT=y + CONFIG_VIRTIO_MMIO=y ++CONFIG_SUN8I_DE2_CCU=m ++CONFIG_SUN50I_IOMMU=y + CONFIG_RPMSG_CHAR=y + CONFIG_RPMSG_CTRL=y + CONFIG_RPMSG_VIRTIO=y ++CONFIG_PHY_SUN4I_USB=m ++CONFIG_NVMEM_SUNXI_SID=y + CONFIG_EXT4_FS=y + CONFIG_EXT4_FS_POSIX_ACL=y + CONFIG_EXT4_FS_SECURITY=y diff --git a/target/linux/d1/patches-6.1/0036-riscv-dts-allwinner-Add-Bluetooth-PCM-audio.patch b/target/linux/d1/patches-6.1/0036-riscv-dts-allwinner-Add-Bluetooth-PCM-audio.patch new file mode 100644 index 0000000000..0ef4b3c56b --- /dev/null +++ b/target/linux/d1/patches-6.1/0036-riscv-dts-allwinner-Add-Bluetooth-PCM-audio.patch @@ -0,0 +1,80 @@ +From bf83f1dc034111aac1f23b98d7205d08c7c83208 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 02:33:25 -0500 +Subject: [PATCH 036/117] riscv: dts: allwinner: Add Bluetooth PCM audio + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../allwinner/sun20i-d1-clockworkpi-v3.14.dts | 47 +++++++++++++++++++ + 1 file changed, 47 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts +@@ -22,6 +22,32 @@ + stdout-path = "serial0:115200n8"; + }; + ++ bt_sco_codec: bt-sco-codec { ++ #sound-dai-cells = <0>; ++ compatible = "linux,bt-sco"; ++ }; ++ ++ bt-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "Bluetooth"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ simple-audio-card,dai-link@0 { ++ format = "dsp_a"; ++ frame-master = <&bt_sound_cpu>; ++ bitclock-master = <&bt_sound_cpu>; ++ ++ bt_sound_cpu: cpu { ++ sound-dai = <&i2s1>; ++ }; ++ ++ codec { ++ sound-dai = <&bt_sco_codec>; ++ }; ++ }; ++ }; ++ + /* + * This regulator is PWM-controlled, but the PWM controller is not + * yet supported, so fix the regulator to its default voltage. +@@ -169,6 +195,12 @@ + }; + }; + ++&i2s1 { ++ pinctrl-0 = <&i2s1_clk_pins>, <&i2s1_din_pin>, <&i2s1_dout_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &mmc0 { + broken-cd; + bus-width = <4>; +@@ -205,6 +237,21 @@ + + &pio { + vcc-pg-supply = <®_ldoa>; ++ ++ i2s1_clk_pins: i2s1-clk-pins { ++ pins = "PG12", "PG13"; ++ function = "i2s1"; ++ }; ++ ++ i2s1_din_pin: i2s1-din-pin { ++ pins = "PG14"; ++ function = "i2s1_din"; ++ }; ++ ++ i2s1_dout_pin: i2s1-dout-pin { ++ pins = "PG15"; ++ function = "i2s1_dout"; ++ }; + }; + + &uart0 { diff --git a/target/linux/d1/patches-6.1/0037-dt-bindings-crypto-sun8i-ce-Add-compatible-for-D1.patch b/target/linux/d1/patches-6.1/0037-dt-bindings-crypto-sun8i-ce-Add-compatible-for-D1.patch new file mode 100644 index 0000000000..1aee036b10 --- /dev/null +++ b/target/linux/d1/patches-6.1/0037-dt-bindings-crypto-sun8i-ce-Add-compatible-for-D1.patch @@ -0,0 +1,87 @@ +From 690b8d708e0193d50522f70359bcab62a2f99742 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Nov 2021 09:04:29 -0600 +Subject: [PATCH 037/117] dt-bindings: crypto: sun8i-ce: Add compatible for D1 + +D1 has a crypto engine similar to the one in other Allwinner SoCs. +Like H6, it has a separate MBUS clock gate. + +It also requires the internal RC oscillator to be enabled for the TRNG +to return data. This is likely the case for earlier variants as well, +but the clock drivers for earlier SoCs did not allow disabling the RC +oscillator. + +Series-changes: 2 + - Add TRNG clock + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/crypto/allwinner,sun8i-ce.yaml | 31 ++++++++++++++----- + 1 file changed, 23 insertions(+), 8 deletions(-) + +--- a/Documentation/devicetree/bindings/crypto/allwinner,sun8i-ce.yaml ++++ b/Documentation/devicetree/bindings/crypto/allwinner,sun8i-ce.yaml +@@ -14,6 +14,7 @@ properties: + enum: + - allwinner,sun8i-h3-crypto + - allwinner,sun8i-r40-crypto ++ - allwinner,sun20i-d1-crypto + - allwinner,sun50i-a64-crypto + - allwinner,sun50i-h5-crypto + - allwinner,sun50i-h6-crypto +@@ -29,6 +30,7 @@ properties: + - description: Bus clock + - description: Module clock + - description: MBus clock ++ - description: TRNG clock (RC oscillator) + minItems: 2 + + clock-names: +@@ -36,6 +38,7 @@ properties: + - const: bus + - const: mod + - const: ram ++ - const: trng + minItems: 2 + + resets: +@@ -44,19 +47,31 @@ properties: + if: + properties: + compatible: +- const: allwinner,sun50i-h6-crypto ++ enum: ++ - allwinner,sun20i-d1-crypto + then: + properties: + clocks: +- minItems: 3 ++ minItems: 4 + clock-names: +- minItems: 3 ++ minItems: 4 + else: +- properties: +- clocks: +- maxItems: 2 +- clock-names: +- maxItems: 2 ++ if: ++ properties: ++ compatible: ++ const: allwinner,sun50i-h6-crypto ++ then: ++ properties: ++ clocks: ++ minItems: 3 ++ clock-names: ++ minItems: 3 ++ else: ++ properties: ++ clocks: ++ maxItems: 2 ++ clock-names: ++ maxItems: 2 + + required: + - compatible diff --git a/target/linux/d1/patches-6.1/0038-crypto-sun8i-ce-Add-TRNG-clock-to-D1-variant.patch b/target/linux/d1/patches-6.1/0038-crypto-sun8i-ce-Add-TRNG-clock-to-D1-variant.patch new file mode 100644 index 0000000000..b8344ce5ce --- /dev/null +++ b/target/linux/d1/patches-6.1/0038-crypto-sun8i-ce-Add-TRNG-clock-to-D1-variant.patch @@ -0,0 +1,47 @@ +From d09357656ae3985095f562cf005fa94fd61ebfe6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 1 Feb 2022 21:50:16 -0600 +Subject: [PATCH 038/117] crypto: sun8i-ce - Add TRNG clock to D1 variant + +At least the D1 variant requires a separate clock for the TRNG. +Without this clock enabled, reading from /dev/hwrng reports: + + sun8i-ce 3040000.crypto: DMA timeout for TRNG (tm=96) on flow 3 + +Experimentation shows that the necessary clock is the SoC's internal +RC oscillator. This makes sense, as the oscillator's frequency +variations can be used as a source of randomness. + +Since D1 does not yet have a device tree, we can update this variant +without breaking anything. + +Series-changes: 2 + - New patch + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 1 + + drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c ++++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +@@ -118,6 +118,7 @@ static const struct ce_variant ce_d1_var + { "bus", 0, 200000000 }, + { "mod", 300000000, 0 }, + { "ram", 0, 400000000 }, ++ { "trng", 0, 0 }, + }, + .esr = ESR_D1, + .prng = CE_ALG_PRNG, +--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h ++++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h +@@ -105,7 +105,7 @@ + + #define MAX_SG 8 + +-#define CE_MAX_CLOCKS 3 ++#define CE_MAX_CLOCKS 4 + + #define MAXFLOW 4 + diff --git a/target/linux/d1/patches-6.1/0039-riscv-dts-allwinner-d1-Add-crypto-engine-support.patch b/target/linux/d1/patches-6.1/0039-riscv-dts-allwinner-d1-Add-crypto-engine-support.patch new file mode 100644 index 0000000000..05289b737c --- /dev/null +++ b/target/linux/d1/patches-6.1/0039-riscv-dts-allwinner-d1-Add-crypto-engine-support.patch @@ -0,0 +1,31 @@ +From 5dae72bf0e0fabb3164dbc4b5eee310c63f1975c Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:20:31 -0500 +Subject: [PATCH 039/117] riscv: dts: allwinner: d1: Add crypto engine support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -457,6 +457,18 @@ + }; + }; + ++ crypto: crypto@3040000 { ++ compatible = "allwinner,sun20i-d1-crypto"; ++ reg = <0x3040000 0x800>; ++ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_CE>, ++ <&ccu CLK_CE>, ++ <&ccu CLK_MBUS_CE>, ++ <&rtc CLK_IOSC>; ++ clock-names = "bus", "mod", "ram", "trng"; ++ resets = <&ccu RST_BUS_CE>; ++ }; ++ + mbus: dram-controller@3102000 { + compatible = "allwinner,sun20i-d1-mbus"; + reg = <0x3102000 0x1000>, diff --git a/target/linux/d1/patches-6.1/0040-ASoC-sun50i-dmic-dt-bindings-Add-D1-compatible-strin.patch b/target/linux/d1/patches-6.1/0040-ASoC-sun50i-dmic-dt-bindings-Add-D1-compatible-strin.patch new file mode 100644 index 0000000000..abc4608e19 --- /dev/null +++ b/target/linux/d1/patches-6.1/0040-ASoC-sun50i-dmic-dt-bindings-Add-D1-compatible-strin.patch @@ -0,0 +1,27 @@ +From 7a24e5ee94e0163801c8ab4c131ae1d530a420ea Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 02:08:36 -0500 +Subject: [PATCH 040/117] ASoC: sun50i-dmic: dt-bindings: Add D1 compatible + string + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/sound/allwinner,sun50i-h6-dmic.yaml | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml ++++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml +@@ -11,7 +11,12 @@ maintainers: + + properties: + compatible: +- const: allwinner,sun50i-h6-dmic ++ oneOf: ++ - items: ++ - enum: ++ - allwinner,sun20i-d1-dmic ++ - const: allwinner,sun50i-h6-dmic ++ - const: allwinner,sun50i-h6-dmic + + "#sound-dai-cells": + const: 0 diff --git a/target/linux/d1/patches-6.1/0041-riscv-dts-allwinner-d1-Add-DMIC-node.patch b/target/linux/d1/patches-6.1/0041-riscv-dts-allwinner-d1-Add-DMIC-node.patch new file mode 100644 index 0000000000..1d838c92bf --- /dev/null +++ b/target/linux/d1/patches-6.1/0041-riscv-dts-allwinner-d1-Add-DMIC-node.patch @@ -0,0 +1,34 @@ +From d73f2176958e405e55c4e782c6d0f888e20080e5 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 02:08:58 -0500 +Subject: [PATCH 041/117] riscv: dts: allwinner: d1: Add DMIC node + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -208,6 +208,21 @@ + }; + }; + ++ dmic: dmic@2031000 { ++ compatible = "allwinner,sun20i-d1-dmic", ++ "allwinner,sun50i-h6-dmic"; ++ reg = <0x2031000 0x400>; ++ interrupts = <40 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_DMIC>, ++ <&ccu CLK_DMIC>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_DMIC>; ++ dmas = <&dma 8>; ++ dma-names = "rx"; ++ status = "disabled"; ++ #sound-dai-cells = <0>; ++ }; ++ + i2s0: i2s@2032000 { + compatible = "allwinner,sun20i-d1-i2s", + "allwinner,sun50i-r329-i2s"; diff --git a/target/linux/d1/patches-6.1/0042-riscv-dts-allwinner-Add-DMIC-sound-cards.patch b/target/linux/d1/patches-6.1/0042-riscv-dts-allwinner-Add-DMIC-sound-cards.patch new file mode 100644 index 0000000000..1aec73b70f --- /dev/null +++ b/target/linux/d1/patches-6.1/0042-riscv-dts-allwinner-Add-DMIC-sound-cards.patch @@ -0,0 +1,144 @@ +From 500a3fc1ce1b216ef4f4df73e4e048170764189e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 02:20:49 -0500 +Subject: [PATCH 042/117] riscv: dts: allwinner: Add DMIC sound cards + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../sun20i-d1-lichee-rv-86-panel.dtsi | 43 ++++++++++++++++++ + .../allwinner/sun20i-d1-lichee-rv-dock.dts | 45 +++++++++++++++++++ + 2 files changed, 88 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi +@@ -9,6 +9,33 @@ + ethernet1 = &xr829; + }; + ++ dmic_codec: dmic-codec { ++ compatible = "dmic-codec"; ++ num-channels = <2>; ++ #sound-dai-cells = <0>; ++ }; ++ ++ dmic-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "DMIC"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ simple-audio-card,dai-link@0 { ++ format = "pdm"; ++ frame-master = <&link0_cpu>; ++ bitclock-master = <&link0_cpu>; ++ ++ link0_cpu: cpu { ++ sound-dai = <&dmic>; ++ }; ++ ++ link0_codec: codec { ++ sound-dai = <&dmic_codec>; ++ }; ++ }; ++ }; ++ + /* PC1 is repurposed as BT_WAKE_AP */ + /delete-node/ leds; + +@@ -24,6 +51,12 @@ + }; + }; + ++&dmic { ++ pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &ehci1 { + status = "okay"; + }; +@@ -69,6 +102,16 @@ + pins = "PG11"; + function = "clk"; + }; ++ ++ dmic_pb11_d0_pin: dmic-pb11-d0-pin { ++ pins = "PB11"; ++ function = "dmic"; ++ }; ++ ++ dmic_pe17_clk_pin: dmic-pe17-clk-pin { ++ pins = "PE17"; ++ function = "dmic"; ++ }; + }; + + &uart1 { +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts +@@ -15,12 +15,45 @@ + ethernet1 = &rtl8723ds; + }; + ++ dmic_codec: dmic-codec { ++ compatible = "dmic-codec"; ++ num-channels = <2>; ++ #sound-dai-cells = <0>; ++ }; ++ ++ dmic-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "DMIC"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ simple-audio-card,dai-link@0 { ++ format = "pdm"; ++ frame-master = <&link0_cpu>; ++ bitclock-master = <&link0_cpu>; ++ ++ link0_cpu: cpu { ++ sound-dai = <&dmic>; ++ }; ++ ++ link0_codec: codec { ++ sound-dai = <&dmic_codec>; ++ }; ++ }; ++ }; ++ + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */ + }; + }; + ++&dmic { ++ pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &ehci1 { + status = "okay"; + }; +@@ -55,6 +88,18 @@ + status = "okay"; + }; + ++&pio { ++ dmic_pb11_d0_pin: dmic-pb11-d0-pin { ++ pins = "PB11"; ++ function = "dmic"; ++ }; ++ ++ dmic_pe17_clk_pin: dmic-pe17-clk-pin { ++ pins = "PE17"; ++ function = "dmic"; ++ }; ++}; ++ + &uart1 { + uart-has-rtscts; + pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>; diff --git a/target/linux/d1/patches-6.1/0043-hwspinlock-sun6i-Clarify-bank-counting-logic.patch b/target/linux/d1/patches-6.1/0043-hwspinlock-sun6i-Clarify-bank-counting-logic.patch new file mode 100644 index 0000000000..e7fb887772 --- /dev/null +++ b/target/linux/d1/patches-6.1/0043-hwspinlock-sun6i-Clarify-bank-counting-logic.patch @@ -0,0 +1,64 @@ +From 7708f7471ab45039e08237b42121d0372f9216a7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:42:19 -0500 +Subject: [PATCH 043/117] hwspinlock: sun6i: Clarify bank counting logic + +In some of the most recent datasheets, the register definition was +updated in a way that resolves the conflict here: the field is only two +bits wide, and a value of "4" really means a bit pattern of "0". Correct +the code to reflect this, but leave an updated comment because some +datasheets still have incorrect information in them. + +Fixes: 3c881e05c814 ("hwspinlock: add sun6i hardware spinlock support") +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/hwspinlock/sun6i_hwspinlock.c | 36 +++++++++++---------------- + 1 file changed, 14 insertions(+), 22 deletions(-) + +--- a/drivers/hwspinlock/sun6i_hwspinlock.c ++++ b/drivers/hwspinlock/sun6i_hwspinlock.c +@@ -129,30 +129,22 @@ static int sun6i_hwspinlock_probe(struct + } + + /* +- * bit 28 and 29 represents the hwspinlock setup ++ * Bits 28 and 29 represent the number of available locks. + * +- * every datasheet (A64, A80, A83T, H3, H5, H6 ...) says the default value is 0x1 and 0x1 +- * to 0x4 represent 32, 64, 128 and 256 locks +- * but later datasheets (H5, H6) say 00, 01, 10, 11 represent 32, 64, 128 and 256 locks, +- * but that would mean H5 and H6 have 64 locks, while their datasheets talk about 32 locks +- * all the time, not a single mentioning of 64 locks +- * the 0x4 value is also not representable by 2 bits alone, so some datasheets are not +- * correct +- * one thing have all in common, default value of the sysstatus register is 0x10000000, +- * which results in bit 28 being set +- * this is the reason 0x1 is considered being 32 locks and bit 30 is taken into account +- * verified on H2+ (datasheet 0x1 = 32 locks) and H5 (datasheet 01 = 64 locks) ++ * The datasheets have two conflicting interpretations for these bits: ++ * | 00 | 01 | 10 | 11 | ++ * +-----+----+-----+-----+ ++ * | 256 | 32 | 64 | 128 | A80, A83T, H3, A64, A50, D1 ++ * | 32 | 64 | 128 | 256 | H5, H6, R329 ++ * where some datasheets use "4" instead of "0" for the first column. ++ * ++ * Experiments shows that the first interpretation is correct, as all ++ * known implementations report the value "1" and have 32 spinlocks. + */ +- num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28; +- switch (num_banks) { +- case 1 ... 4: +- priv->nlocks = 1 << (4 + num_banks); +- break; +- default: +- err = -EINVAL; +- dev_err(&pdev->dev, "unsupported hwspinlock setup (%d)\n", num_banks); +- goto bank_fail; +- } ++ num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28 & 0x3; ++ if (!num_banks) ++ num_banks = 4; ++ priv->nlocks = 1 << (4 + num_banks); + + priv->bank = devm_kzalloc(&pdev->dev, struct_size(priv->bank, lock, priv->nlocks), + GFP_KERNEL); diff --git a/target/linux/d1/patches-6.1/0044-hwspinlock-sun6i-Fix-driver-to-match-binding.patch b/target/linux/d1/patches-6.1/0044-hwspinlock-sun6i-Fix-driver-to-match-binding.patch new file mode 100644 index 0000000000..23adcd3af3 --- /dev/null +++ b/target/linux/d1/patches-6.1/0044-hwspinlock-sun6i-Fix-driver-to-match-binding.patch @@ -0,0 +1,37 @@ +From a19b55088945ce86051ea4eab22df27805a30c71 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:41:44 -0500 +Subject: [PATCH 044/117] hwspinlock: sun6i: Fix driver to match binding + +The binding for this device does not allow using the clock-names and +reset-names properties, so the driver should not reference the clock or +reset by name. + +Fixes: 3c881e05c814 ("hwspinlock: add sun6i hardware spinlock support") +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/hwspinlock/sun6i_hwspinlock.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/hwspinlock/sun6i_hwspinlock.c ++++ b/drivers/hwspinlock/sun6i_hwspinlock.c +@@ -104,14 +104,12 @@ static int sun6i_hwspinlock_probe(struct + if (!priv) + return -ENOMEM; + +- priv->ahb_clk = devm_clk_get(&pdev->dev, "ahb"); +- if (IS_ERR(priv->ahb_clk)) { +- err = PTR_ERR(priv->ahb_clk); +- dev_err(&pdev->dev, "unable to get AHB clock (%d)\n", err); +- return err; +- } ++ priv->ahb_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->ahb_clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(priv->ahb_clk), ++ "unable to get AHB clock\n"); + +- priv->reset = devm_reset_control_get(&pdev->dev, "ahb"); ++ priv->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(priv->reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset), + "unable to get reset control\n"); diff --git a/target/linux/d1/patches-6.1/0045-dt-bindings-hwlock-sun6i-Add-interrupts-property.patch b/target/linux/d1/patches-6.1/0045-dt-bindings-hwlock-sun6i-Add-interrupts-property.patch new file mode 100644 index 0000000000..d2c61a54dd --- /dev/null +++ b/target/linux/d1/patches-6.1/0045-dt-bindings-hwlock-sun6i-Add-interrupts-property.patch @@ -0,0 +1,51 @@ +From f0c29c5d370507ca2106689e7e17b81e8b58f236 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Nov 2021 11:37:34 -0600 +Subject: [PATCH 045/117] dt-bindings: hwlock: sun6i: Add interrupts property + +While it was not officially documented until recently (e.g. A50), the +hwspinlock block can trigger an interrupt when a lock is unlocked. This +capability is used by Allwinner's ARISC firmware, it has been verified +to work on A64, and the IRQ numbers are reserved as far back as A31. +So most likely this feature has always been available. + +Even though the Linux hwspinlock framework cannot make use of the IRQ, +the capability should still be documented in the device tree. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml ++++ b/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml +@@ -26,17 +26,22 @@ properties: + resets: + maxItems: 1 + ++ interrupts: ++ maxItems: 1 ++ + required: + - compatible + - reg + - clocks + - resets ++ - interrupts + + additionalProperties: false + + examples: + - | + #include <dt-bindings/clock/sun8i-a23-a33-ccu.h> ++ #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/reset/sun8i-a23-a33-ccu.h> + + hwlock@1c18000 { +@@ -44,5 +49,6 @@ examples: + reg = <0x01c18000 0x1000>; + clocks = <&ccu CLK_BUS_SPINLOCK>; + resets = <&ccu RST_BUS_SPINLOCK>; ++ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; + }; + ... diff --git a/target/linux/d1/patches-6.1/0046-dt-bindings-hwlock-sun6i-Add-per-SoC-compatibles.patch b/target/linux/d1/patches-6.1/0046-dt-bindings-hwlock-sun6i-Add-per-SoC-compatibles.patch new file mode 100644 index 0000000000..120232b51a --- /dev/null +++ b/target/linux/d1/patches-6.1/0046-dt-bindings-hwlock-sun6i-Add-per-SoC-compatibles.patch @@ -0,0 +1,39 @@ +From e7b8c42c6bf02f4c2e24b015a12cd9edad094644 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Nov 2021 12:36:52 -0600 +Subject: [PATCH 046/117] dt-bindings: hwlock: sun6i: Add per-SoC compatibles + +While all implementations of this hardware appear to be indentical, it +is possible that some difference exists. To be safe, add a compatible +for each SoC integration, using the A31 compatible only as a fallback. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../hwlock/allwinner,sun6i-a31-hwspinlock.yaml | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml ++++ b/Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml +@@ -15,7 +15,21 @@ description: + + properties: + compatible: +- const: allwinner,sun6i-a31-hwspinlock ++ oneOf: ++ - items: ++ - enum: ++ - allwinner,sun8i-a23-hwspinlock ++ - allwinner,sun8i-a33-hwspinlock ++ - allwinner,sun8i-a50-hwspinlock ++ - allwinner,sun8i-a83t-hwspinlock ++ - allwinner,sun8i-h3-hwspinlock ++ - allwinner,sun9i-a80-hwspinlock ++ - allwinner,sun20i-d1-hwspinlock ++ - allwinner,sun50i-a64-hwspinlock ++ - allwinner,sun50i-h6-hwspinlock ++ - allwinner,sun50i-r329-hwspinlock ++ - const: allwinner,sun6i-a31-hwspinlock ++ - const: allwinner,sun6i-a31-hwspinlock + + reg: + maxItems: 1 diff --git a/target/linux/d1/patches-6.1/0047-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch b/target/linux/d1/patches-6.1/0047-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch new file mode 100644 index 0000000000..c0350455c9 --- /dev/null +++ b/target/linux/d1/patches-6.1/0047-ASoC-sun4i-i2s-Also-set-capture-DMA-width.patch @@ -0,0 +1,20 @@ +From 419b337ac3e60126f9de0bc98892e54a8ffe3b6e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:50:57 -0500 +Subject: [PATCH 047/117] ASoC: sun4i-i2s: Also set capture DMA width + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-i2s.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/soc/sunxi/sun4i-i2s.c ++++ b/sound/soc/sunxi/sun4i-i2s.c +@@ -633,6 +633,7 @@ static int sun4i_i2s_hw_params(struct sn + params_physical_width(params)); + return -EINVAL; + } ++ i2s->capture_dma_data.addr_width = width; + i2s->playback_dma_data.addr_width = width; + + sr = i2s->variant->get_sr(word_size); diff --git a/target/linux/d1/patches-6.1/0048-todo.patch b/target/linux/d1/patches-6.1/0048-todo.patch new file mode 100644 index 0000000000..b06f37ea37 --- /dev/null +++ b/target/linux/d1/patches-6.1/0048-todo.patch @@ -0,0 +1,19 @@ +From dbad9a1f280b3c3e34cc133407ae057293b8aadf Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 02:34:08 -0500 +Subject: [PATCH 048/117] todo + +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -253,6 +253,7 @@ + #sound-dai-cells = <0>; + }; + ++ // TODO: how to integrate ASRC? same or separate node? + i2s2: i2s@2034000 { + compatible = "allwinner,sun20i-d1-i2s", + "allwinner,sun50i-r329-i2s"; diff --git a/target/linux/d1/patches-6.1/0049-dt-bindings-iommu-sun50i-Add-compatible-for-Allwinne.patch b/target/linux/d1/patches-6.1/0049-dt-bindings-iommu-sun50i-Add-compatible-for-Allwinne.patch new file mode 100644 index 0000000000..63ff6234c8 --- /dev/null +++ b/target/linux/d1/patches-6.1/0049-dt-bindings-iommu-sun50i-Add-compatible-for-Allwinne.patch @@ -0,0 +1,46 @@ +From 031deed1d755fc9f1e4908ef70969e1458203421 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 6 Jun 2021 10:20:38 -0500 +Subject: [PATCH 049/117] dt-bindings: iommu: sun50i: Add compatible for + Allwinner D1 + +D1 contains an IOMMU similar to the one in the H6 SoC, but the D1 +variant has no external reset signal. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../iommu/allwinner,sun50i-h6-iommu.yaml | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml ++++ b/Documentation/devicetree/bindings/iommu/allwinner,sun50i-h6-iommu.yaml +@@ -17,7 +17,9 @@ properties: + The content of the cell is the master ID. + + compatible: +- const: allwinner,sun50i-h6-iommu ++ enum: ++ - allwinner,sun20i-d1-iommu ++ - allwinner,sun50i-h6-iommu + + reg: + maxItems: 1 +@@ -37,7 +39,17 @@ required: + - reg + - interrupts + - clocks +- - resets ++ ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - allwinner,sun50i-h6-iommu ++ ++then: ++ required: ++ - resets + + additionalProperties: false + diff --git a/target/linux/d1/patches-6.1/0050-iommu-sun50i-Support-variants-without-an-external-re.patch b/target/linux/d1/patches-6.1/0050-iommu-sun50i-Support-variants-without-an-external-re.patch new file mode 100644 index 0000000000..483746a11f --- /dev/null +++ b/target/linux/d1/patches-6.1/0050-iommu-sun50i-Support-variants-without-an-external-re.patch @@ -0,0 +1,69 @@ +From 15a0487680cf506bb4b9bfee2c41b2c3176d4efa Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 27 Apr 2022 19:01:57 -0500 +Subject: [PATCH 050/117] iommu/sun50i: Support variants without an external + reset + +The IOMMU in the Allwinner D1 SoC does not have an external reset line. + +Only attempt to get the reset on hardware variants which should have one +according to the binding. And switch from the deprecated function to the +explicit "exclusive" variant. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/iommu/sun50i-iommu.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/sun50i-iommu.c ++++ b/drivers/iommu/sun50i-iommu.c +@@ -95,6 +95,10 @@ + + #define SPAGE_SIZE 4096 + ++struct sun50i_iommu_variant { ++ bool has_reset; ++}; ++ + struct sun50i_iommu { + struct iommu_device iommu; + +@@ -979,9 +983,14 @@ static irqreturn_t sun50i_iommu_irq(int + + static int sun50i_iommu_probe(struct platform_device *pdev) + { ++ const struct sun50i_iommu_variant *variant; + struct sun50i_iommu *iommu; + int ret, irq; + ++ variant = of_device_get_match_data(&pdev->dev); ++ if (!variant) ++ return -EINVAL; ++ + iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL); + if (!iommu) + return -ENOMEM; +@@ -1021,7 +1030,8 @@ static int sun50i_iommu_probe(struct pla + goto err_free_group; + } + +- iommu->reset = devm_reset_control_get(&pdev->dev, NULL); ++ if (variant->has_reset) ++ iommu->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(iommu->reset)) { + dev_err(&pdev->dev, "Couldn't get our reset line.\n"); + ret = PTR_ERR(iommu->reset); +@@ -1059,8 +1069,12 @@ err_free_cache: + return ret; + } + ++static const struct sun50i_iommu_variant sun50i_h6_iommu = { ++ .has_reset = true, ++}; ++ + static const struct of_device_id sun50i_iommu_dt[] = { +- { .compatible = "allwinner,sun50i-h6-iommu", }, ++ { .compatible = "allwinner,sun50i-h6-iommu", .data = &sun50i_h6_iommu }, + { /* sentinel */ }, + }; + MODULE_DEVICE_TABLE(of, sun50i_iommu_dt); diff --git a/target/linux/d1/patches-6.1/0051-iommu-sun50i-Ensure-bypass-is-disabled.patch b/target/linux/d1/patches-6.1/0051-iommu-sun50i-Ensure-bypass-is-disabled.patch new file mode 100644 index 0000000000..3f2db0054e --- /dev/null +++ b/target/linux/d1/patches-6.1/0051-iommu-sun50i-Ensure-bypass-is-disabled.patch @@ -0,0 +1,26 @@ +From 384e2ca3c049fe36f4e679fc76fcc8dfdc9297f9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 27 Apr 2022 19:06:28 -0500 +Subject: [PATCH 051/117] iommu/sun50i: Ensure bypass is disabled + +The H6 variant of the hardware disables bypass by default. The D1 +variant of the hardware enables bypass for all masters by default. + +Since the driver expects bypass to be disabled, ensure that is the case. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/iommu/sun50i-iommu.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/iommu/sun50i-iommu.c ++++ b/drivers/iommu/sun50i-iommu.c +@@ -445,6 +445,8 @@ static int sun50i_iommu_enable(struct su + + spin_lock_irqsave(&iommu->iommu_lock, flags); + ++ iommu_write(iommu, IOMMU_BYPASS_REG, 0); ++ + iommu_write(iommu, IOMMU_TTB_REG, sun50i_domain->dt_dma); + iommu_write(iommu, IOMMU_TLB_PREFETCH_REG, + IOMMU_TLB_PREFETCH_MASTER_ENABLE(0) | diff --git a/target/linux/d1/patches-6.1/0052-iommu-sun50i-Add-support-for-the-D1-variant.patch b/target/linux/d1/patches-6.1/0052-iommu-sun50i-Add-support-for-the-D1-variant.patch new file mode 100644 index 0000000000..d82542a4a2 --- /dev/null +++ b/target/linux/d1/patches-6.1/0052-iommu-sun50i-Add-support-for-the-D1-variant.patch @@ -0,0 +1,32 @@ +From 5fdd5231c56d58f16a6cefa2bed4b8f331da2c92 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 27 Apr 2022 19:20:58 -0500 +Subject: [PATCH 052/117] iommu/sun50i: Add support for the D1 variant + +D1 contains an IOMMU similar to the one in the H6 SoC, but the D1 +variant has no external reset signal. It also has some register +definition changes, but none that affect the current driver. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/iommu/sun50i-iommu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/iommu/sun50i-iommu.c ++++ b/drivers/iommu/sun50i-iommu.c +@@ -1071,11 +1071,15 @@ err_free_cache: + return ret; + } + ++static const struct sun50i_iommu_variant sun20i_d1_iommu = { ++}; ++ + static const struct sun50i_iommu_variant sun50i_h6_iommu = { + .has_reset = true, + }; + + static const struct of_device_id sun50i_iommu_dt[] = { ++ { .compatible = "allwinner,sun20i-d1-iommu", .data = &sun20i_d1_iommu }, + { .compatible = "allwinner,sun50i-h6-iommu", .data = &sun50i_h6_iommu }, + { /* sentinel */ }, + }; diff --git a/target/linux/d1/patches-6.1/0053-riscv-dts-allwinner-d1-Add-IOMMU-node.patch b/target/linux/d1/patches-6.1/0053-riscv-dts-allwinner-d1-Add-IOMMU-node.patch new file mode 100644 index 0000000000..b3a2d53c24 --- /dev/null +++ b/target/linux/d1/patches-6.1/0053-riscv-dts-allwinner-d1-Add-IOMMU-node.patch @@ -0,0 +1,43 @@ +From 4c37ac95ee354857c8c662b6b7b4bc50eea23206 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Aug 2022 11:20:37 -0500 +Subject: [PATCH 053/117] riscv: dts: allwinner: d1: Add IOMMU node + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -188,6 +188,14 @@ + status = "disabled"; + }; + ++ iommu: iommu@2010000 { ++ compatible = "allwinner,sun20i-d1-iommu"; ++ reg = <0x2010000 0x10000>; ++ interrupts = <80 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_IOMMU>; ++ #iommu-cells = <1>; ++ }; ++ + codec: audio-codec@2030000 { + compatible = "simple-mfd", "syscon"; + reg = <0x2030000 0x1000>; +@@ -681,6 +689,7 @@ + <&display_clocks CLK_MIXER0>; + clock-names = "bus", "mod"; + resets = <&display_clocks RST_MIXER0>; ++ iommus = <&iommu 2>; + + ports { + #address-cells = <1>; +@@ -703,6 +712,7 @@ + <&display_clocks CLK_MIXER1>; + clock-names = "bus", "mod"; + resets = <&display_clocks RST_MIXER1>; ++ iommus = <&iommu 2>; + + ports { + #address-cells = <1>; diff --git a/target/linux/d1/patches-6.1/0054-dt-bindings-leds-Add-Allwinner-A100-LED-controller.patch b/target/linux/d1/patches-6.1/0054-dt-bindings-leds-Add-Allwinner-A100-LED-controller.patch new file mode 100644 index 0000000000..548a92efb5 --- /dev/null +++ b/target/linux/d1/patches-6.1/0054-dt-bindings-leds-Add-Allwinner-A100-LED-controller.patch @@ -0,0 +1,179 @@ +From 31857adcc9db7244a047a3a3550219f7559d8846 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 4 Aug 2021 21:36:26 -0500 +Subject: [PATCH 054/117] dt-bindings: leds: Add Allwinner A100 LED controller + +The Allwinner A100, R329, and D1 SoCs contain an LED controller designed +to drive a series of RGB LED pixels. It supports PIO and DMA transfers, +and has configurable timing and pixel format. All three implementations +appear to be identical, so use the oldest as the fallback compatible. + +Series-changes: 2 + - Fixed typo leading to duplicate t1h-ns property + - Removed "items" layer in definition of dmas/dma-names + - Replaced uint32 type reference with maxItems in timing properties + +Series-changes: 3 + - Removed quotes from enumeration values + - Added vendor prefix to timing/format properties + - Renamed "format" property to "pixel-format" for clarity + - Dropped "vled-supply" as it is unrelated to the controller hardware + +Series-changes: 4 + - Use "default" instead of "maxItems" for timing properties + +Series-changes: 5 + - A100 contains the original implementation, so use that as the base + compatible string, and rename the binding to match + - Add "unevaluatedProperties: false" to the child multi-led binding + +Acked-by: Maxime Ripard <maxime@cerno.tech> +Reviewed-by: Rob Herring <robh@kernel.org> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../leds/allwinner,sun50i-a100-ledc.yaml | 139 ++++++++++++++++++ + 1 file changed, 139 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml +@@ -0,0 +1,139 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/leds/allwinner,sun50i-a100-ledc.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Allwinner A100 LED Controller Bindings ++ ++maintainers: ++ - Samuel Holland <samuel@sholland.org> ++ ++description: ++ The LED controller found in Allwinner sunxi SoCs uses a one-wire serial ++ interface to drive up to 1024 RGB LEDs. ++ ++properties: ++ compatible: ++ oneOf: ++ - const: allwinner,sun50i-a100-ledc ++ - items: ++ - enum: ++ - allwinner,sun20i-d1-ledc ++ - allwinner,sun50i-r329-ledc ++ - const: allwinner,sun50i-a100-ledc ++ ++ reg: ++ maxItems: 1 ++ ++ "#address-cells": ++ const: 1 ++ ++ "#size-cells": ++ const: 0 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: Bus clock ++ - description: Module clock ++ ++ clock-names: ++ items: ++ - const: bus ++ - const: mod ++ ++ resets: ++ maxItems: 1 ++ ++ dmas: ++ maxItems: 1 ++ description: TX DMA channel ++ ++ dma-names: ++ const: tx ++ ++ allwinner,pixel-format: ++ description: Pixel format (subpixel transmission order), default is "grb" ++ enum: ++ - bgr ++ - brg ++ - gbr ++ - grb ++ - rbg ++ - rgb ++ ++ allwinner,t0h-ns: ++ default: 336 ++ description: Length of high pulse when transmitting a "0" bit ++ ++ allwinner,t0l-ns: ++ default: 840 ++ description: Length of low pulse when transmitting a "0" bit ++ ++ allwinner,t1h-ns: ++ default: 882 ++ description: Length of high pulse when transmitting a "1" bit ++ ++ allwinner,t1l-ns: ++ default: 294 ++ description: Length of low pulse when transmitting a "1" bit ++ ++ allwinner,treset-ns: ++ default: 300000 ++ description: Minimum delay between transmission frames ++ ++patternProperties: ++ "^multi-led@[0-9a-f]+$": ++ type: object ++ $ref: leds-class-multicolor.yaml# ++ unevaluatedProperties: false ++ properties: ++ reg: ++ minimum: 0 ++ maximum: 1023 ++ description: Index of the LED in the series (must be contiguous) ++ ++ required: ++ - reg ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ - resets ++ - dmas ++ - dma-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include <dt-bindings/interrupt-controller/irq.h> ++ #include <dt-bindings/leds/common.h> ++ ++ ledc: led-controller@2008000 { ++ compatible = "allwinner,sun20i-d1-ledc", ++ "allwinner,sun50i-a100-ledc"; ++ reg = <0x2008000 0x400>; ++ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu 12>, <&ccu 34>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu 12>; ++ dmas = <&dma 42>; ++ dma-names = "tx"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ multi-led@0 { ++ reg = <0x0>; ++ color = <LED_COLOR_ID_RGB>; ++ function = LED_FUNCTION_INDICATOR; ++ }; ++ }; ++ ++... diff --git a/target/linux/d1/patches-6.1/0055-leds-sun50i-a100-New-driver-for-the-A100-LED-control.patch b/target/linux/d1/patches-6.1/0055-leds-sun50i-a100-New-driver-for-the-A100-LED-control.patch new file mode 100644 index 0000000000..4c2cab557a --- /dev/null +++ b/target/linux/d1/patches-6.1/0055-leds-sun50i-a100-New-driver-for-the-A100-LED-control.patch @@ -0,0 +1,620 @@ +From 352b296d30df06b880d2c7620910cd759dc2609d Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 26 Jun 2021 11:02:49 -0500 +Subject: [PATCH 055/117] leds: sun50i-a100: New driver for the A100 LED + controller + +Some Allwinner sunxi SoCs, starting with the A100, contain an LED +controller designed to drive RGB LED pixels. Add a driver for it using +the multicolor LED framework, and with LEDs defined in the device tree. + +Series-changes: 2 + - Renamed from sunxi-ledc to sun50i-r329-ledc + - Added missing "static" to functions/globals as reported by 0day bot + +Series-changes: 3 + - Added vendor prefix to timing/format properties + - Renamed "format" property to "pixel-format" for clarity + - Dropped "vled-supply" as it is unrelated to the controller hardware + - Changed "writesl" to "iowrite32_rep" so the driver builds on hppa + +Series-changes: 4 + - Depend on LEDS_CLASS_MULTICOLOR + +Series-changes: 5 + - Rename the driver R329 -> A100, since that is the actual original + implementation + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/leds/Kconfig | 9 + + drivers/leds/Makefile | 1 + + drivers/leds/leds-sun50i-a100.c | 554 ++++++++++++++++++++++++++++++++ + 3 files changed, 564 insertions(+) + create mode 100644 drivers/leds/leds-sun50i-a100.c + +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -283,6 +283,15 @@ config LEDS_COBALT_RAQ + help + This option enables support for the Cobalt Raq series LEDs. + ++config LEDS_SUN50I_A100 ++ tristate "LED support for Allwinner A100 RGB LED controller" ++ depends on LEDS_CLASS_MULTICOLOR && OF ++ depends on ARCH_SUNXI || COMPILE_TEST ++ help ++ This option enables support for the RGB LED controller found ++ in some Allwinner sunxi SoCs, includeing A100, R329, and D1. ++ It uses a one-wire interface to control up to 1024 LEDs. ++ + config LEDS_SUNFIRE + tristate "LED support for SunFire servers." + depends on LEDS_CLASS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -76,6 +76,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o ++obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o + obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o + obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o +--- /dev/null ++++ b/drivers/leds/leds-sun50i-a100.c +@@ -0,0 +1,554 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Copyright (c) 2021-2022 Samuel Holland <samuel@sholland.org> ++// ++// Partly based on drivers/leds/leds-turris-omnia.c, which is: ++// Copyright (c) 2020 by Marek Behún <kabel@kernel.org> ++// ++ ++#include <linux/clk.h> ++#include <linux/dma-mapping.h> ++#include <linux/dmaengine.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/led-class-multicolor.h> ++#include <linux/leds.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/pm.h> ++#include <linux/reset.h> ++#include <linux/spinlock.h> ++ ++#define LEDC_CTRL_REG 0x0000 ++#define LEDC_CTRL_REG_DATA_LENGTH (0x1fff << 16) ++#define LEDC_CTRL_REG_RGB_MODE (0x7 << 6) ++#define LEDC_CTRL_REG_LEDC_EN BIT(0) ++#define LEDC_T01_TIMING_CTRL_REG 0x0004 ++#define LEDC_T01_TIMING_CTRL_REG_T1H (0x3f << 21) ++#define LEDC_T01_TIMING_CTRL_REG_T1L (0x1f << 16) ++#define LEDC_T01_TIMING_CTRL_REG_T0H (0x1f << 6) ++#define LEDC_T01_TIMING_CTRL_REG_T0L (0x3f << 0) ++#define LEDC_RESET_TIMING_CTRL_REG 0x000c ++#define LEDC_RESET_TIMING_CTRL_REG_LED_NUM (0x3ff << 0) ++#define LEDC_DATA_REG 0x0014 ++#define LEDC_DMA_CTRL_REG 0x0018 ++#define LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL (0x1f << 0) ++#define LEDC_INT_CTRL_REG 0x001c ++#define LEDC_INT_CTRL_REG_GLOBAL_INT_EN BIT(5) ++#define LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN BIT(1) ++#define LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN BIT(0) ++#define LEDC_INT_STS_REG 0x0020 ++#define LEDC_INT_STS_REG_FIFO_CPUREQ_INT BIT(1) ++#define LEDC_INT_STS_REG_TRANS_FINISH_INT BIT(0) ++ ++#define LEDC_FIFO_DEPTH 32 ++#define LEDC_MAX_LEDS 1024 ++ ++#define LEDS_TO_BYTES(n) ((n) * sizeof(u32)) ++ ++struct sun50i_a100_ledc_led { ++ struct led_classdev_mc mc_cdev; ++ struct mc_subled subled_info[3]; ++}; ++ ++#define to_ledc_led(mc) container_of(mc, struct sun50i_a100_ledc_led, mc_cdev) ++ ++struct sun50i_a100_ledc_timing { ++ u32 t0h_ns; ++ u32 t0l_ns; ++ u32 t1h_ns; ++ u32 t1l_ns; ++ u32 treset_ns; ++}; ++ ++struct sun50i_a100_ledc { ++ struct device *dev; ++ void __iomem *base; ++ struct clk *bus_clk; ++ struct clk *mod_clk; ++ struct reset_control *reset; ++ ++ u32 *buffer; ++ struct dma_chan *dma_chan; ++ dma_addr_t dma_handle; ++ int pio_length; ++ int pio_offset; ++ ++ spinlock_t lock; ++ int next_length; ++ bool xfer_active; ++ ++ u32 format; ++ struct sun50i_a100_ledc_timing timing; ++ ++ int num_leds; ++ struct sun50i_a100_ledc_led leds[]; ++}; ++ ++static int sun50i_a100_ledc_dma_xfer(struct sun50i_a100_ledc *priv, int length) ++{ ++ struct dma_async_tx_descriptor *desc; ++ dma_cookie_t cookie; ++ ++ desc = dmaengine_prep_slave_single(priv->dma_chan, priv->dma_handle, ++ LEDS_TO_BYTES(length), ++ DMA_MEM_TO_DEV, 0); ++ if (!desc) ++ return -ENOMEM; ++ ++ cookie = dmaengine_submit(desc); ++ if (dma_submit_error(cookie)) ++ return -EIO; ++ ++ dma_async_issue_pending(priv->dma_chan); ++ ++ return 0; ++} ++ ++static void sun50i_a100_ledc_pio_xfer(struct sun50i_a100_ledc *priv, int length) ++{ ++ u32 burst, offset, val; ++ ++ if (length) { ++ /* New transfer (FIFO is empty). */ ++ offset = 0; ++ burst = min(length, LEDC_FIFO_DEPTH); ++ } else { ++ /* Existing transfer (FIFO is half-full). */ ++ length = priv->pio_length; ++ offset = priv->pio_offset; ++ burst = min(length, LEDC_FIFO_DEPTH / 2); ++ } ++ ++ iowrite32_rep(priv->base + LEDC_DATA_REG, priv->buffer + offset, burst); ++ ++ if (burst < length) { ++ priv->pio_length = length - burst; ++ priv->pio_offset = offset + burst; ++ ++ if (!offset) { ++ val = readl(priv->base + LEDC_INT_CTRL_REG); ++ val |= LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN; ++ writel(val, priv->base + LEDC_INT_CTRL_REG); ++ } ++ } else { ++ /* Disable the request IRQ once all data is written. */ ++ val = readl(priv->base + LEDC_INT_CTRL_REG); ++ val &= ~LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN; ++ writel(val, priv->base + LEDC_INT_CTRL_REG); ++ } ++} ++ ++static void sun50i_a100_ledc_start_xfer(struct sun50i_a100_ledc *priv, ++ int length) ++{ ++ u32 val; ++ ++ dev_dbg(priv->dev, "Updating %d LEDs\n", length); ++ ++ val = readl(priv->base + LEDC_CTRL_REG); ++ val &= ~LEDC_CTRL_REG_DATA_LENGTH; ++ val |= length << 16 | LEDC_CTRL_REG_LEDC_EN; ++ writel(val, priv->base + LEDC_CTRL_REG); ++ ++ if (length > LEDC_FIFO_DEPTH) { ++ int ret = sun50i_a100_ledc_dma_xfer(priv, length); ++ ++ if (!ret) ++ return; ++ ++ dev_warn(priv->dev, "Failed to set up DMA: %d\n", ret); ++ } ++ ++ sun50i_a100_ledc_pio_xfer(priv, length); ++} ++ ++static irqreturn_t sun50i_a100_ledc_irq(int irq, void *dev_id) ++{ ++ struct sun50i_a100_ledc *priv = dev_id; ++ u32 val; ++ ++ val = readl(priv->base + LEDC_INT_STS_REG); ++ ++ if (val & LEDC_INT_STS_REG_TRANS_FINISH_INT) { ++ int next_length; ++ ++ /* Start the next transfer if needed. */ ++ spin_lock(&priv->lock); ++ next_length = priv->next_length; ++ if (next_length) ++ priv->next_length = 0; ++ else ++ priv->xfer_active = false; ++ spin_unlock(&priv->lock); ++ ++ if (next_length) ++ sun50i_a100_ledc_start_xfer(priv, next_length); ++ } else if (val & LEDC_INT_STS_REG_FIFO_CPUREQ_INT) { ++ /* Continue the current transfer. */ ++ sun50i_a100_ledc_pio_xfer(priv, 0); ++ } ++ ++ writel(val, priv->base + LEDC_INT_STS_REG); ++ ++ return IRQ_HANDLED; ++} ++ ++static void sun50i_a100_ledc_brightness_set(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct sun50i_a100_ledc *priv = dev_get_drvdata(cdev->dev->parent); ++ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); ++ struct sun50i_a100_ledc_led *led = to_ledc_led(mc_cdev); ++ int addr = led - priv->leds; ++ unsigned long flags; ++ bool xfer_active; ++ int next_length; ++ ++ led_mc_calc_color_components(mc_cdev, brightness); ++ ++ priv->buffer[addr] = led->subled_info[0].brightness << 16 | ++ led->subled_info[1].brightness << 8 | ++ led->subled_info[2].brightness; ++ ++ dev_dbg(priv->dev, "LED %d -> #%06x\n", addr, priv->buffer[addr]); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ next_length = max(priv->next_length, addr + 1); ++ xfer_active = priv->xfer_active; ++ if (xfer_active) ++ priv->next_length = next_length; ++ else ++ priv->xfer_active = true; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (!xfer_active) ++ sun50i_a100_ledc_start_xfer(priv, next_length); ++} ++ ++static const char *const sun50i_a100_ledc_formats[] = { ++ "rgb", ++ "rbg", ++ "grb", ++ "gbr", ++ "brg", ++ "bgr", ++}; ++ ++static int sun50i_a100_ledc_parse_format(const struct device_node *np, ++ struct sun50i_a100_ledc *priv) ++{ ++ const char *format = "grb"; ++ u32 i; ++ ++ of_property_read_string(np, "allwinner,pixel-format", &format); ++ ++ for (i = 0; i < ARRAY_SIZE(sun50i_a100_ledc_formats); ++i) { ++ if (!strcmp(format, sun50i_a100_ledc_formats[i])) { ++ priv->format = i; ++ return 0; ++ } ++ } ++ ++ dev_err(priv->dev, "Bad pixel format '%s'\n", format); ++ ++ return -EINVAL; ++} ++ ++static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv) ++{ ++ u32 val; ++ ++ val = readl(priv->base + LEDC_CTRL_REG); ++ val &= ~LEDC_CTRL_REG_RGB_MODE; ++ val |= priv->format << 6; ++ writel(val, priv->base + LEDC_CTRL_REG); ++} ++ ++static const struct sun50i_a100_ledc_timing sun50i_a100_ledc_default_timing = { ++ .t0h_ns = 336, ++ .t0l_ns = 840, ++ .t1h_ns = 882, ++ .t1l_ns = 294, ++ .treset_ns = 300000, ++}; ++ ++static int sun50i_a100_ledc_parse_timing(const struct device_node *np, ++ struct sun50i_a100_ledc *priv) ++{ ++ struct sun50i_a100_ledc_timing *timing = &priv->timing; ++ ++ *timing = sun50i_a100_ledc_default_timing; ++ ++ of_property_read_u32(np, "allwinner,t0h-ns", &timing->t0h_ns); ++ of_property_read_u32(np, "allwinner,t0l-ns", &timing->t0l_ns); ++ of_property_read_u32(np, "allwinner,t1h-ns", &timing->t1h_ns); ++ of_property_read_u32(np, "allwinner,t1l-ns", &timing->t1l_ns); ++ of_property_read_u32(np, "allwinner,treset-ns", &timing->treset_ns); ++ ++ return 0; ++} ++ ++static void sun50i_a100_ledc_set_timing(struct sun50i_a100_ledc *priv) ++{ ++ const struct sun50i_a100_ledc_timing *timing = &priv->timing; ++ unsigned long mod_freq = clk_get_rate(priv->mod_clk); ++ u32 cycle_ns = NSEC_PER_SEC / mod_freq; ++ u32 val; ++ ++ val = (timing->t1h_ns / cycle_ns) << 21 | ++ (timing->t1l_ns / cycle_ns) << 16 | ++ (timing->t0h_ns / cycle_ns) << 6 | ++ (timing->t0l_ns / cycle_ns); ++ writel(val, priv->base + LEDC_T01_TIMING_CTRL_REG); ++ ++ val = (timing->treset_ns / cycle_ns) << 16 | ++ (priv->num_leds - 1); ++ writel(val, priv->base + LEDC_RESET_TIMING_CTRL_REG); ++} ++ ++static int sun50i_a100_ledc_resume(struct device *dev) ++{ ++ struct sun50i_a100_ledc *priv = dev_get_drvdata(dev); ++ u32 val; ++ int ret; ++ ++ ret = reset_control_deassert(priv->reset); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(priv->bus_clk); ++ if (ret) ++ goto err_assert_reset; ++ ++ ret = clk_prepare_enable(priv->mod_clk); ++ if (ret) ++ goto err_disable_bus_clk; ++ ++ sun50i_a100_ledc_set_format(priv); ++ sun50i_a100_ledc_set_timing(priv); ++ ++ /* The trigger level must be at least the burst length. */ ++ val = readl(priv->base + LEDC_DMA_CTRL_REG); ++ val &= ~LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL; ++ val |= LEDC_FIFO_DEPTH / 2; ++ writel(val, priv->base + LEDC_DMA_CTRL_REG); ++ ++ val = LEDC_INT_CTRL_REG_GLOBAL_INT_EN | ++ LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN; ++ writel(val, priv->base + LEDC_INT_CTRL_REG); ++ ++ return 0; ++ ++err_disable_bus_clk: ++ clk_disable_unprepare(priv->bus_clk); ++err_assert_reset: ++ reset_control_assert(priv->reset); ++ ++ return ret; ++} ++ ++static int sun50i_a100_ledc_suspend(struct device *dev) ++{ ++ struct sun50i_a100_ledc *priv = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(priv->mod_clk); ++ clk_disable_unprepare(priv->bus_clk); ++ reset_control_assert(priv->reset); ++ ++ return 0; ++} ++ ++static void sun50i_a100_ledc_dma_cleanup(void *data) ++{ ++ struct sun50i_a100_ledc *priv = data; ++ struct device *dma_dev = dmaengine_get_dma_device(priv->dma_chan); ++ ++ if (priv->buffer) ++ dma_free_wc(dma_dev, LEDS_TO_BYTES(priv->num_leds), ++ priv->buffer, priv->dma_handle); ++ dma_release_channel(priv->dma_chan); ++} ++ ++static int sun50i_a100_ledc_probe(struct platform_device *pdev) ++{ ++ const struct device_node *np = pdev->dev.of_node; ++ struct dma_slave_config dma_cfg = {}; ++ struct led_init_data init_data = {}; ++ struct device *dev = &pdev->dev; ++ struct device_node *child; ++ struct sun50i_a100_ledc *priv; ++ struct resource *mem; ++ int count, irq, ret; ++ ++ count = of_get_available_child_count(np); ++ if (!count) ++ return -ENODEV; ++ if (count > LEDC_MAX_LEDS) { ++ dev_err(dev, "Too many LEDs! (max is %d)\n", LEDC_MAX_LEDS); ++ return -EINVAL; ++ } ++ ++ priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ priv->num_leds = count; ++ spin_lock_init(&priv->lock); ++ dev_set_drvdata(dev, priv); ++ ++ ret = sun50i_a100_ledc_parse_format(np, priv); ++ if (ret) ++ return ret; ++ ++ ret = sun50i_a100_ledc_parse_timing(np, priv); ++ if (ret) ++ return ret; ++ ++ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ priv->bus_clk = devm_clk_get(dev, "bus"); ++ if (IS_ERR(priv->bus_clk)) ++ return PTR_ERR(priv->bus_clk); ++ ++ priv->mod_clk = devm_clk_get(dev, "mod"); ++ if (IS_ERR(priv->mod_clk)) ++ return PTR_ERR(priv->mod_clk); ++ ++ priv->reset = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(priv->reset)) ++ return PTR_ERR(priv->reset); ++ ++ priv->dma_chan = dma_request_chan(dev, "tx"); ++ if (IS_ERR(priv->dma_chan)) ++ return PTR_ERR(priv->dma_chan); ++ ++ ret = devm_add_action_or_reset(dev, sun50i_a100_ledc_dma_cleanup, priv); ++ if (ret) ++ return ret; ++ ++ dma_cfg.dst_addr = mem->start + LEDC_DATA_REG; ++ dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dma_cfg.dst_maxburst = LEDC_FIFO_DEPTH / 2; ++ ret = dmaengine_slave_config(priv->dma_chan, &dma_cfg); ++ if (ret) ++ return ret; ++ ++ priv->buffer = dma_alloc_wc(dmaengine_get_dma_device(priv->dma_chan), ++ LEDS_TO_BYTES(priv->num_leds), ++ &priv->dma_handle, GFP_KERNEL); ++ if (!priv->buffer) ++ return -ENOMEM; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_irq(dev, irq, sun50i_a100_ledc_irq, ++ 0, dev_name(dev), priv); ++ if (ret) ++ return ret; ++ ++ ret = sun50i_a100_ledc_resume(dev); ++ if (ret) ++ return ret; ++ ++ for_each_available_child_of_node(np, child) { ++ struct sun50i_a100_ledc_led *led; ++ struct led_classdev *cdev; ++ u32 addr, color; ++ ++ ret = of_property_read_u32(child, "reg", &addr); ++ if (ret || addr >= count) { ++ dev_err(dev, "LED 'reg' values must be from 0 to %d\n", ++ priv->num_leds - 1); ++ ret = -EINVAL; ++ goto err_put_child; ++ } ++ ++ ret = of_property_read_u32(child, "color", &color); ++ if (ret || color != LED_COLOR_ID_RGB) { ++ dev_err(dev, "LED 'color' must be LED_COLOR_ID_RGB\n"); ++ ret = -EINVAL; ++ goto err_put_child; ++ } ++ ++ led = &priv->leds[addr]; ++ ++ led->subled_info[0].color_index = LED_COLOR_ID_RED; ++ led->subled_info[0].channel = 0; ++ led->subled_info[1].color_index = LED_COLOR_ID_GREEN; ++ led->subled_info[1].channel = 1; ++ led->subled_info[2].color_index = LED_COLOR_ID_BLUE; ++ led->subled_info[2].channel = 2; ++ ++ led->mc_cdev.num_colors = ARRAY_SIZE(led->subled_info); ++ led->mc_cdev.subled_info = led->subled_info; ++ ++ cdev = &led->mc_cdev.led_cdev; ++ cdev->max_brightness = U8_MAX; ++ cdev->brightness_set = sun50i_a100_ledc_brightness_set; ++ ++ init_data.fwnode = of_fwnode_handle(child); ++ ++ ret = devm_led_classdev_multicolor_register_ext(dev, ++ &led->mc_cdev, ++ &init_data); ++ if (ret) { ++ dev_err(dev, "Failed to register LED %u: %d\n", ++ addr, ret); ++ goto err_put_child; ++ } ++ } ++ ++ dev_info(dev, "Registered %d LEDs\n", priv->num_leds); ++ ++ return 0; ++ ++err_put_child: ++ of_node_put(child); ++ sun50i_a100_ledc_suspend(&pdev->dev); ++ ++ return ret; ++} ++ ++static int sun50i_a100_ledc_remove(struct platform_device *pdev) ++{ ++ sun50i_a100_ledc_suspend(&pdev->dev); ++ ++ return 0; ++} ++ ++static void sun50i_a100_ledc_shutdown(struct platform_device *pdev) ++{ ++ sun50i_a100_ledc_suspend(&pdev->dev); ++} ++ ++static const struct of_device_id sun50i_a100_ledc_of_match[] = { ++ { .compatible = "allwinner,sun50i-a100-ledc" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, sun50i_a100_ledc_of_match); ++ ++static SIMPLE_DEV_PM_OPS(sun50i_a100_ledc_pm, ++ sun50i_a100_ledc_suspend, sun50i_a100_ledc_resume); ++ ++static struct platform_driver sun50i_a100_ledc_driver = { ++ .probe = sun50i_a100_ledc_probe, ++ .remove = sun50i_a100_ledc_remove, ++ .shutdown = sun50i_a100_ledc_shutdown, ++ .driver = { ++ .name = "sun50i-a100-ledc", ++ .of_match_table = sun50i_a100_ledc_of_match, ++ .pm = pm_ptr(&sun50i_a100_ledc_pm), ++ }, ++}; ++module_platform_driver(sun50i_a100_ledc_driver); ++ ++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); ++MODULE_DESCRIPTION("Allwinner A100 LED controller driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/d1/patches-6.1/0056-arm64-dts-allwinner-a100-Add-LED-controller-node.patch b/target/linux/d1/patches-6.1/0056-arm64-dts-allwinner-a100-Add-LED-controller-node.patch new file mode 100644 index 0000000000..92fa2a31ee --- /dev/null +++ b/target/linux/d1/patches-6.1/0056-arm64-dts-allwinner-a100-Add-LED-controller-node.patch @@ -0,0 +1,38 @@ +From 0040f071ab45d3098b2aad7e28e07593a5740782 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 25 Aug 2022 23:19:40 -0500 +Subject: [PATCH 056/117] arm64: dts: allwinner: a100: Add LED controller node + +Allwinner A100 contains an LED controller. Add it to the devicetree. + +Commit-changes: 5 + - New patch for v5 + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi +@@ -273,6 +273,20 @@ + #size-cells = <0>; + }; + ++ ledc: led-controller@5018000 { ++ compatible = "allwinner,sun50i-a100-ledc"; ++ reg = <0x5018000 0x400>; ++ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_LEDC>, <&ccu CLK_LEDC>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_LEDC>; ++ dmas = <&dma 42>; ++ dma-names = "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ + ths: thermal-sensor@5070400 { + compatible = "allwinner,sun50i-a100-ths"; + reg = <0x05070400 0x100>; diff --git a/target/linux/d1/patches-6.1/0057-riscv-dts-allwinner-d1-Add-LED-controller-node.patch b/target/linux/d1/patches-6.1/0057-riscv-dts-allwinner-d1-Add-LED-controller-node.patch new file mode 100644 index 0000000000..f6a04113b1 --- /dev/null +++ b/target/linux/d1/patches-6.1/0057-riscv-dts-allwinner-d1-Add-LED-controller-node.patch @@ -0,0 +1,53 @@ +From 595f76548e1d51a76b1ab201293ef441233921cf Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 23:02:43 -0500 +Subject: [PATCH 057/117] riscv: dts: allwinner: d1: Add LED controller node + +Allwinner D1 contains an LED controller. Add its devicetree node, as +well as the pinmux used by the reference board design. + +Commit-changes: 5 + - New patch for v5 + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 21 ++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -116,6 +116,12 @@ + }; + + /omit-if-no-ref/ ++ ledc_pc0_pin: ledc-pc0-pin { ++ pins = "PC0"; ++ function = "ledc"; ++ }; ++ ++ /omit-if-no-ref/ + mmc0_pins: mmc0-pins { + pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; + function = "mmc0"; +@@ -178,6 +184,21 @@ + #reset-cells = <1>; + }; + ++ ledc: led-controller@2008000 { ++ compatible = "allwinner,sun20i-d1-ledc", ++ "allwinner,sun50i-a100-ledc"; ++ reg = <0x2008000 0x400>; ++ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_LEDC>, <&ccu CLK_LEDC>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_LEDC>; ++ dmas = <&dma 42>; ++ dma-names = "tx"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ + lradc: keys@2009800 { + compatible = "allwinner,sun20i-d1-lradc", + "allwinner,sun50i-r329-lradc"; diff --git a/target/linux/d1/patches-6.1/0058-riscv-dts-allwinner-d1-Add-RGB-LEDs-to-boards.patch b/target/linux/d1/patches-6.1/0058-riscv-dts-allwinner-d1-Add-RGB-LEDs-to-boards.patch new file mode 100644 index 0000000000..901cb0daf8 --- /dev/null +++ b/target/linux/d1/patches-6.1/0058-riscv-dts-allwinner-d1-Add-RGB-LEDs-to-boards.patch @@ -0,0 +1,98 @@ +From e6eb041b2099ec3d07a4ec391a06e86d7697c9d1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 23:03:01 -0500 +Subject: [PATCH 058/117] riscv: dts: allwinner: d1: Add RGB LEDs to boards + +Some D1-based boards feature an onboard RGB LED. Enable them. + +Commit-changes: 5 + - New patch for v5 + +Series-version: 5 + +Series-to: Pavel Machek <pavel@ucw.cz> +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> +Series-to: linux-leds@vger.kernel.org +Series-cc: Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org> +Series-cc: Rob Herring <robh+dt@kernel.org> +Series-cc: devicetree@vger.kernel.org +Series-cc: linux-arm-kernel@lists.infradead.org +Series-cc: linux-kernel@vger.kernel.org +Series-cc: linux-riscv@lists.infradead.org +Series-cc: linux-sunxi@lists.linux.dev + +Cover-letter: +leds: Allwinner A100 LED controller support +This series adds bindings and a driver for the RGB LED controller found +in some Allwinner SoCs, starting with A100. The hardware in the R329 and +D1 SoCs appears to be identical. + +Patch 3 is included because the LED controller binding requires the DMA +properties. That patch was sent previously[1], but never got merged. + +Patches 5-6 depend on the D1 devicetree series[2], but the rest of this +series can be merged without them. + +This driver was tested on the D1 Nezha board. + +[1]: https://lore.kernel.org/linux-arm-kernel/20201110040553.1381-7-frank@allwinnertech.com/ +[2]: https://lore.kernel.org/linux-riscv/20220815050815.22340-1-samuel@sholland.org/ +END + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts | 12 ++++++++++++ + arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts | 13 +++++++++++++ + 2 files changed, 25 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts +@@ -58,6 +58,18 @@ + status = "okay"; + }; + ++&ledc { ++ pinctrl-0 = <&ledc_pc0_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ multi-led@0 { ++ reg = <0x0>; ++ color = <LED_COLOR_ID_RGB>; ++ function = LED_FUNCTION_STATUS; ++ }; ++}; ++ + &lradc { + status = "okay"; + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts +@@ -5,6 +5,7 @@ + + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/input/input.h> ++#include <dt-bindings/leds/common.h> + + #include "sun20i-d1.dtsi" + #include "sun20i-d1-common-regulators.dtsi" +@@ -90,6 +91,18 @@ + }; + }; + ++&ledc { ++ pinctrl-0 = <&ledc_pc0_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ multi-led@0 { ++ reg = <0x0>; ++ color = <LED_COLOR_ID_RGB>; ++ function = LED_FUNCTION_STATUS; ++ }; ++}; ++ + &lradc { + status = "okay"; + diff --git a/target/linux/d1/patches-6.1/0059-pwm-sun8i-v536-document-device-tree-bindings.patch b/target/linux/d1/patches-6.1/0059-pwm-sun8i-v536-document-device-tree-bindings.patch new file mode 100644 index 0000000000..4ec15bce0c --- /dev/null +++ b/target/linux/d1/patches-6.1/0059-pwm-sun8i-v536-document-device-tree-bindings.patch @@ -0,0 +1,40 @@ +From effa2ef8717b0390e8fb0648e16df1b43610af53 Mon Sep 17 00:00:00 2001 +From: Ban Tao <fengzheng923@gmail.com> +Date: Tue, 2 Mar 2021 20:40:23 +0800 +Subject: [PATCH 059/117] pwm: sun8i-v536: document device tree bindings + +This adds binding documentation for sun8i-v536 SoC PWM driver. + +Signed-off-by: Ban Tao <fengzheng923@gmail.com> +--- + .../bindings/pwm/pwm-sun8i-v536.txt | 24 +++++++++++++++++++ + 1 file changed, 24 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/pwm-sun8i-v536.txt +@@ -0,0 +1,24 @@ ++Allwinner sun8i-v536 SoC PWM controller ++ ++Required properties: ++ - compatible: should be "allwinner,<name>-pwm" ++ "allwinner,sun8i-v833-pwm" ++ "allwinner,sun8i-v536-pwm" ++ "allwinner,sun50i-r818-pwm" ++ "allwinner,sun50i-a133-pwm" ++ "allwinner,sun50i-r329-pwm" ++ - reg: physical base address and length of the controller's registers ++ - #pwm-cells: should be 3. See pwm.txt in this directory for a description of ++ the cells format. ++ - clocks: From common clock binding, handle to the parent clock. ++ - resets: From reset clock binding, handle to the parent clock. ++ ++Example: ++ ++ pwm: pwm@300a0000 { ++ compatible = "allwinner,sun50i-r818-pwm"; ++ reg = <0x0300a000 0x3ff>; ++ clocks = <&ccu CLK_BUS_PWM>; ++ resets = <&ccu RST_BUS_PWM>; ++ #pwm-cells = <3>; ++ }; diff --git a/target/linux/d1/patches-6.1/0060-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch b/target/linux/d1/patches-6.1/0060-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch new file mode 100644 index 0000000000..8c5d290c49 --- /dev/null +++ b/target/linux/d1/patches-6.1/0060-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-driver.patch @@ -0,0 +1,466 @@ +From 4919e67557eaebb9f155950e7cac547a507b59e5 Mon Sep 17 00:00:00 2001 +From: Ban Tao <fengzheng923@gmail.com> +Date: Tue, 2 Mar 2021 20:37:37 +0800 +Subject: [PATCH 060/117] pwm: sunxi: Add Allwinner SoC PWM controller driver + +The Allwinner R818, A133, R329, V536 and V833 has a new PWM controller +IP compared to the older Allwinner SoCs. + +Signed-off-by: Ban Tao <fengzheng923@gmail.com> +--- + MAINTAINERS | 6 + + drivers/pwm/Kconfig | 11 + + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-sun8i-v536.c | 401 +++++++++++++++++++++++++++++++++++ + 4 files changed, 419 insertions(+) + create mode 100644 drivers/pwm/pwm-sun8i-v536.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -802,6 +802,12 @@ S: Maintained + F: Documentation/devicetree/bindings/hwlock/allwinner,sun6i-a31-hwspinlock.yaml + F: drivers/hwspinlock/sun6i_hwspinlock.c + ++ALLWINNER PWM DRIVER ++M: Ban Tao <fengzheng923@gmail.com> ++L: linux-pwm@vger.kernel.org ++S: Maintained ++F: drivers/pwm/pwm-sun8i-v536.c ++ + ALLWINNER THERMAL DRIVER + M: Vasily Khoruzhick <anarsoul@gmail.com> + M: Yangtao Li <tiny.windzz@gmail.com> +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -582,6 +582,17 @@ config PWM_SUN4I + To compile this driver as a module, choose M here: the module + will be called pwm-sun4i. + ++config PWM_SUN8I_V536 ++ tristate "Allwinner SUN8I_V536 PWM support" ++ depends on ARCH_SUNXI || COMPILE_TEST ++ depends on HAS_IOMEM && COMMON_CLK ++ help ++ Enhanced PWM framework driver for Allwinner R818, A133, R329, ++ V536 and V833 SoCs. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-sun8i-v536. ++ + config PWM_SUNPLUS + tristate "Sunplus PWM support" + depends on ARCH_SUNPLUS || COMPILE_TEST +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -54,6 +54,7 @@ obj-$(CONFIG_PWM_STM32) += pwm-stm32.o + obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o + obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o + obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o ++obj-$(CONFIG_PWM_SUN8I_V536) += pwm-sun8i-v536.o + obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o + obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o + obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o +--- /dev/null ++++ b/drivers/pwm/pwm-sun8i-v536.c +@@ -0,0 +1,401 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Driver for Allwinner sun8i-v536 Pulse Width Modulation Controller ++ * ++ * Copyright (C) 2021 Ban Tao <fengzheng923@gmail.com> ++ * ++ * ++ * Limitations: ++ * - When PWM is disabled, the output is driven to inactive. ++ * - If the register is reconfigured while PWM is running, ++ * it does not complete the currently running period. ++ * - If the user input duty is beyond acceptible limits, ++ * -EINVAL is returned. ++ */ ++ ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/pwm.h> ++#include <linux/clk.h> ++#include <linux/reset.h> ++ ++#define PWM_GET_CLK_OFFSET(chan) (0x20 + ((chan >> 1) * 0x4)) ++#define PWM_CLK_APB_SCR BIT(7) ++#define PWM_DIV_M 0 ++#define PWM_DIV_M_MASK GENMASK(3, PWM_DIV_M) ++ ++#define PWM_CLK_REG 0x40 ++#define PWM_CLK_GATING BIT(0) ++ ++#define PWM_ENABLE_REG 0x80 ++#define PWM_EN BIT(0) ++ ++#define PWM_CTL_REG(chan) (0x100 + 0x20 * chan) ++#define PWM_ACT_STA BIT(8) ++#define PWM_PRESCAL_K 0 ++#define PWM_PRESCAL_K_MASK GENMASK(7, PWM_PRESCAL_K) ++ ++#define PWM_PERIOD_REG(chan) (0x104 + 0x20 * chan) ++#define PWM_ENTIRE_CYCLE 16 ++#define PWM_ENTIRE_CYCLE_MASK GENMASK(31, PWM_ENTIRE_CYCLE) ++#define PWM_ACT_CYCLE 0 ++#define PWM_ACT_CYCLE_MASK GENMASK(15, PWM_ACT_CYCLE) ++ ++#define BIT_CH(bit, chan) ((bit) << (chan)) ++#define SET_BITS(shift, mask, reg, val) \ ++ (((reg) & ~mask) | (val << (shift))) ++ ++#define PWM_OSC_CLK 24000000 ++#define PWM_PRESCALER_MAX 256 ++#define PWM_CLK_DIV_M__MAX 9 ++#define PWM_ENTIRE_CYCLE_MAX 65536 ++ ++struct sun8i_pwm_data { ++ unsigned int npwm; ++}; ++ ++struct sun8i_pwm_chip { ++ struct pwm_chip chip; ++ struct clk *clk; ++ struct reset_control *rst_clk; ++ void __iomem *base; ++ const struct sun8i_pwm_data *data; ++}; ++ ++static inline struct sun8i_pwm_chip *to_sun8i_pwm_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct sun8i_pwm_chip, chip); ++} ++ ++static inline u32 sun8i_pwm_readl(struct sun8i_pwm_chip *chip, ++ unsigned long offset) ++{ ++ return readl(chip->base + offset); ++} ++ ++static inline void sun8i_pwm_writel(struct sun8i_pwm_chip *chip, ++ u32 val, unsigned long offset) ++{ ++ writel(val, chip->base + offset); ++} ++ ++static void sun8i_pwm_get_state(struct pwm_chip *chip, ++ struct pwm_device *pwm, ++ struct pwm_state *state) ++{ ++ struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip); ++ u64 clk_rate; ++ u32 tmp, entire_cycles, active_cycles; ++ unsigned int prescaler, div_m; ++ ++ tmp = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ if (tmp & PWM_CLK_APB_SCR) ++ clk_rate = clk_get_rate(pc->clk); ++ else ++ clk_rate = PWM_OSC_CLK; ++ ++ tmp = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ div_m = 0x1 << (tmp & PWM_DIV_M_MASK); ++ ++ tmp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm)); ++ prescaler = (tmp & PWM_PRESCAL_K_MASK) + 1; ++ ++ tmp = sun8i_pwm_readl(pc, PWM_PERIOD_REG(pwm->hwpwm)); ++ entire_cycles = (tmp >> PWM_ENTIRE_CYCLE) + 1; ++ active_cycles = (tmp & PWM_ACT_CYCLE_MASK); ++ ++ /* (clk / div_m / prescaler) / entire_cycles = NSEC_PER_SEC / period_ns. */ ++ state->period = DIV_ROUND_CLOSEST_ULL(entire_cycles * NSEC_PER_SEC, ++ clk_rate) * div_m * prescaler; ++ /* duty_ns / period_ns = active_cycles / entire_cycles. */ ++ state->duty_cycle = DIV_ROUND_CLOSEST_ULL(active_cycles * state->period, ++ entire_cycles); ++ ++ /* parsing polarity */ ++ tmp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm)); ++ if (tmp & PWM_ACT_STA) ++ state->polarity = PWM_POLARITY_NORMAL; ++ else ++ state->polarity = PWM_POLARITY_INVERSED; ++ ++ /* parsing enabled */ ++ tmp = sun8i_pwm_readl(pc, PWM_ENABLE_REG); ++ if (tmp & BIT_CH(PWM_EN, pwm->hwpwm)) ++ state->enabled = true; ++ else ++ state->enabled = false; ++ ++ dev_dbg(chip->dev, "duty_ns=%lld period_ns=%lld polarity=%s enabled=%s.\n", ++ state->duty_cycle, state->period, ++ state->polarity ? "inversed":"normal", ++ state->enabled ? "true":"false"); ++} ++ ++static void sun8i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, ++ enum pwm_polarity polarity) ++{ ++ struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip); ++ u32 temp; ++ ++ temp = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm)); ++ ++ if (polarity == PWM_POLARITY_NORMAL) ++ temp |= PWM_ACT_STA; ++ else ++ temp &= ~PWM_ACT_STA; ++ ++ sun8i_pwm_writel(pc, temp, PWM_CTL_REG(pwm->hwpwm)); ++} ++ ++static int sun8i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip); ++ unsigned long long c; ++ unsigned long entire_cycles, active_cycles; ++ unsigned int div_m, prescaler; ++ u64 duty_ns = state->duty_cycle, period_ns = state->period; ++ u32 config; ++ int ret = 0; ++ ++ if (period_ns > 334) { ++ /* if freq < 3M, then select 24M clock */ ++ c = PWM_OSC_CLK; ++ config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ config &= ~PWM_CLK_APB_SCR; ++ sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ } else { ++ /* if freq > 3M, then select APB as clock */ ++ c = clk_get_rate(pc->clk); ++ config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ config |= PWM_CLK_APB_SCR; ++ sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ } ++ ++ dev_dbg(chip->dev, "duty_ns=%lld period_ns=%lld c =%llu.\n", ++ duty_ns, period_ns, c); ++ ++ /* ++ * (clk / div_m / prescaler) / entire_cycles = NSEC_PER_SEC / period_ns. ++ * So, entire_cycles = clk * period_ns / NSEC_PER_SEC / div_m / prescaler. ++ */ ++ c = c * period_ns; ++ c = DIV_ROUND_CLOSEST_ULL(c, NSEC_PER_SEC); ++ for (div_m = 0; div_m < PWM_CLK_DIV_M__MAX; div_m++) { ++ for (prescaler = 0; prescaler < PWM_PRESCALER_MAX; prescaler++) { ++ /* ++ * actual prescaler = prescaler(reg value) + 1. ++ * actual div_m = 0x1 << div_m(reg value). ++ */ ++ entire_cycles = ((unsigned long)c >> div_m)/(prescaler + 1); ++ if (entire_cycles <= PWM_ENTIRE_CYCLE_MAX) ++ goto calc_end; ++ } ++ } ++ ret = -EINVAL; ++ goto exit; ++ ++calc_end: ++ /* ++ * duty_ns / period_ns = active_cycles / entire_cycles. ++ * So, active_cycles = entire_cycles * duty_ns / period_ns. ++ */ ++ c = (unsigned long long)entire_cycles * duty_ns; ++ c = DIV_ROUND_CLOSEST_ULL(c, period_ns); ++ active_cycles = c; ++ if (entire_cycles == 0) ++ entire_cycles++; ++ ++ /* config clk div_m*/ ++ config = sun8i_pwm_readl(pc, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ config = SET_BITS(PWM_DIV_M, PWM_DIV_M_MASK, config, div_m); ++ sun8i_pwm_writel(pc, config, PWM_GET_CLK_OFFSET(pwm->hwpwm)); ++ ++ /* config prescaler */ ++ config = sun8i_pwm_readl(pc, PWM_CTL_REG(pwm->hwpwm)); ++ config = SET_BITS(PWM_PRESCAL_K, PWM_PRESCAL_K_MASK, config, prescaler); ++ sun8i_pwm_writel(pc, config, PWM_CTL_REG(pwm->hwpwm)); ++ ++ /* config active and period cycles */ ++ config = sun8i_pwm_readl(pc, PWM_PERIOD_REG(pwm->hwpwm)); ++ config = SET_BITS(PWM_ACT_CYCLE, PWM_ACT_CYCLE_MASK, config, active_cycles); ++ config = SET_BITS(PWM_ENTIRE_CYCLE, PWM_ENTIRE_CYCLE_MASK, ++ config, (entire_cycles - 1)); ++ sun8i_pwm_writel(pc, config, PWM_PERIOD_REG(pwm->hwpwm)); ++ ++ dev_dbg(chip->dev, "active_cycles=%lu entire_cycles=%lu prescaler=%u div_m=%u\n", ++ active_cycles, entire_cycles, prescaler, div_m); ++ ++exit: ++ return ret; ++} ++ ++static void sun8i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, ++ bool enable) ++{ ++ struct sun8i_pwm_chip *pc = to_sun8i_pwm_chip(chip); ++ u32 clk, pwm_en; ++ ++ clk = sun8i_pwm_readl(pc, PWM_CLK_REG); ++ pwm_en = sun8i_pwm_readl(pc, PWM_ENABLE_REG); ++ ++ if (enable) { ++ clk |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ++ sun8i_pwm_writel(pc, clk, PWM_CLK_REG); ++ ++ pwm_en |= BIT_CH(PWM_EN, pwm->hwpwm); ++ sun8i_pwm_writel(pc, pwm_en, PWM_ENABLE_REG); ++ } else { ++ pwm_en &= ~BIT_CH(PWM_EN, pwm->hwpwm); ++ sun8i_pwm_writel(pc, pwm_en, PWM_ENABLE_REG); ++ ++ clk &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ++ sun8i_pwm_writel(pc, clk, PWM_CLK_REG); ++ } ++} ++ ++static int sun8i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct pwm_state curstate; ++ int ret; ++ ++ pwm_get_state(pwm, &curstate); ++ ++ ret = sun8i_pwm_config(chip, pwm, state); ++ ++ if (state->polarity != curstate.polarity) ++ sun8i_pwm_set_polarity(chip, pwm, state->polarity); ++ ++ if (state->enabled != curstate.enabled) ++ sun8i_pwm_enable(chip, pwm, state->enabled); ++ ++ return ret; ++} ++ ++static const struct pwm_ops sun8i_pwm_ops = { ++ .get_state = sun8i_pwm_get_state, ++ .apply = sun8i_pwm_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct sun8i_pwm_data sun8i_pwm_data_c9 = { ++ .npwm = 9, ++}; ++ ++static const struct sun8i_pwm_data sun50i_pwm_data_c16 = { ++ .npwm = 16, ++}; ++ ++static const struct of_device_id sun8i_pwm_dt_ids[] = { ++ { ++ .compatible = "allwinner,sun8i-v536-pwm", ++ .data = &sun8i_pwm_data_c9, ++ }, { ++ .compatible = "allwinner,sun50i-r818-pwm", ++ .data = &sun50i_pwm_data_c16, ++ }, { ++ /* sentinel */ ++ }, ++}; ++MODULE_DEVICE_TABLE(of, sun8i_pwm_dt_ids); ++ ++static int sun8i_pwm_probe(struct platform_device *pdev) ++{ ++ struct sun8i_pwm_chip *pc; ++ int ret; ++ ++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return dev_err_probe(&pdev->dev, -ENOMEM, ++ "memory allocation failed\n"); ++ ++ pc->data = of_device_get_match_data(&pdev->dev); ++ if (!pc->data) ++ return dev_err_probe(&pdev->dev, -ENODEV, ++ "can't get match data\n"); ++ ++ pc->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pc->base)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->base), ++ "can't remap pwm resource\n"); ++ ++ pc->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pc->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), ++ "get clock failed\n"); ++ ++ pc->rst_clk = devm_reset_control_get_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(pc->rst_clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->rst_clk), ++ "get reset failed\n"); ++ ++ /* Deassert reset */ ++ ret = reset_control_deassert(pc->rst_clk); ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, ++ "cannot deassert reset control\n"); ++ ++ ret = clk_prepare_enable(pc->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot prepare and enable clk %pe\n", ++ ERR_PTR(ret)); ++ goto err_clk; ++ } ++ ++ pc->chip.dev = &pdev->dev; ++ pc->chip.ops = &sun8i_pwm_ops; ++ pc->chip.npwm = pc->data->npwm; ++ pc->chip.of_xlate = of_pwm_xlate_with_flags; ++ pc->chip.base = -1; ++ pc->chip.of_pwm_n_cells = 3; ++ ++ ret = pwmchip_add(&pc->chip); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); ++ goto err_pwm_add; ++ } ++ ++ platform_set_drvdata(pdev, pc); ++ ++ return 0; ++ ++err_pwm_add: ++ clk_disable_unprepare(pc->clk); ++err_clk: ++ reset_control_assert(pc->rst_clk); ++ ++ return ret; ++} ++ ++static int sun8i_pwm_remove(struct platform_device *pdev) ++{ ++ struct sun8i_pwm_chip *pc = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = pwmchip_remove(&pc->chip); ++ if (ret) ++ return ret; ++ ++ clk_disable_unprepare(pc->clk); ++ reset_control_assert(pc->rst_clk); ++ ++ return 0; ++} ++ ++static struct platform_driver sun8i_pwm_driver = { ++ .driver = { ++ .name = "sun8i-pwm-v536", ++ .of_match_table = sun8i_pwm_dt_ids, ++ }, ++ .probe = sun8i_pwm_probe, ++ .remove = sun8i_pwm_remove, ++}; ++module_platform_driver(sun8i_pwm_driver); ++ ++MODULE_ALIAS("platform:sun8i-v536-pwm"); ++MODULE_AUTHOR("Ban Tao <fengzheng923@gmail.com>"); ++MODULE_DESCRIPTION("Allwinner sun8i-v536 PWM driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/d1/patches-6.1/0061-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch b/target/linux/d1/patches-6.1/0061-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch new file mode 100644 index 0000000000..0eac89797d --- /dev/null +++ b/target/linux/d1/patches-6.1/0061-squash-pwm-sunxi-Add-Allwinner-SoC-PWM-controller-dr.patch @@ -0,0 +1,43 @@ +From 2f452dd6047126c42a0ad32ef0f10145c6047d66 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 6 Jun 2021 11:05:20 -0500 +Subject: [PATCH 061/117] squash? pwm: sunxi: Add Allwinner SoC PWM controller + driver + +--- + drivers/pwm/Kconfig | 4 ++-- + drivers/pwm/pwm-sun8i-v536.c | 6 +----- + 2 files changed, 3 insertions(+), 7 deletions(-) + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -583,11 +583,11 @@ config PWM_SUN4I + will be called pwm-sun4i. + + config PWM_SUN8I_V536 +- tristate "Allwinner SUN8I_V536 PWM support" ++ tristate "Allwinner SUN8I V536 enhanced PWM support" + depends on ARCH_SUNXI || COMPILE_TEST + depends on HAS_IOMEM && COMMON_CLK + help +- Enhanced PWM framework driver for Allwinner R818, A133, R329, ++ Enhanced PWM framework driver for Allwinner A133, D1, R329, R818, + V536 and V833 SoCs. + + To compile this driver as a module, choose M here: the module +--- a/drivers/pwm/pwm-sun8i-v536.c ++++ b/drivers/pwm/pwm-sun8i-v536.c +@@ -373,12 +373,8 @@ err_clk: + static int sun8i_pwm_remove(struct platform_device *pdev) + { + struct sun8i_pwm_chip *pc = platform_get_drvdata(pdev); +- int ret; +- +- ret = pwmchip_remove(&pc->chip); +- if (ret) +- return ret; + ++ pwmchip_remove(&pc->chip); + clk_disable_unprepare(pc->clk); + reset_control_assert(pc->rst_clk); + diff --git a/target/linux/d1/patches-6.1/0062-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch b/target/linux/d1/patches-6.1/0062-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch new file mode 100644 index 0000000000..d9df6e6681 --- /dev/null +++ b/target/linux/d1/patches-6.1/0062-pwm-sun8i-v536-Add-support-for-the-Allwinner-D1.patch @@ -0,0 +1,33 @@ +From 8bb576d8640fdf896650a4d4a1b2e60254d75eb2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 6 Jun 2021 10:56:25 -0500 +Subject: [PATCH 062/117] pwm: sun8i-v536: Add support for the Allwinner D1 + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/pwm/pwm-sun8i-v536.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/pwm/pwm-sun8i-v536.c ++++ b/drivers/pwm/pwm-sun8i-v536.c +@@ -285,6 +285,10 @@ static const struct sun8i_pwm_data sun8i + .npwm = 9, + }; + ++static const struct sun8i_pwm_data sun20i_pwm_data_c8 = { ++ .npwm = 8, ++}; ++ + static const struct sun8i_pwm_data sun50i_pwm_data_c16 = { + .npwm = 16, + }; +@@ -294,6 +298,9 @@ static const struct of_device_id sun8i_p + .compatible = "allwinner,sun8i-v536-pwm", + .data = &sun8i_pwm_data_c9, + }, { ++ .compatible = "allwinner,sun20i-d1-pwm", ++ .data = &sun20i_pwm_data_c8, ++ }, { + .compatible = "allwinner,sun50i-r818-pwm", + .data = &sun50i_pwm_data_c16, + }, { diff --git a/target/linux/d1/patches-6.1/0063-riscv-dts-allwinner-d1-Add-PWM-support.patch b/target/linux/d1/patches-6.1/0063-riscv-dts-allwinner-d1-Add-PWM-support.patch new file mode 100644 index 0000000000..f353c6f91b --- /dev/null +++ b/target/linux/d1/patches-6.1/0063-riscv-dts-allwinner-d1-Add-PWM-support.patch @@ -0,0 +1,61 @@ +From 2ee8994e4db3978261e6c644e897400c4df5edeb Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:24:52 -0500 +Subject: [PATCH 063/117] riscv: dts: allwinner: d1: Add PWM support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 35 ++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -155,6 +155,30 @@ + }; + + /omit-if-no-ref/ ++ pwm0_pd16_pin: pwm0-pd16-pin { ++ pins = "PD16"; ++ function = "pwm0"; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm2_pd18_pin: pwm2-pd18-pin { ++ pins = "PD18"; ++ function = "pwm2"; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm4_pd20_pin: pwm4-pd20-pin { ++ pins = "PD20"; ++ function = "pwm4"; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm7_pd22_pin: pwm7-pd22-pin { ++ pins = "PD22"; ++ function = "pwm7"; ++ }; ++ ++ /omit-if-no-ref/ + uart0_pb8_pins: uart0-pb8-pins { + pins = "PB8", "PB9"; + function = "uart0"; +@@ -173,6 +197,17 @@ + }; + }; + ++ pwm: pwm@2000c00 { ++ compatible = "allwinner,sun20i-d1-pwm"; ++ reg = <0x2000c00 0x400>; ++ interrupts = <34 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_PWM>, <&osc24M>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_PWM>; ++ status = "disabled"; ++ #pwm-cells = <3>; ++ }; ++ + ccu: clock-controller@2001000 { + compatible = "allwinner,sun20i-d1-ccu"; + reg = <0x2001000 0x1000>; diff --git a/target/linux/d1/patches-6.1/0064-riscv-dts-allwinner-d1-Hook-up-PWM-controlled-CPU-vo.patch b/target/linux/d1/patches-6.1/0064-riscv-dts-allwinner-d1-Hook-up-PWM-controlled-CPU-vo.patch new file mode 100644 index 0000000000..ff61b07d93 --- /dev/null +++ b/target/linux/d1/patches-6.1/0064-riscv-dts-allwinner-d1-Hook-up-PWM-controlled-CPU-vo.patch @@ -0,0 +1,124 @@ +From 5479c8efb6ffbbc8b7fd1068337037faf9c20a36 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:25:40 -0500 +Subject: [PATCH 064/117] riscv: dts: allwinner: d1: Hook up PWM-controlled CPU + voltage regulators + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../allwinner/sun20i-d1-clockworkpi-v3.14.dts | 19 +++++++++++-------- + .../sun20i-d1-dongshan-nezha-stu.dts | 19 +++++++++++-------- + .../boot/dts/allwinner/sun20i-d1-nezha.dts | 19 +++++++++++-------- + 3 files changed, 33 insertions(+), 24 deletions(-) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts +@@ -48,16 +48,13 @@ + }; + }; + +- /* +- * This regulator is PWM-controlled, but the PWM controller is not +- * yet supported, so fix the regulator to its default voltage. +- */ + reg_vdd_cpu: vdd-cpu { +- compatible = "regulator-fixed"; ++ compatible = "pwm-regulator"; ++ pwms = <&pwm 0 50000 0>; ++ pwm-supply = <®_vcc>; + regulator-name = "vdd-cpu"; +- regulator-min-microvolt = <1100000>; +- regulator-max-microvolt = <1100000>; +- vin-supply = <®_vcc>; ++ regulator-min-microvolt = <810000>; ++ regulator-max-microvolt = <1160000>; + }; + + wifi_pwrseq: wifi-pwrseq { +@@ -254,6 +251,12 @@ + }; + }; + ++&pwm { ++ pinctrl-0 = <&pwm0_pd16_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-0 = <&uart0_pb8_pins>; + pinctrl-names = "default"; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-dongshan-nezha-stu.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-dongshan-nezha-stu.dts +@@ -43,16 +43,13 @@ + vin-supply = <®_vcc>; + }; + +- /* +- * This regulator is PWM-controlled, but the PWM controller is not +- * yet supported, so fix the regulator to its default voltage. +- */ + reg_vdd_cpu: vdd-cpu { +- compatible = "regulator-fixed"; ++ compatible = "pwm-regulator"; ++ pwms = <&pwm 0 50000 0>; ++ pwm-supply = <®_vcc>; + regulator-name = "vdd-cpu"; +- regulator-min-microvolt = <1100000>; +- regulator-max-microvolt = <1100000>; +- vin-supply = <®_vcc>; ++ regulator-min-microvolt = <810000>; ++ regulator-max-microvolt = <1160000>; + }; + }; + +@@ -95,6 +92,12 @@ + status = "okay"; + }; + ++&pwm { ++ pinctrl-0 = <&pwm0_pd16_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-0 = <&uart0_pb8_pins>; + pinctrl-names = "default"; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts +@@ -35,16 +35,13 @@ + vin-supply = <®_vcc>; + }; + +- /* +- * This regulator is PWM-controlled, but the PWM controller is not +- * yet supported, so fix the regulator to its default voltage. +- */ + reg_vdd_cpu: vdd-cpu { +- compatible = "regulator-fixed"; ++ compatible = "pwm-regulator"; ++ pwms = <&pwm 0 50000 0>; ++ pwm-supply = <®_vcc>; + regulator-name = "vdd-cpu"; +- regulator-min-microvolt = <1100000>; +- regulator-max-microvolt = <1100000>; +- vin-supply = <®_vcc>; ++ regulator-min-microvolt = <810000>; ++ regulator-max-microvolt = <1160000>; + }; + + wifi_pwrseq: wifi-pwrseq { +@@ -155,6 +152,12 @@ + status = "okay"; + }; + ++&pwm { ++ pinctrl-0 = <&pwm0_pd16_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-0 = <&uart0_pb8_pins>; + pinctrl-names = "default"; diff --git a/target/linux/d1/patches-6.1/0065-riscv-dts-allwinner-mangopi-mq-pro-Add-PWM-LED.patch b/target/linux/d1/patches-6.1/0065-riscv-dts-allwinner-mangopi-mq-pro-Add-PWM-LED.patch new file mode 100644 index 0000000000..f184bd2136 --- /dev/null +++ b/target/linux/d1/patches-6.1/0065-riscv-dts-allwinner-mangopi-mq-pro-Add-PWM-LED.patch @@ -0,0 +1,38 @@ +From 29360e65c326ea8bbac6e63b42aa91fb8f14d3bf Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:57:13 -0500 +Subject: [PATCH 065/117] riscv: dts: allwinner: mangopi-mq-pro: Add PWM LED + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../boot/dts/allwinner/sun20i-d1-mangopi-mq-pro.dts | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-mangopi-mq-pro.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-mangopi-mq-pro.dts +@@ -4,6 +4,7 @@ + /dts-v1/; + + #include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/leds/common.h> + + #include "sun20i-d1.dtsi" + #include "sun20i-d1-common-regulators.dtsi" +@@ -22,6 +23,17 @@ + stdout-path = "serial0:115200n8"; + }; + ++ leds { ++ compatible = "pwm-leds"; ++ ++ led { ++ color = <LED_COLOR_ID_BLUE>; ++ function = LED_FUNCTION_STATUS; ++ max-brightness = <255>; ++ pwms = <&pwm 2 50000 0>; ++ }; ++ }; ++ + reg_avdd2v8: avdd2v8 { + compatible = "regulator-fixed"; + regulator-name = "avdd2v8"; diff --git a/target/linux/d1/patches-6.1/0066-ASoC-dt-bindings-sun4i-spdif-Require-resets-for-H6.patch b/target/linux/d1/patches-6.1/0066-ASoC-dt-bindings-sun4i-spdif-Require-resets-for-H6.patch new file mode 100644 index 0000000000..0d27224ac3 --- /dev/null +++ b/target/linux/d1/patches-6.1/0066-ASoC-dt-bindings-sun4i-spdif-Require-resets-for-H6.patch @@ -0,0 +1,24 @@ +From bccb19038038c7377275d74bb815f5f9363ba2e3 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 13 Nov 2021 10:08:41 -0600 +Subject: [PATCH 066/117] ASoC: dt-bindings: sun4i-spdif: Require resets for H6 + +The H6 variant has a module reset, and it is used by the driver. So the +resets property should be required in the binding for this variant. + +Fixes: b20453031472 ("dt-bindings: sound: sun4i-spdif: Add Allwinner H6 compatible") +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml ++++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +@@ -61,6 +61,7 @@ allOf: + enum: + - allwinner,sun6i-a31-spdif + - allwinner,sun8i-h3-spdif ++ - allwinner,sun50i-h6-spdif + + then: + required: diff --git a/target/linux/d1/patches-6.1/0067-ASoC-dt-bindings-sun4i-spdif-Add-compatible-for-D1.patch b/target/linux/d1/patches-6.1/0067-ASoC-dt-bindings-sun4i-spdif-Add-compatible-for-D1.patch new file mode 100644 index 0000000000..5c7e21954f --- /dev/null +++ b/target/linux/d1/patches-6.1/0067-ASoC-dt-bindings-sun4i-spdif-Add-compatible-for-D1.patch @@ -0,0 +1,94 @@ +From 4e72722bfb7dec028e11278a924bb8bef3e10897 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 13 Nov 2021 10:48:24 -0600 +Subject: [PATCH 067/117] ASoC: dt-bindings: sun4i-spdif: Add compatible for D1 + +D1 mostly keeps the existing register layout, but it separates the +module clock into separate clocks for the RX block and the TX block. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../sound/allwinner,sun4i-a10-spdif.yaml | 54 +++++++++++++++---- + 1 file changed, 44 insertions(+), 10 deletions(-) + +--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml ++++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +@@ -18,10 +18,12 @@ properties: + + compatible: + oneOf: +- - const: allwinner,sun4i-a10-spdif +- - const: allwinner,sun6i-a31-spdif +- - const: allwinner,sun8i-h3-spdif +- - const: allwinner,sun50i-h6-spdif ++ - enum: ++ - allwinner,sun4i-a10-spdif ++ - allwinner,sun6i-a31-spdif ++ - allwinner,sun8i-h3-spdif ++ - allwinner,sun20i-d1-spdif ++ - allwinner,sun50i-h6-spdif + - items: + - const: allwinner,sun8i-a83t-spdif + - const: allwinner,sun8i-h3-spdif +@@ -36,14 +38,12 @@ properties: + maxItems: 1 + + clocks: +- items: +- - description: Bus Clock +- - description: Module Clock ++ minItems: 2 ++ maxItems: 3 + + clock-names: +- items: +- - const: apb +- - const: spdif ++ minItems: 2 ++ maxItems: 3 + + # Even though it only applies to subschemas under the conditionals, + # not listing them here will trigger a warning because of the +@@ -59,8 +59,42 @@ allOf: + compatible: + contains: + enum: ++ - allwinner,sun20i-d1-spdif ++ ++ then: ++ properties: ++ clocks: ++ items: ++ - description: Bus Clock ++ - description: RX Module Clock ++ - description: TX Module Clock ++ ++ clock-names: ++ items: ++ - const: apb ++ - const: rx ++ - const: tx ++ ++ else: ++ properties: ++ clocks: ++ items: ++ - description: Bus Clock ++ - description: Module Clock ++ ++ clock-names: ++ items: ++ - const: apb ++ - const: spdif ++ ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: + - allwinner,sun6i-a31-spdif + - allwinner,sun8i-h3-spdif ++ - allwinner,sun20i-d1-spdif + - allwinner,sun50i-h6-spdif + + then: diff --git a/target/linux/d1/patches-6.1/0068-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch b/target/linux/d1/patches-6.1/0068-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch new file mode 100644 index 0000000000..794fd8c1db --- /dev/null +++ b/target/linux/d1/patches-6.1/0068-ASoC-sun4i-spdif-Assert-reset-when-removing-the-devi.patch @@ -0,0 +1,30 @@ +From 1d85b3609cf4239f7e971b839f1ab985413cd560 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 13 Nov 2021 11:12:14 -0600 +Subject: [PATCH 068/117] ASoC: sun4i-spdif: Assert reset when removing the + device + +This completes reversing the process done in the probe function. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-spdif.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/soc/sunxi/sun4i-spdif.c ++++ b/sound/soc/sunxi/sun4i-spdif.c +@@ -705,10 +705,14 @@ err_unregister: + + static int sun4i_spdif_remove(struct platform_device *pdev) + { ++ struct sun4i_spdif_dev *host = dev_get_drvdata(&pdev->dev); ++ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + sun4i_spdif_runtime_suspend(&pdev->dev); + ++ reset_control_assert(host->rst); ++ + return 0; + } + diff --git a/target/linux/d1/patches-6.1/0069-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch b/target/linux/d1/patches-6.1/0069-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch new file mode 100644 index 0000000000..0cd39d0b19 --- /dev/null +++ b/target/linux/d1/patches-6.1/0069-ASoC-sun4i-spdif-Simplify-code-around-optional-reset.patch @@ -0,0 +1,78 @@ +From 0efd742482dbe4b17a441eab5c57231d65f9a852 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 13 Nov 2021 11:14:30 -0600 +Subject: [PATCH 069/117] ASoC: sun4i-spdif: Simplify code around optional + resets + +The driver does not need to care about which variants have a reset; +the devicetree binding already enforces that the necessary resources are +provided. Simplify the logic by always calling the optional getter, +which will return NULL if no reset reference is found. + +Also clean up the error handling, which should not print a misleading +error in the EPROBE_DEFER case. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-spdif.c | 22 ++++++---------------- + 1 file changed, 6 insertions(+), 16 deletions(-) + +--- a/sound/soc/sunxi/sun4i-spdif.c ++++ b/sound/soc/sunxi/sun4i-spdif.c +@@ -170,12 +170,10 @@ + * struct sun4i_spdif_quirks - Differences between SoC variants. + * + * @reg_dac_txdata: TX FIFO offset for DMA config. +- * @has_reset: SoC needs reset deasserted. + * @val_fctl_ftx: TX FIFO flush bitmask. + */ + struct sun4i_spdif_quirks { + unsigned int reg_dac_txdata; +- bool has_reset; + unsigned int val_fctl_ftx; + }; + +@@ -546,19 +544,16 @@ static const struct sun4i_spdif_quirks s + static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = { + .reg_dac_txdata = SUN4I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, +- .has_reset = true, + }; + + static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = { + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, +- .has_reset = true, + }; + + static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = { + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN50I_H6_SPDIF_FCTL_FTX, +- .has_reset = true, + }; + + static const struct of_device_id sun4i_spdif_of_match[] = { +@@ -667,17 +662,12 @@ static int sun4i_spdif_probe(struct plat + + platform_set_drvdata(pdev, host); + +- if (quirks->has_reset) { +- host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, +- NULL); +- if (PTR_ERR(host->rst) == -EPROBE_DEFER) { +- ret = -EPROBE_DEFER; +- dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); +- return ret; +- } +- if (!IS_ERR(host->rst)) +- reset_control_deassert(host->rst); +- } ++ host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (IS_ERR(host->rst)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(host->rst), ++ "Failed to get reset\n"); ++ ++ reset_control_deassert(host->rst); + + ret = devm_snd_soc_register_component(&pdev->dev, + &sun4i_spdif_component, &sun4i_spdif_dai, 1); diff --git a/target/linux/d1/patches-6.1/0070-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch b/target/linux/d1/patches-6.1/0070-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch new file mode 100644 index 0000000000..99a198bd82 --- /dev/null +++ b/target/linux/d1/patches-6.1/0070-ASoC-sun4i-spdif-Add-support-for-separate-RX-TX-cloc.patch @@ -0,0 +1,116 @@ +From b42a9e0cf6b0ca78b4ef5310de967d515a3cca03 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:53:16 -0500 +Subject: [PATCH 070/117] ASoC: sun4i-spdif: Add support for separate RX/TX + clocks + +On older variants of the hardware, the RX and TX blocks share a single +module clock, named "spdif" in the DT binding. The D1 variant has +separate RX and TX clocks, so the TX module clock is named "tx" in the +binding. To support this, supply the clock name in the quirks structure. + +Since the driver supports only TX, only the TX clock name is needed. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-spdif.c | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +--- a/sound/soc/sunxi/sun4i-spdif.c ++++ b/sound/soc/sunxi/sun4i-spdif.c +@@ -169,18 +169,20 @@ + /** + * struct sun4i_spdif_quirks - Differences between SoC variants. + * ++ * @tx_clk_name: firmware name for the TX clock reference. + * @reg_dac_txdata: TX FIFO offset for DMA config. + * @val_fctl_ftx: TX FIFO flush bitmask. + */ + struct sun4i_spdif_quirks { ++ const char *tx_clk_name; + unsigned int reg_dac_txdata; + unsigned int val_fctl_ftx; + }; + + struct sun4i_spdif_dev { + struct platform_device *pdev; +- struct clk *spdif_clk; + struct clk *apb_clk; ++ struct clk *tx_clk; + struct reset_control *rst; + struct snd_soc_dai_driver cpu_dai_drv; + struct regmap *regmap; +@@ -313,7 +315,7 @@ static int sun4i_spdif_hw_params(struct + return -EINVAL; + } + +- ret = clk_set_rate(host->spdif_clk, mclk); ++ ret = clk_set_rate(host->tx_clk, mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "Setting SPDIF clock rate for %d Hz failed!\n", mclk); +@@ -537,21 +539,25 @@ static struct snd_soc_dai_driver sun4i_s + }; + + static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = { ++ .tx_clk_name = "spdif", + .reg_dac_txdata = SUN4I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, + }; + + static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = { ++ .tx_clk_name = "spdif", + .reg_dac_txdata = SUN4I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, + }; + + static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = { ++ .tx_clk_name = "spdif", + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, + }; + + static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = { ++ .tx_clk_name = "spdif", + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, + .val_fctl_ftx = SUN50I_H6_SPDIF_FCTL_FTX, + }; +@@ -586,7 +592,7 @@ static int sun4i_spdif_runtime_suspend(s + { + struct sun4i_spdif_dev *host = dev_get_drvdata(dev); + +- clk_disable_unprepare(host->spdif_clk); ++ clk_disable_unprepare(host->tx_clk); + clk_disable_unprepare(host->apb_clk); + + return 0; +@@ -597,12 +603,12 @@ static int sun4i_spdif_runtime_resume(st + struct sun4i_spdif_dev *host = dev_get_drvdata(dev); + int ret; + +- ret = clk_prepare_enable(host->spdif_clk); ++ ret = clk_prepare_enable(host->tx_clk); + if (ret) + return ret; + ret = clk_prepare_enable(host->apb_clk); + if (ret) +- clk_disable_unprepare(host->spdif_clk); ++ clk_disable_unprepare(host->tx_clk); + + return ret; + } +@@ -650,10 +656,10 @@ static int sun4i_spdif_probe(struct plat + return PTR_ERR(host->apb_clk); + } + +- host->spdif_clk = devm_clk_get(&pdev->dev, "spdif"); +- if (IS_ERR(host->spdif_clk)) { +- dev_err(&pdev->dev, "failed to get a spdif clock.\n"); +- return PTR_ERR(host->spdif_clk); ++ host->tx_clk = devm_clk_get(&pdev->dev, quirks->tx_clk_name); ++ if (IS_ERR(host->tx_clk)) { ++ dev_err(&pdev->dev, "failed to get TX module clock.\n"); ++ return PTR_ERR(host->tx_clk); + } + + host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata; diff --git a/target/linux/d1/patches-6.1/0071-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch b/target/linux/d1/patches-6.1/0071-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch new file mode 100644 index 0000000000..022e319ab0 --- /dev/null +++ b/target/linux/d1/patches-6.1/0071-ASoC-sun4i-spdif-Add-support-for-the-D1-variant.patch @@ -0,0 +1,40 @@ +From af01261bf4e334cad158519291e5bc38765c955f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:53:26 -0500 +Subject: [PATCH 071/117] ASoC: sun4i-spdif: Add support for the D1 variant + +The D1 variant is similar to the H6 variant, except for its clock setup. +The clock tree changes impact some register fields on the RX side, but +those are not yet relevant, because RX is not supported by this driver. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-spdif.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/sound/soc/sunxi/sun4i-spdif.c ++++ b/sound/soc/sunxi/sun4i-spdif.c +@@ -556,6 +556,12 @@ static const struct sun4i_spdif_quirks s + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, + }; + ++static const struct sun4i_spdif_quirks sun20i_d1_spdif_quirks = { ++ .tx_clk_name = "tx", ++ .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, ++ .val_fctl_ftx = SUN50I_H6_SPDIF_FCTL_FTX, ++}; ++ + static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = { + .tx_clk_name = "spdif", + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, +@@ -576,6 +582,10 @@ static const struct of_device_id sun4i_s + .data = &sun8i_h3_spdif_quirks, + }, + { ++ .compatible = "allwinner,sun20i-d1-spdif", ++ .data = &sun20i_d1_spdif_quirks, ++ }, ++ { + .compatible = "allwinner,sun50i-h6-spdif", + .data = &sun50i_h6_spdif_quirks, + }, diff --git a/target/linux/d1/patches-6.1/0072-riscv-dts-allwinner-d1-Add-SPDIF-support.patch b/target/linux/d1/patches-6.1/0072-riscv-dts-allwinner-d1-Add-SPDIF-support.patch new file mode 100644 index 0000000000..72335cab40 --- /dev/null +++ b/target/linux/d1/patches-6.1/0072-riscv-dts-allwinner-d1-Add-SPDIF-support.patch @@ -0,0 +1,35 @@ +From 36153e325aa912268a5a5d4574dc7092e67c8008 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 17 Aug 2022 01:54:46 -0500 +Subject: [PATCH 072/117] riscv: dts: allwinner: d1: Add SPDIF support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -333,6 +333,22 @@ + #sound-dai-cells = <0>; + }; + ++ // TODO: add receive functionality ++ spdif: spdif@2036000 { ++ compatible = "allwinner,sun20i-d1-spdif"; ++ reg = <0x2036000 0x400>; ++ interrupts = <39 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_SPDIF>, ++ <&ccu CLK_SPDIF_RX>, ++ <&ccu CLK_SPDIF_TX>; ++ clock-names = "apb", "rx", "tx"; ++ resets = <&ccu RST_BUS_SPDIF>; ++ dmas = <&dma 2>, <&dma 2>; ++ dma-names = "rx", "tx"; ++ status = "disabled"; ++ #sound-dai-cells = <0>; ++ }; ++ + timer: timer@2050000 { + compatible = "allwinner,sun20i-d1-timer", + "allwinner,sun8i-a23-timer"; diff --git a/target/linux/d1/patches-6.1/0073-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch b/target/linux/d1/patches-6.1/0073-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch new file mode 100644 index 0000000000..37ff3e2a9a --- /dev/null +++ b/target/linux/d1/patches-6.1/0073-ASoC-sun4i-spdif-Add-support-for-separate-resets.patch @@ -0,0 +1,34 @@ +From c2b3f2c723e1b558afe5661bb91669e3b68154f7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 13 Jun 2021 23:52:47 -0500 +Subject: [PATCH 073/117] ASoC: sun4i-spdif: Add support for separate resets + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun4i-spdif.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/sound/soc/sunxi/sun4i-spdif.c ++++ b/sound/soc/sunxi/sun4i-spdif.c +@@ -28,10 +28,11 @@ + #include <sound/soc.h> + + #define SUN4I_SPDIF_CTL (0x00) ++ #define SUN4I_SPDIF_CTL_RST_RX BIT(12) + #define SUN4I_SPDIF_CTL_MCLKDIV(v) ((v) << 4) /* v even */ + #define SUN4I_SPDIF_CTL_MCLKOUTEN BIT(2) + #define SUN4I_SPDIF_CTL_GEN BIT(1) +- #define SUN4I_SPDIF_CTL_RESET BIT(0) ++ #define SUN4I_SPDIF_CTL_RST_TX BIT(0) + + #define SUN4I_SPDIF_TXCFG (0x04) + #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31) +@@ -196,7 +197,7 @@ static void sun4i_spdif_configure(struct + const struct sun4i_spdif_quirks *quirks = host->quirks; + + /* soft reset SPDIF */ +- regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET); ++ regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RST_TX); + + /* flush TX FIFO */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL, diff --git a/target/linux/d1/patches-6.1/0074-dt-bindings-spi-sun6i-Add-R329-variant.patch b/target/linux/d1/patches-6.1/0074-dt-bindings-spi-sun6i-Add-R329-variant.patch new file mode 100644 index 0000000000..2301fad1cd --- /dev/null +++ b/target/linux/d1/patches-6.1/0074-dt-bindings-spi-sun6i-Add-R329-variant.patch @@ -0,0 +1,34 @@ +From e8e8a9490b2d4acc8670256dd3ba7d2a77346c4d Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:23:05 -0500 +Subject: [PATCH 074/117] dt-bindings: spi: sun6i: Add R329 variant + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml ++++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml +@@ -21,6 +21,7 @@ properties: + oneOf: + - const: allwinner,sun6i-a31-spi + - const: allwinner,sun8i-h3-spi ++ - const: allwinner,sun50i-r329-spi + - items: + - enum: + - allwinner,sun8i-r40-spi +@@ -28,6 +29,13 @@ properties: + - allwinner,sun50i-h616-spi + - allwinner,suniv-f1c100s-spi + - const: allwinner,sun8i-h3-spi ++ - items: ++ - const: allwinner,sun20i-d1-spi ++ - const: allwinner,sun50i-r329-spi ++ - items: ++ - const: allwinner,sun20i-d1-spi-dbi ++ - const: allwinner,sun50i-r329-spi-dbi ++ - const: allwinner,sun50i-r329-spi + + reg: + maxItems: 1 diff --git a/target/linux/d1/patches-6.1/0075-spi-spi-sun6i-Use-a-struct-for-quirks.patch b/target/linux/d1/patches-6.1/0075-spi-spi-sun6i-Use-a-struct-for-quirks.patch new file mode 100644 index 0000000000..b13b7accf7 --- /dev/null +++ b/target/linux/d1/patches-6.1/0075-spi-spi-sun6i-Use-a-struct-for-quirks.patch @@ -0,0 +1,109 @@ +From dbc9e83cefe51d19877a4a7349ebbeafa31c0e06 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 16 Jul 2021 21:33:16 -0500 +Subject: [PATCH 075/117] spi: spi-sun6i: Use a struct for quirks + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/spi/spi-sun6i.c | 32 ++++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 10 deletions(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -85,7 +85,12 @@ + #define SUN6I_TXDATA_REG 0x200 + #define SUN6I_RXDATA_REG 0x300 + ++struct sun6i_spi_quirks { ++ unsigned long fifo_depth; ++}; ++ + struct sun6i_spi { ++ const struct sun6i_spi_quirks *quirks; + struct spi_master *master; + void __iomem *base_addr; + dma_addr_t dma_addr_rx; +@@ -100,7 +105,6 @@ struct sun6i_spi { + const u8 *tx_buf; + u8 *rx_buf; + int len; +- unsigned long fifo_depth; + }; + + static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) +@@ -157,7 +161,7 @@ static inline void sun6i_spi_fill_fifo(s + u8 byte; + + /* See how much data we can fit */ +- cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi); ++ cnt = sspi->quirks->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi); + + len = min((int)cnt, sspi->len); + +@@ -300,14 +304,14 @@ static int sun6i_spi_transfer_one(struct + * the hardcoded value used in old generation of Allwinner + * SPI controller. (See spi-sun4i.c) + */ +- trig_level = sspi->fifo_depth / 4 * 3; ++ trig_level = sspi->quirks->fifo_depth / 4 * 3; + } else { + /* + * Setup FIFO DMA request trigger level + * We choose 1/2 of the full fifo depth, that value will + * be used as DMA burst length. + */ +- trig_level = sspi->fifo_depth / 2; ++ trig_level = sspi->quirks->fifo_depth / 2; + + if (tfr->tx_buf) + reg |= SUN6I_FIFO_CTL_TF_DRQ_EN; +@@ -421,9 +425,9 @@ static int sun6i_spi_transfer_one(struct + reg = SUN6I_INT_CTL_TC; + + if (!use_dma) { +- if (rx_len > sspi->fifo_depth) ++ if (rx_len > sspi->quirks->fifo_depth) + reg |= SUN6I_INT_CTL_RF_RDY; +- if (tx_len > sspi->fifo_depth) ++ if (tx_len > sspi->quirks->fifo_depth) + reg |= SUN6I_INT_CTL_TF_ERQ; + } + +@@ -569,7 +573,7 @@ static bool sun6i_spi_can_dma(struct spi + * the fifo length we can just fill the fifo and wait for a single + * irq, so don't bother setting up dma + */ +- return xfer->len > sspi->fifo_depth; ++ return xfer->len > sspi->quirks->fifo_depth; + } + + static int sun6i_spi_probe(struct platform_device *pdev) +@@ -608,7 +612,7 @@ static int sun6i_spi_probe(struct platfo + } + + sspi->master = master; +- sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev); ++ sspi->quirks = of_device_get_match_data(&pdev->dev); + + master->max_speed_hz = 100 * 1000 * 1000; + master->min_speed_hz = 3 * 1000; +@@ -723,9 +727,17 @@ static int sun6i_spi_remove(struct platf + return 0; + } + ++static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = { ++ .fifo_depth = SUN6I_FIFO_DEPTH, ++}; ++ ++static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = { ++ .fifo_depth = SUN8I_FIFO_DEPTH, ++}; ++ + static const struct of_device_id sun6i_spi_match[] = { +- { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH }, +- { .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH }, ++ { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks }, ++ { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks }, + {} + }; + MODULE_DEVICE_TABLE(of, sun6i_spi_match); diff --git a/target/linux/d1/patches-6.1/0076-spi-spi-sun6i-Add-Allwinner-R329-support.patch b/target/linux/d1/patches-6.1/0076-spi-spi-sun6i-Add-Allwinner-R329-support.patch new file mode 100644 index 0000000000..04e1c17f66 --- /dev/null +++ b/target/linux/d1/patches-6.1/0076-spi-spi-sun6i-Add-Allwinner-R329-support.patch @@ -0,0 +1,146 @@ +From ec8dfb455da3822451129257ab21e2f0d03a6ae3 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 16 Jul 2021 21:46:31 -0500 +Subject: [PATCH 076/117] spi: spi-sun6i: Add Allwinner R329 support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/spi/spi-sun6i.c | 78 ++++++++++++++++++++++++++--------------- + 1 file changed, 49 insertions(+), 29 deletions(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -30,6 +30,7 @@ + #define SUN6I_GBL_CTL_REG 0x04 + #define SUN6I_GBL_CTL_BUS_ENABLE BIT(0) + #define SUN6I_GBL_CTL_MASTER BIT(1) ++#define SUN6I_GBL_CTL_SAMPLE_MODE BIT(2) + #define SUN6I_GBL_CTL_TP BIT(7) + #define SUN6I_GBL_CTL_RST BIT(31) + +@@ -87,6 +88,8 @@ + + struct sun6i_spi_quirks { + unsigned long fifo_depth; ++ bool has_divider : 1; ++ bool has_new_sample_mode : 1; + }; + + struct sun6i_spi { +@@ -362,38 +365,44 @@ static int sun6i_spi_transfer_one(struct + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ +- mclk_rate = clk_get_rate(sspi->mclk); +- if (mclk_rate < (2 * tfr->speed_hz)) { +- clk_set_rate(sspi->mclk, 2 * tfr->speed_hz); ++ if (sspi->quirks->has_divider) { + mclk_rate = clk_get_rate(sspi->mclk); +- } ++ if (mclk_rate < (2 * tfr->speed_hz)) { ++ clk_set_rate(sspi->mclk, 2 * tfr->speed_hz); ++ mclk_rate = clk_get_rate(sspi->mclk); ++ } + +- /* +- * Setup clock divider. +- * +- * We have two choices there. Either we can use the clock +- * divide rate 1, which is calculated thanks to this formula: +- * SPI_CLK = MOD_CLK / (2 ^ cdr) +- * Or we can use CDR2, which is calculated with the formula: +- * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) +- * Wether we use the former or the latter is set through the +- * DRS bit. +- * +- * First try CDR2, and if we can't reach the expected +- * frequency, fall back to CDR1. +- */ +- div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz); +- div_cdr2 = DIV_ROUND_UP(div_cdr1, 2); +- if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { +- reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS; +- tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2); ++ /* ++ * Setup clock divider. ++ * ++ * We have two choices there. Either we can use the clock ++ * divide rate 1, which is calculated thanks to this formula: ++ * SPI_CLK = MOD_CLK / (2 ^ cdr) ++ * Or we can use CDR2, which is calculated with the formula: ++ * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) ++ * Wether we use the former or the latter is set through the ++ * DRS bit. ++ * ++ * First try CDR2, and if we can't reach the expected ++ * frequency, fall back to CDR1. ++ */ ++ div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz); ++ div_cdr2 = DIV_ROUND_UP(div_cdr1, 2); ++ if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { ++ reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS; ++ tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2); ++ } else { ++ div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1)); ++ reg = SUN6I_CLK_CTL_CDR1(div); ++ tfr->effective_speed_hz = mclk_rate / (1 << div); ++ } ++ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); + } else { +- div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1)); +- reg = SUN6I_CLK_CTL_CDR1(div); +- tfr->effective_speed_hz = mclk_rate / (1 << div); ++ clk_set_rate(sspi->mclk, tfr->speed_hz); ++ mclk_rate = clk_get_rate(sspi->mclk); ++ tfr->effective_speed_hz = mclk_rate; + } + +- sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); + /* Finally enable the bus - doing so before might raise SCK to HIGH */ + reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG); + reg |= SUN6I_GBL_CTL_BUS_ENABLE; +@@ -518,6 +527,7 @@ static int sun6i_spi_runtime_resume(stru + struct spi_master *master = dev_get_drvdata(dev); + struct sun6i_spi *sspi = spi_master_get_devdata(master); + int ret; ++ u32 reg; + + ret = clk_prepare_enable(sspi->hclk); + if (ret) { +@@ -537,8 +547,10 @@ static int sun6i_spi_runtime_resume(stru + goto err2; + } + +- sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, +- SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); ++ reg = SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP; ++ if (sspi->quirks->has_new_sample_mode) ++ reg |= SUN6I_GBL_CTL_SAMPLE_MODE; ++ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg); + + return 0; + +@@ -729,15 +741,23 @@ static int sun6i_spi_remove(struct platf + + static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = { + .fifo_depth = SUN6I_FIFO_DEPTH, ++ .has_divider = true, + }; + + static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = { + .fifo_depth = SUN8I_FIFO_DEPTH, ++ .has_divider = true, ++}; ++ ++static const struct sun6i_spi_quirks sun50i_r329_spi_quirks = { ++ .fifo_depth = SUN8I_FIFO_DEPTH, ++ .has_new_sample_mode = true, + }; + + static const struct of_device_id sun6i_spi_match[] = { + { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks }, + { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks }, ++ { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_quirks }, + {} + }; + MODULE_DEVICE_TABLE(of, sun6i_spi_match); diff --git a/target/linux/d1/patches-6.1/0077-spi-spi-sun6i-Dual-Quad-RX-Support.patch b/target/linux/d1/patches-6.1/0077-spi-spi-sun6i-Dual-Quad-RX-Support.patch new file mode 100644 index 0000000000..ab7df5fe87 --- /dev/null +++ b/target/linux/d1/patches-6.1/0077-spi-spi-sun6i-Dual-Quad-RX-Support.patch @@ -0,0 +1,50 @@ +From b300b013de16109f833782d9f4e7ee8cc204780f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 17 Jul 2021 11:19:29 -0500 +Subject: [PATCH 077/117] spi: spi-sun6i: Dual/Quad RX Support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/spi/spi-sun6i.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -82,6 +82,8 @@ + #define SUN6I_XMIT_CNT_REG 0x34 + + #define SUN6I_BURST_CTL_CNT_REG 0x38 ++#define SUN6I_BURST_CTL_CNT_QUAD_EN BIT(29) ++#define SUN6I_BURST_CTL_CNT_DUAL_EN BIT(28) + + #define SUN6I_TXDATA_REG 0x200 + #define SUN6I_RXDATA_REG 0x300 +@@ -415,7 +417,17 @@ static int sun6i_spi_transfer_one(struct + /* Setup the counters */ + sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len); + sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len); +- sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len); ++ ++ reg = tx_len; ++ switch (tfr->rx_nbits) { ++ case SPI_NBITS_QUAD: ++ reg |= SUN6I_BURST_CTL_CNT_QUAD_EN; ++ break; ++ case SPI_NBITS_DUAL: ++ reg |= SUN6I_BURST_CTL_CNT_DUAL_EN; ++ break; ++ } ++ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg); + + if (!use_dma) { + /* Fill the TX FIFO */ +@@ -632,7 +644,8 @@ static int sun6i_spi_probe(struct platfo + master->set_cs = sun6i_spi_set_cs; + master->transfer_one = sun6i_spi_transfer_one; + master->num_chipselect = 4; +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST ++ | SPI_RX_DUAL | SPI_RX_QUAD; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; diff --git a/target/linux/d1/patches-6.1/0078-riscv-dts-allwinner-Add-SPI-support.patch b/target/linux/d1/patches-6.1/0078-riscv-dts-allwinner-Add-SPI-support.patch new file mode 100644 index 0000000000..67a3dfb32b --- /dev/null +++ b/target/linux/d1/patches-6.1/0078-riscv-dts-allwinner-Add-SPI-support.patch @@ -0,0 +1,154 @@ +From aaabd3cf8c041b5122ca252f51fa616833e18749 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 00:54:01 -0500 +Subject: [PATCH 078/117] riscv: dts: allwinner: Add SPI support + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../dts/allwinner/sun20i-d1-lichee-rv.dts | 6 +++ + .../boot/dts/allwinner/sun20i-d1-nezha.dts | 44 ++++++++++++++++ + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 51 +++++++++++++++++++ + 3 files changed, 101 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv.dts +@@ -65,6 +65,12 @@ + status = "okay"; + }; + ++&spi0 { ++ pinctrl-0 = <&spi0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-0 = <&uart0_pb8_pins>; + pinctrl-names = "default"; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts +@@ -19,6 +19,7 @@ + ethernet1 = &xr829; + mmc0 = &mmc0; + serial0 = &uart0; ++ spi0 = &spi0; + }; + + chosen { +@@ -157,6 +158,49 @@ + pinctrl-names = "default"; + status = "okay"; + }; ++ ++&spi0 { ++ pinctrl-0 = <&spi0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "boot0"; ++ reg = <0x00000000 0x00100000>; ++ }; ++ ++ partition@100000 { ++ label = "uboot"; ++ reg = <0x00100000 0x00300000>; ++ }; ++ ++ partition@400000 { ++ label = "secure_storage"; ++ reg = <0x00400000 0x00100000>; ++ }; ++ ++ partition@500000 { ++ label = "sys"; ++ reg = <0x00500000 0x0fb00000>; ++ }; ++ }; ++ }; ++}; ++ ++&spi1 { ++ pinctrl-0 = <&spi1_pd_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; + + &uart0 { + pinctrl-0 = <&uart0_pb8_pins>; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -179,6 +179,24 @@ + }; + + /omit-if-no-ref/ ++ spi0_pins: spi0-pins { ++ pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7"; ++ function = "spi0"; ++ }; ++ ++ /omit-if-no-ref/ ++ spi1_pb_pins: spi1-pb-pins { ++ pins = "PB0", "PB8", "PB9", "PB10", "PB11", "PB12"; ++ function = "spi1"; ++ }; ++ ++ /omit-if-no-ref/ ++ spi1_pd_pins: spi1-pd-pins { ++ pins = "PD10", "PD11", "PD12", "PD13", "PD14", "PD15"; ++ function = "spi1"; ++ }; ++ ++ /omit-if-no-ref/ + uart0_pb8_pins: uart0-pb8-pins { + pins = "PB8", "PB9"; + function = "uart0"; +@@ -631,6 +649,39 @@ + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; ++ }; ++ ++ spi0: spi@4025000 { ++ compatible = "allwinner,sun20i-d1-spi", ++ "allwinner,sun50i-r329-spi"; ++ reg = <0x4025000 0x1000>; ++ interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; ++ clock-names = "ahb", "mod"; ++ resets = <&ccu RST_BUS_SPI0>; ++ dmas = <&dma 22>, <&dma 22>; ++ dma-names = "rx", "tx"; ++ num-cs = <1>; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ spi1: spi@4026000 { ++ compatible = "allwinner,sun20i-d1-spi-dbi", ++ "allwinner,sun50i-r329-spi-dbi", ++ "allwinner,sun50i-r329-spi"; ++ reg = <0x4026000 0x1000>; ++ interrupts = <32 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>; ++ clock-names = "ahb", "mod"; ++ resets = <&ccu RST_BUS_SPI1>; ++ dmas = <&dma 23>, <&dma 23>; ++ dma-names = "rx", "tx"; ++ num-cs = <1>; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; + }; + + usb_otg: usb@4100000 { diff --git a/target/linux/d1/patches-6.1/0079-dt-bindings-thermal-sun8i-Add-compatible-for-D1.patch b/target/linux/d1/patches-6.1/0079-dt-bindings-thermal-sun8i-Add-compatible-for-D1.patch new file mode 100644 index 0000000000..6ba5b3ac75 --- /dev/null +++ b/target/linux/d1/patches-6.1/0079-dt-bindings-thermal-sun8i-Add-compatible-for-D1.patch @@ -0,0 +1,80 @@ +From 68c6f452bf42d6c5cbaf40537d8a17a7f3f5481e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 6 Jun 2021 10:03:12 -0500 +Subject: [PATCH 079/117] dt-bindings: thermal: sun8i: Add compatible for D1 + +D1 contains a thermal sensor similar to other Allwinner SoCs. Like the +H3 variant, it contains only one channel. + +D1's thermal sensor gets a reference voltage from AVCC. This may always +have been the case; it is explicitly documented in the SoC user manuals +since at least H616. However, it was not as important on earlier SoCs, +because those reference designs foreced AVCC always-on by connecting it +to the PLL power supply. + +Now, since D1 only uses AVCC for other optional peripherals, this supply +could be turned off at runtime, so it must be made explicit in the DTS. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../thermal/allwinner,sun8i-a83t-ths.yaml | 21 ++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml ++++ b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml +@@ -16,6 +16,7 @@ properties: + - allwinner,sun8i-a83t-ths + - allwinner,sun8i-h3-ths + - allwinner,sun8i-r40-ths ++ - allwinner,sun20i-d1-ths + - allwinner,sun50i-a64-ths + - allwinner,sun50i-a100-ths + - allwinner,sun50i-h5-ths +@@ -55,6 +56,10 @@ properties: + - 0 + - 1 + ++ vref-supply: ++ description: ++ Regulator for the analog reference voltage ++ + allOf: + - if: + properties: +@@ -84,7 +89,9 @@ allOf: + properties: + compatible: + contains: +- const: allwinner,sun8i-h3-ths ++ enum: ++ - allwinner,sun8i-h3-ths ++ - allwinner,sun20i-d1-ths + + then: + properties: +@@ -103,6 +110,7 @@ allOf: + enum: + - allwinner,sun8i-h3-ths + - allwinner,sun8i-r40-ths ++ - allwinner,sun20i-d1-ths + - allwinner,sun50i-a64-ths + - allwinner,sun50i-a100-ths + - allwinner,sun50i-h5-ths +@@ -114,6 +122,17 @@ allOf: + - clock-names + - resets + ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - allwinner,sun20i-d1-ths ++ ++ then: ++ required: ++ - vref-supply ++ + required: + - compatible + - reg diff --git a/target/linux/d1/patches-6.1/0080-riscv-dts-allwinner-d1-Add-thermal-sensor-and-zone.patch b/target/linux/d1/patches-6.1/0080-riscv-dts-allwinner-d1-Add-thermal-sensor-and-zone.patch new file mode 100644 index 0000000000..9bfb74b895 --- /dev/null +++ b/target/linux/d1/patches-6.1/0080-riscv-dts-allwinner-d1-Add-thermal-sensor-and-zone.patch @@ -0,0 +1,79 @@ +From c225b48d2cf5f5a824b5b0a4144511bdc5f65ab5 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 14 Aug 2022 11:18:11 -0500 +Subject: [PATCH 080/117] riscv: dts: allwinner: d1: Add thermal sensor and + zone + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../sun20i-d1-common-regulators.dtsi | 4 ++ + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 41 +++++++++++++++++++ + 2 files changed, 45 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi +@@ -49,3 +49,7 @@ + regulator-max-microvolt = <1800000>; + ldo-in-supply = <®_vcc_3v3>; + }; ++ ++&ths { ++ vref-supply = <®_aldo>; ++}; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -59,6 +59,35 @@ + #clock-cells = <0>; + }; + ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <0>; ++ polling-delay-passive = <0>; ++ thermal-sensors = <&ths>; ++ ++ trips { ++ cpu_target: cpu-target { ++ hysteresis = <3000>; ++ temperature = <85000>; ++ type = "passive"; ++ }; ++ ++ cpu-crit { ++ hysteresis = <0>; ++ temperature = <110000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_target>; ++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ + soc { + compatible = "simple-bus"; + ranges; +@@ -252,6 +281,18 @@ + #size-cells = <0>; + }; + ++ ths: temperature-sensor@2009400 { ++ compatible = "allwinner,sun20i-d1-ths"; ++ reg = <0x2009400 0x400>; ++ interrupts = <74 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_THS>, <&osc24M>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_THS>; ++ nvmem-cells = <&ths_calib>; ++ nvmem-cell-names = "calibration"; ++ #thermal-sensor-cells = <0>; ++ }; ++ + lradc: keys@2009800 { + compatible = "allwinner,sun20i-d1-lradc", + "allwinner,sun50i-r329-lradc"; diff --git a/target/linux/d1/patches-6.1/0081-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch b/target/linux/d1/patches-6.1/0081-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch new file mode 100644 index 0000000000..6460d84f07 --- /dev/null +++ b/target/linux/d1/patches-6.1/0081-ASoC-sun20i-codec-New-driver-for-D1-internal-codec.patch @@ -0,0 +1,927 @@ +From 9b6a07cacab9300c261b1f7e25857f96cfeae9cf Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sat, 12 Jun 2021 23:42:48 -0500 +Subject: [PATCH 081/117] ASoC: sun20i-codec: New driver for D1 internal codec + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/Kconfig | 6 + + sound/soc/sunxi/Makefile | 1 + + sound/soc/sunxi/sun20i-codec.c | 886 +++++++++++++++++++++++++++++++++ + 3 files changed, 893 insertions(+) + create mode 100644 sound/soc/sunxi/sun20i-codec.c + +--- a/sound/soc/sunxi/Kconfig ++++ b/sound/soc/sunxi/Kconfig +@@ -30,6 +30,12 @@ config SND_SUN8I_CODEC_ANALOG + Say Y or M if you want to add support for the analog controls for + the codec embedded in newer Allwinner SoCs. + ++config SND_SUN20I_CODEC ++ tristate "Allwinner D1 (sun20i) Audio Codec" ++ depends on ARCH_SUNXI || COMPILE_TEST ++ help ++ Say Y or M to add support for the audio codec in Allwinner D1 SoC. ++ + config SND_SUN50I_CODEC_ANALOG + tristate "Allwinner sun50i Codec Analog Controls Support" + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST +--- a/sound/soc/sunxi/Makefile ++++ b/sound/soc/sunxi/Makefile +@@ -3,6 +3,7 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-c + obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o + obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o + obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o ++obj-$(CONFIG_SND_SUN20I_CODEC) += sun20i-codec.o + obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o + obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o + obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o +--- /dev/null ++++ b/sound/soc/sunxi/sun20i-codec.c +@@ -0,0 +1,886 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++ ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/reset.h> ++ ++#include <sound/dmaengine_pcm.h> ++#include <sound/pcm_params.h> ++#include <sound/simple_card_utils.h> ++#include <sound/soc.h> ++#include <sound/soc-dai.h> ++#include <sound/soc-dapm.h> ++#include <sound/tlv.h> ++ ++#define SUN20I_CODEC_DAC_DPC 0x0000 ++#define SUN20I_CODEC_DAC_DPC_EN_DA 31 ++#define SUN20I_CODEC_DAC_DPC_HPF_EN 18 ++#define SUN20I_CODEC_DAC_DPC_DVOL 12 ++#define SUN20I_CODEC_DAC_VOL_CTRL 0x0004 ++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL 16 ++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_L 8 ++#define SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_R 0 ++#define SUN20I_CODEC_DAC_FIFOC 0x0010 ++#define SUN20I_CODEC_DAC_FIFOC_FS 29 ++#define SUN20I_CODEC_DAC_FIFOC_FIFO_MODE 24 ++#define SUN20I_CODEC_DAC_FIFOC_DRQ_CLR_CNT 21 ++#define SUN20I_CODEC_DAC_FIFOC_TRIG_LEVEL 8 ++#define SUN20I_CODEC_DAC_FIFOC_MONO_EN 6 ++#define SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS 5 ++#define SUN20I_CODEC_DAC_FIFOC_DRQ_EN 4 ++#define SUN20I_CODEC_DAC_FIFOC_FIFO_FLUSH 0 ++#define SUN20I_CODEC_DAC_TXDATA 0x0020 ++#define SUN20I_CODEC_DAC_DEBUG 0x0028 ++#define SUN20I_CODEC_DAC_DEBUG_DA_SWP 6 ++#define SUN20I_CODEC_DAC_ADDA_LOOP_MODE 0 ++ ++#define SUN20I_CODEC_ADC_FIFOC 0x0030 ++#define SUN20I_CODEC_ADC_FIFOC_FS 29 ++#define SUN20I_CODEC_ADC_FIFOC_EN_AD 28 ++#define SUN20I_CODEC_ADC_FIFOC_FIFO_MODE 24 ++#define SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS 16 ++#define SUN20I_CODEC_ADC_FIFOC_TRIG_LEVEL 4 ++#define SUN20I_CODEC_ADC_FIFOC_DRQ_EN 3 ++#define SUN20I_CODEC_ADC_FIFOC_FIFO_FLUSH 0 ++#define SUN20I_CODEC_ADC_VOL_CTRL 0x0034 ++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC3_VOL 16 ++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC2_VOL 8 ++#define SUN20I_CODEC_ADC_VOL_CTRL_ADC1_VOL 0 ++#define SUN20I_CODEC_ADC_RXDATA 0x0040 ++#define SUN20I_CODEC_ADC_DEBUG 0x004c ++#define SUN20I_CODEC_ADC_DEBUG_AD_SWP1 24 ++#define SUN20I_CODEC_ADC_DIG_CTRL 0x0050 ++#define SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN 16 ++#define SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN 0 ++ ++#define SUN20I_CODEC_DAC_DAP_CTRL 0x00f0 ++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_EN 31 ++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_DRC_EN 29 ++#define SUN20I_CODEC_DAC_DAP_CTRL_DAP_HPF_EN 28 ++ ++#define SUN20I_CODEC_ADC_DAP_CTRL 0x00f8 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_EN 31 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_DRC_EN 29 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP0_HPF_EN 28 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_EN 27 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_DRC_EN 25 ++#define SUN20I_CODEC_ADC_DAP_CTRL_DAP1_HPF_EN 24 ++ ++#define SUN20I_CODEC_ADC1 0x0300 ++#define SUN20I_CODEC_ADC1_ADC1_EN 31 ++#define SUN20I_CODEC_ADC1_MICIN1_PGA_EN 30 ++#define SUN20I_CODEC_ADC1_ADC1_DITHER_EN 29 ++#define SUN20I_CODEC_ADC1_MICIN1_SIN_EN 28 ++#define SUN20I_CODEC_ADC1_FMINL_EN 27 ++#define SUN20I_CODEC_ADC1_FMINL_GAIN 26 ++#define SUN20I_CODEC_ADC1_DITHER_LEVEL 24 ++#define SUN20I_CODEC_ADC1_LINEINL_EN 23 ++#define SUN20I_CODEC_ADC1_LINEINL_GAIN 22 ++#define SUN20I_CODEC_ADC1_ADC1_PGA_GAIN 8 ++#define SUN20I_CODEC_ADC2 0x0304 ++#define SUN20I_CODEC_ADC2_ADC2_EN 31 ++#define SUN20I_CODEC_ADC2_MICIN2_PGA_EN 30 ++#define SUN20I_CODEC_ADC2_ADC2_DITHER_EN 29 ++#define SUN20I_CODEC_ADC2_MICIN2_SIN_EN 28 ++#define SUN20I_CODEC_ADC2_FMINR_EN 27 ++#define SUN20I_CODEC_ADC2_FMINR_GAIN 26 ++#define SUN20I_CODEC_ADC2_DITHER_LEVEL 24 ++#define SUN20I_CODEC_ADC2_LINEINR_EN 23 ++#define SUN20I_CODEC_ADC2_LINEINR_GAIN 22 ++#define SUN20I_CODEC_ADC2_ADC2_PGA_GAIN 8 ++#define SUN20I_CODEC_ADC3 0x0308 ++#define SUN20I_CODEC_ADC3_ADC3_EN 31 ++#define SUN20I_CODEC_ADC3_MICIN3_PGA_EN 30 ++#define SUN20I_CODEC_ADC3_ADC3_DITHER_EN 29 ++#define SUN20I_CODEC_ADC3_MICIN3_SIN_EN 28 ++#define SUN20I_CODEC_ADC3_DITHER_LEVEL 24 ++#define SUN20I_CODEC_ADC3_ADC3_PGA_GAIN 8 ++ ++#define SUN20I_CODEC_DAC 0x0310 ++#define SUN20I_CODEC_DAC_DACL_EN 15 ++#define SUN20I_CODEC_DAC_DACR_EN 14 ++#define SUN20I_CODEC_DAC_LINEOUTL_EN 13 ++#define SUN20I_CODEC_DAC_LMUTE 12 ++#define SUN20I_CODEC_DAC_LINEOUTR_EN 11 ++#define SUN20I_CODEC_DAC_RMUTE 10 ++#define SUN20I_CODEC_DAC_LINEOUTL_DIFFEN 6 ++#define SUN20I_CODEC_DAC_LINEOUTR_DIFFEN 5 ++#define SUN20I_CODEC_DAC_LINEOUT_VOL_CTRL 0 ++ ++#define SUN20I_CODEC_MICBIAS 0x0318 ++#define SUN20I_CODEC_MICBIAS_SELDETADCFS 28 ++#define SUN20I_CODEC_MICBIAS_SELDETADCDB 26 ++#define SUN20I_CODEC_MICBIAS_SELDETADCBF 24 ++#define SUN20I_CODEC_MICBIAS_JACKDETEN 23 ++#define SUN20I_CODEC_MICBIAS_SELDETADCDY 21 ++#define SUN20I_CODEC_MICBIAS_MICADCEN 20 ++#define SUN20I_CODEC_MICBIAS_POPFREE 19 ++#define SUN20I_CODEC_MICBIAS_DET_MODE 18 ++#define SUN20I_CODEC_MICBIAS_AUTOPLEN 17 ++#define SUN20I_CODEC_MICBIAS_MICDETPL 16 ++#define SUN20I_CODEC_MICBIAS_HMICBIASEN 15 ++#define SUN20I_CODEC_MICBIAS_HMICBIASSEL 13 ++#define SUN20I_CODEC_MICBIAS_HMIC_CHOPPER_EN 12 ++#define SUN20I_CODEC_MICBIAS_HMIC_CHOPPER_CLK 10 ++#define SUN20I_CODEC_MICBIAS_MMICBIASEN 7 ++#define SUN20I_CODEC_MICBIAS_MMICBIASSEL 5 ++#define SUN20I_CODEC_MICBIAS_MMIC_CHOPPER_EN 4 ++#define SUN20I_CODEC_MICBIAS_MMIC_CHOPPER_CLK 2 ++ ++/* TODO */ ++#define SUN20I_CODEC_RAMP 0x031c ++#define SUN20I_CODEC_RAMP_HP_PULL_OUT_EN 15 ++ ++#define SUN20I_CODEC_HMIC_CTRL 0x0328 ++#define SUN20I_CODEC_HMIC_CTRL_SAMPLE_SELECT 21 ++#define SUN20I_CODEC_HMIC_CTRL_MDATA_THRESHOLD 16 ++#define SUN20I_CODEC_HMIC_CTRL_SF 14 ++#define SUN20I_CODEC_HMIC_CTRL_M 10 ++#define SUN20I_CODEC_HMIC_CTRL_N 6 ++#define SUN20I_CODEC_HMIC_CTRL_THRESH_DEBOUNCE 3 ++#define SUN20I_CODEC_HMIC_CTRL_JACK_OUT_IRQ_EN 2 ++#define SUN20I_CODEC_HMIC_CTRL_JACK_IN_IRQ_EN 1 ++#define SUN20I_CODEC_HMIC_CTRL_MIC_DET_IRQ_EN 0 ++#define SUN20I_CODEC_HMIC_STS 0x032c ++#define SUN20I_CODEC_HMIC_STS_MDATA_DISCARD 13 ++#define SUN20I_CODEC_HMIC_STS_HMIC_DATA 8 ++#define SUN20I_CODEC_HMIC_STS_JACK_OUT_IRQ 4 ++#define SUN20I_CODEC_HMIC_STS_JACK_IN_IRQ 3 ++#define SUN20I_CODEC_HMIC_STS_MIC_DET_IRQ 0 ++ ++#define SUN20I_CODEC_HP2 0x0340 ++#define SUN20I_CODEC_HP2_HPFB_BUF_EN 31 ++#define SUN20I_CODEC_HP2_HEADPHONE_GAIN 28 ++#define SUN20I_CODEC_HP2_HPFB_RES 26 ++#define SUN20I_CODEC_HP2_HP_DRVEN 21 ++#define SUN20I_CODEC_HP2_HP_DRVOUTEN 20 ++#define SUN20I_CODEC_HP2_RSWITCH 19 ++#define SUN20I_CODEC_HP2_RAMPEN 18 ++#define SUN20I_CODEC_HP2_HPFB_IN_EN 17 ++#define SUN20I_CODEC_HP2_RAMP_FINAL_CONTROL 16 ++#define SUN20I_CODEC_HP2_RAMP_OUT_EN 15 ++#define SUN20I_CODEC_HP2_RAMP_FINAL_STATE_RES 13 ++ ++/* Not affected by codec bus clock/reset */ ++#define SUN20I_CODEC_POWER 0x0348 ++#define SUN20I_CODEC_POWER_ALDO_EN_MASK BIT(31) ++#define SUN20I_CODEC_POWER_HPLDO_EN_MASK BIT(30) ++#define SUN20I_CODEC_POWER_ALDO_VOLTAGE_MASK GENMASK(14, 12) ++#define SUN20I_CODEC_POWER_HPLDO_VOLTAGE_MASK GENMASK(10, 8) ++ ++#define SUN20I_CODEC_ADC_CUR 0x034c ++ ++#define SUN20I_CODEC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE|\ ++ SNDRV_PCM_FMTBIT_S20_LE|\ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++#define DRIVER_NAME "sun20i-codec" ++ ++/* snd_soc_register_card() takes over drvdata, so the card must be first! */ ++struct sun20i_codec { ++ struct snd_soc_card card; ++ struct snd_soc_dai_link dai_link; ++ struct snd_soc_dai_link_component dlcs[3]; ++ struct snd_dmaengine_dai_dma_data dma_data[2]; ++ ++ struct clk *bus_clk; ++ struct clk *adc_clk; ++ struct clk *dac_clk; ++ struct reset_control *reset; ++}; ++ ++static int sun20i_codec_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai); ++ ++ snd_soc_dai_init_dma_data(dai, ++ &codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK], ++ &codec->dma_data[SNDRV_PCM_STREAM_CAPTURE]); ++ ++ return 0; ++} ++ ++static struct clk *sun20i_codec_get_clk(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai); ++ ++ return substream->stream == SNDRV_PCM_STREAM_CAPTURE ? ++ codec->adc_clk : codec->dac_clk; ++} ++ ++static const unsigned int sun20i_codec_rates[] = { ++ 7350, 8000, 11025, 12000, 14700, 16000, 22050, 24000, ++ 29400, 32000, 44100, 48000, 88200, 96000, 176400, 192000, ++}; ++ ++static const struct snd_pcm_hw_constraint_list sun20i_codec_rate_lists[] = { ++ [SNDRV_PCM_STREAM_PLAYBACK] = { ++ .list = sun20i_codec_rates, ++ .count = ARRAY_SIZE(sun20i_codec_rates), ++ }, ++ [SNDRV_PCM_STREAM_CAPTURE] = { ++ .list = sun20i_codec_rates, ++ .count = ARRAY_SIZE(sun20i_codec_rates) - 4, /* max 48 kHz */ ++ }, ++}; ++ ++static int sun20i_codec_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ const struct snd_pcm_hw_constraint_list *list; ++ int ret; ++ ++ list = &sun20i_codec_rate_lists[substream->stream]; ++ ret = snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, list); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(sun20i_codec_get_clk(substream, dai)); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void sun20i_codec_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ clk_disable_unprepare(sun20i_codec_get_clk(substream, dai)); ++} ++ ++static unsigned int sun20i_codec_get_clk_rate(unsigned int sample_rate) ++{ ++ return (sample_rate % 4000) ? 22579200 : 24576000; ++} ++ ++static const unsigned short sun20i_codec_divisors[] = { ++ 512, 1024, 2048, 128, ++ 768, 1536, 3072, 256, ++}; ++ ++static int sun20i_codec_get_fs(unsigned int clk_rate, unsigned int sample_rate) ++{ ++ unsigned int divisor = clk_rate / sample_rate; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sun20i_codec_divisors); ++i) ++ if (sun20i_codec_divisors[i] == divisor) ++ return i; ++ ++ return -EINVAL; ++} ++ ++static int sun20i_codec_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct sun20i_codec *codec = snd_soc_dai_get_drvdata(dai); ++ struct snd_soc_component *component = dai->component; ++ unsigned int channels = params_channels(params); ++ unsigned int sample_bits = params_width(params); ++ unsigned int sample_rate = params_rate(params); ++ unsigned int clk_rate = sun20i_codec_get_clk_rate(sample_rate); ++ enum dma_slave_buswidth dma_width; ++ unsigned int reg; ++ int ret, val; ++ ++ switch (params_physical_width(params)) { ++ case 16: ++ dma_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ++ break; ++ case 32: ++ dma_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ break; ++ default: ++ dev_err(dai->dev, "Unsupported physical sample width: %d\n", ++ params_physical_width(params)); ++ return -EINVAL; ++ } ++ codec->dma_data[substream->stream].addr_width = dma_width; ++ ++ ret = clk_set_rate(sun20i_codec_get_clk(substream, dai), ++ sun20i_codec_get_clk_rate(sample_rate)); ++ if (ret) ++ return ret; ++ ++ reg = substream->stream == SNDRV_PCM_STREAM_CAPTURE ? ++ SUN20I_CODEC_ADC_FIFOC : SUN20I_CODEC_DAC_FIFOC; ++ ++ val = sun20i_codec_get_fs(clk_rate, sample_rate); ++ if (val < 0) ++ return val; ++ snd_soc_component_update_bits(component, reg, ++ 0x7 << SUN20I_CODEC_DAC_FIFOC_FS, ++ val << SUN20I_CODEC_DAC_FIFOC_FS); ++ ++ /* Data is at MSB for full 4-byte samples, otherwise at LSB. */ ++ val = sample_bits != 32; ++ snd_soc_component_update_bits(component, reg, ++ 0x1 << SUN20I_CODEC_DAC_FIFOC_FIFO_MODE, ++ val << SUN20I_CODEC_DAC_FIFOC_FIFO_MODE); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ val = sample_bits > 16; ++ snd_soc_component_update_bits(component, reg, ++ 0x1 << SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS, ++ val << SUN20I_CODEC_ADC_FIFOC_SAMPLE_BITS); ++ ++ val = BIT(channels) - 1; ++ snd_soc_component_update_bits(component, SUN20I_CODEC_ADC_DIG_CTRL, ++ 0xf << SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN, ++ val << SUN20I_CODEC_ADC_DIG_CTRL_ADC_EN); ++ } else { ++ val = sample_bits > 16; ++ snd_soc_component_update_bits(component, reg, ++ 0x1 << SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS, ++ val << SUN20I_CODEC_DAC_FIFOC_SAMPLE_BITS); ++ ++ val = channels == 1; ++ snd_soc_component_update_bits(component, reg, ++ 0x1 << SUN20I_CODEC_DAC_FIFOC_MONO_EN, ++ val << SUN20I_CODEC_DAC_FIFOC_MONO_EN); ++ } ++ ++ return 0; ++} ++ ++static int sun20i_codec_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ unsigned int reg, mask; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ reg = SUN20I_CODEC_ADC_FIFOC; ++ mask = BIT(SUN20I_CODEC_ADC_FIFOC_DRQ_EN); ++ } else { ++ reg = SUN20I_CODEC_DAC_FIFOC; ++ mask = BIT(SUN20I_CODEC_DAC_FIFOC_DRQ_EN); ++ } ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ mask |= BIT(SUN20I_CODEC_DAC_FIFOC_FIFO_FLUSH); ++ snd_soc_component_update_bits(component, reg, mask, mask); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ snd_soc_component_update_bits(component, reg, mask, 0); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct snd_soc_dai_ops sun20i_codec_dai_ops = { ++ .startup = sun20i_codec_startup, ++ .shutdown = sun20i_codec_shutdown, ++ .hw_params = sun20i_codec_hw_params, ++ .trigger = sun20i_codec_trigger, ++}; ++ ++static struct snd_soc_dai_driver sun20i_codec_dai = { ++ .name = DRIVER_NAME, ++ .probe = sun20i_codec_dai_probe, ++ .ops = &sun20i_codec_dai_ops, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 3, /* ??? */ ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SUN20I_CODEC_PCM_FORMATS, ++ .sig_bits = 20, ++ }, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SUN20I_CODEC_PCM_FORMATS, ++ .sig_bits = 20, ++ }, ++}; ++ ++static const DECLARE_TLV_DB_SCALE(sun20i_codec_boost_vol_scale, 0, 600, 0); ++static const DECLARE_TLV_DB_SCALE(sun20i_codec_digital_vol_scale, -12000, 75, 1); ++static const DECLARE_TLV_DB_SCALE(sun20i_codec_headphone_vol_scale, -4200, 600, 0); ++/* FIXME */ ++static const DECLARE_TLV_DB_SCALE(sun20i_codec_line_out_vol_scale, -4650, 150, 1); ++/* FIXME */ ++static const DECLARE_TLV_DB_SCALE(sun20i_codec_pga_vol_scale, 500, 100, 0); ++ ++static const char *const sun20i_codec_line_out_mode_enum_text[] = { ++ "Single-Ended", "Differential" ++}; ++ ++static const SOC_ENUM_DOUBLE_DECL(sun20i_codec_line_out_mode_enum, ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_LINEOUTL_DIFFEN, ++ SUN20I_CODEC_DAC_LINEOUTR_DIFFEN, ++ sun20i_codec_line_out_mode_enum_text); ++ ++static const struct snd_kcontrol_new sun20i_codec_controls[] = { ++ /* Digital Controls */ ++ SOC_DOUBLE_TLV("DAC Playback Volume", ++ SUN20I_CODEC_DAC_VOL_CTRL, ++ SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_L, ++ SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_R, ++ 0xc0, 0, sun20i_codec_digital_vol_scale), ++ SOC_SINGLE_TLV("ADC3 Capture Volume", ++ SUN20I_CODEC_ADC_VOL_CTRL, ++ SUN20I_CODEC_ADC_VOL_CTRL_ADC3_VOL, ++ 0xc0, 0, sun20i_codec_digital_vol_scale), ++ SOC_SINGLE_TLV("ADC2 Capture Volume", ++ SUN20I_CODEC_ADC_VOL_CTRL, ++ SUN20I_CODEC_ADC_VOL_CTRL_ADC2_VOL, ++ 0xc0, 0, sun20i_codec_digital_vol_scale), ++ SOC_SINGLE_TLV("ADC1 Capture Volume", ++ SUN20I_CODEC_ADC_VOL_CTRL, ++ SUN20I_CODEC_ADC_VOL_CTRL_ADC1_VOL, ++ 0xc0, 0, sun20i_codec_digital_vol_scale), ++ ++ /* Analog Controls */ ++ SOC_DOUBLE_R_TLV("FM Capture Volume", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC1_FMINL_GAIN, ++ 0x1, 0, sun20i_codec_boost_vol_scale), ++ SOC_DOUBLE_R_TLV("Line In Capture Volume", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC1_LINEINL_GAIN, ++ 0x1, 0, sun20i_codec_boost_vol_scale), ++ SOC_ENUM("Line Out Mode Playback Enum", ++ sun20i_codec_line_out_mode_enum), ++ SOC_SINGLE_TLV("Line Out Playback Volume", ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_LINEOUT_VOL_CTRL, ++ 0x1f, 0, sun20i_codec_line_out_vol_scale), ++ SOC_SINGLE_TLV("Headphone Playback Volume", ++ SUN20I_CODEC_HP2, ++ SUN20I_CODEC_HP2_HEADPHONE_GAIN, ++ 0x7, 1, sun20i_codec_headphone_vol_scale), ++}; ++ ++static const struct snd_kcontrol_new sun20i_codec_line_out_switch = ++ SOC_DAPM_DOUBLE("Line Out Playback Switch", ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_LMUTE, ++ SUN20I_CODEC_DAC_RMUTE, 1, 1); ++ ++static const struct snd_kcontrol_new sun20i_codec_hp_switch = ++ SOC_DAPM_SINGLE("Headphone Playback Switch", ++ SUN20I_CODEC_HP2, ++ SUN20I_CODEC_HP2_HP_DRVOUTEN, 1, 0); ++ ++static const struct snd_kcontrol_new sun20i_codec_adc12_mixer_controls[] = { ++ /* ADC1 Only */ ++ SOC_DAPM_SINGLE("Mic1 Capture Switch", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC1_MICIN1_SIN_EN, 1, 0), ++ /* Shared */ ++ SOC_DAPM_DOUBLE_R("FM Capture Switch", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC1_FMINL_EN, 1, 0), ++ /* Shared */ ++ SOC_DAPM_DOUBLE_R("Line In Capture Switch", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC1_LINEINL_EN, 1, 0), ++ /* ADC2 Only */ ++ SOC_DAPM_SINGLE("Mic2 Capture Switch", ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC2_MICIN2_SIN_EN, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new sun20i_codec_adc3_mixer_controls[] = { ++ SOC_DAPM_SINGLE("Mic3 Capture Switch", ++ SUN20I_CODEC_ADC3, ++ SUN20I_CODEC_ADC3_MICIN3_SIN_EN, 1, 0), ++}; ++ ++static const struct snd_kcontrol_new sun20i_codec_mic1_volume = ++ SOC_DAPM_SINGLE_TLV("Capture Volume", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC1_ADC1_PGA_GAIN, ++ 0x1f, 0, sun20i_codec_pga_vol_scale); ++ ++static const struct snd_kcontrol_new sun20i_codec_mic2_volume = ++ SOC_DAPM_SINGLE_TLV("Capture Volume", ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC2_ADC2_PGA_GAIN, ++ 0x1f, 0, sun20i_codec_pga_vol_scale); ++ ++static const struct snd_kcontrol_new sun20i_codec_mic3_volume = ++ SOC_DAPM_SINGLE_TLV("Capture Volume", ++ SUN20I_CODEC_ADC3, ++ SUN20I_CODEC_ADC3_ADC3_PGA_GAIN, ++ 0x1f, 0, sun20i_codec_pga_vol_scale); ++ ++static const struct snd_soc_dapm_widget sun20i_codec_widgets[] = { ++ /* Playback */ ++ SND_SOC_DAPM_OUTPUT("LINEOUTL"), ++ SND_SOC_DAPM_OUTPUT("LINEOUTR"), ++ ++ SND_SOC_DAPM_SWITCH("LINEOUTL Switch", ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_LINEOUTL_EN, 0, ++ &sun20i_codec_line_out_switch), ++ SND_SOC_DAPM_SWITCH("LINEOUTR Switch", ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_LINEOUTR_EN, 0, ++ &sun20i_codec_line_out_switch), ++ ++ SND_SOC_DAPM_OUTPUT("HPOUTL"), ++ SND_SOC_DAPM_OUTPUT("HPOUTR"), ++ ++ SND_SOC_DAPM_SWITCH("HPOUTL Switch", ++ SND_SOC_NOPM, 0, 0, &sun20i_codec_hp_switch), ++ SND_SOC_DAPM_SWITCH("HPOUTR Switch", ++ SND_SOC_NOPM, 0, 0, &sun20i_codec_hp_switch), ++ SND_SOC_DAPM_SUPPLY("Headphone Driver", ++ SUN20I_CODEC_HP2, ++ SUN20I_CODEC_HP2_HP_DRVEN, 0, NULL, 0), ++ ++ SND_SOC_DAPM_DAC("DACL", NULL, ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_DACL_EN, 0), ++ SND_SOC_DAPM_DAC("DACR", NULL, ++ SUN20I_CODEC_DAC, ++ SUN20I_CODEC_DAC_DACR_EN, 0), ++ SND_SOC_DAPM_SUPPLY("DAC", ++ SUN20I_CODEC_DAC_DPC, ++ SUN20I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), ++ ++ SND_SOC_DAPM_AIF_IN("DACL FIFO", "Playback", 0, ++ SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_IN("DACR FIFO", "Playback", 1, ++ SND_SOC_NOPM, 0, 0), ++ ++ /* Capture */ ++ SND_SOC_DAPM_AIF_OUT("ADC1 FIFO", "Capture", 0, ++ SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("ADC2 FIFO", "Capture", 1, ++ SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("ADC3 FIFO", "Capture", 2, ++ SND_SOC_NOPM, 0, 0), ++ ++ SND_SOC_DAPM_ADC("ADC1", NULL, ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC1_ADC1_EN, 0), ++ SND_SOC_DAPM_ADC("ADC2", NULL, ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC2_ADC2_EN, 0), ++ SND_SOC_DAPM_ADC("ADC3", NULL, ++ SUN20I_CODEC_ADC3, ++ SUN20I_CODEC_ADC3_ADC3_EN, 0), ++ SND_SOC_DAPM_SUPPLY("ADC", ++ SUN20I_CODEC_ADC_FIFOC, ++ SUN20I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), ++ ++ SND_SOC_DAPM_MIXER_NAMED_CTL("ADC1 Mixer", SND_SOC_NOPM, 0, 0, ++ sun20i_codec_adc12_mixer_controls, 3), ++ SND_SOC_DAPM_MIXER_NAMED_CTL("ADC2 Mixer", SND_SOC_NOPM, 0, 0, ++ sun20i_codec_adc12_mixer_controls + 1, 3), ++ SND_SOC_DAPM_MIXER_NAMED_CTL("ADC3 Mixer", SND_SOC_NOPM, 0, 0, ++ sun20i_codec_adc3_mixer_controls, ++ ARRAY_SIZE(sun20i_codec_adc3_mixer_controls)), ++ ++ SND_SOC_DAPM_PGA("Mic1", ++ SUN20I_CODEC_ADC1, ++ SUN20I_CODEC_ADC1_MICIN1_PGA_EN, 0, ++ &sun20i_codec_mic1_volume, 1), ++ SND_SOC_DAPM_PGA("Mic2", ++ SUN20I_CODEC_ADC2, ++ SUN20I_CODEC_ADC2_MICIN2_PGA_EN, 0, ++ &sun20i_codec_mic2_volume, 1), ++ SND_SOC_DAPM_PGA("Mic3", ++ SUN20I_CODEC_ADC3, ++ SUN20I_CODEC_ADC3_MICIN3_PGA_EN, 0, ++ &sun20i_codec_mic3_volume, 1), ++ ++ SND_SOC_DAPM_INPUT("MICIN1"), ++ SND_SOC_DAPM_INPUT("MICIN2"), ++ SND_SOC_DAPM_INPUT("MICIN3"), ++ ++ SND_SOC_DAPM_INPUT("FMINL"), ++ SND_SOC_DAPM_INPUT("FMINR"), ++ ++ SND_SOC_DAPM_INPUT("LINEINL"), ++ SND_SOC_DAPM_INPUT("LINEINR"), ++ ++ SND_SOC_DAPM_SUPPLY("HBIAS", ++ SUN20I_CODEC_MICBIAS, ++ SUN20I_CODEC_MICBIAS_HMICBIASEN, 0, NULL, 0), ++ SND_SOC_DAPM_SUPPLY("MBIAS", ++ SUN20I_CODEC_MICBIAS, ++ SUN20I_CODEC_MICBIAS_MMICBIASEN, 0, NULL, 0), ++ ++ SND_SOC_DAPM_REGULATOR_SUPPLY("avcc", 0, 0), ++ SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0), ++ SND_SOC_DAPM_REGULATOR_SUPPLY("vdd33", 0, 0), ++}; ++ ++static const struct snd_soc_dapm_route sun20i_codec_routes[] = { ++ /* Playback */ ++ { "LINEOUTL", NULL, "LINEOUTL Switch" }, ++ { "LINEOUTR", NULL, "LINEOUTR Switch" }, ++ ++ { "LINEOUTL Switch", "Line Out Playback Switch", "DACL" }, ++ { "LINEOUTR Switch", "Line Out Playback Switch", "DACR" }, ++ ++ { "HPOUTL", NULL, "HPOUTL Switch" }, ++ { "HPOUTR", NULL, "HPOUTR Switch" }, ++ ++ { "HPOUTL Switch", "Headphone Playback Switch", "DACL" }, ++ { "HPOUTR Switch", "Headphone Playback Switch", "DACR" }, ++ { "HPOUTL Switch", NULL, "Headphone Driver" }, ++ { "HPOUTR Switch", NULL, "Headphone Driver" }, ++ { "Headphone Driver", NULL, "hpvcc" }, ++ ++ { "DACL", NULL, "DACL FIFO" }, ++ { "DACR", NULL, "DACR FIFO" }, ++ { "DACL", NULL, "DAC" }, ++ { "DACR", NULL, "DAC" }, ++ { "DACL", NULL, "avcc" }, ++ { "DACR", NULL, "avcc" }, ++ ++ /* Capture */ ++ { "ADC1 FIFO", NULL, "ADC1" }, ++ { "ADC2 FIFO", NULL, "ADC2" }, ++ { "ADC3 FIFO", NULL, "ADC3" }, ++ ++ { "ADC1", NULL, "ADC1 Mixer" }, ++ { "ADC2", NULL, "ADC2 Mixer" }, ++ { "ADC3", NULL, "ADC3 Mixer" }, ++ { "ADC1", NULL, "ADC" }, ++ { "ADC2", NULL, "ADC" }, ++ { "ADC3", NULL, "ADC" }, ++ { "ADC1", NULL, "avcc" }, ++ { "ADC2", NULL, "avcc" }, ++ { "ADC3", NULL, "avcc" }, ++ ++ { "ADC1 Mixer", "Mic1 Capture Switch", "Mic1" }, ++ { "ADC2 Mixer", "Mic2 Capture Switch", "Mic2" }, ++ { "ADC3 Mixer", "Mic3 Capture Switch", "Mic3" }, ++ { "ADC1 Mixer", "FM Capture Switch", "FMINL" }, ++ { "ADC2 Mixer", "FM Capture Switch", "FMINR" }, ++ { "ADC1 Mixer", "Line In Capture Switch", "LINEINL" }, ++ { "ADC2 Mixer", "Line In Capture Switch", "LINEINR" }, ++ ++ { "Mic1", NULL, "MICIN1" }, ++ { "Mic2", NULL, "MICIN2" }, ++ { "Mic3", NULL, "MICIN3" }, ++ ++ { "HBIAS", NULL, "vdd33" }, ++ { "MBIAS", NULL, "vdd33" }, ++}; ++ ++static int sun20i_codec_component_probe(struct snd_soc_component *component) ++{ ++ struct sun20i_codec *codec = snd_soc_component_get_drvdata(component); ++ int ret; ++ ++ ret = reset_control_deassert(codec->reset); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(codec->bus_clk); ++ if (ret) ++ goto err_assert_reset; ++ ++ /* Enable digital volume control. */ ++ snd_soc_component_update_bits(component, SUN20I_CODEC_DAC_VOL_CTRL, ++ 0x1 << SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL, ++ 0x1 << SUN20I_CODEC_DAC_VOL_CTRL_DAC_VOL_SEL); ++ snd_soc_component_update_bits(component, SUN20I_CODEC_ADC_DIG_CTRL, ++ 0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN, ++ 0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN); ++ ++ return 0; ++ ++err_assert_reset: ++ reset_control_assert(codec->reset); ++ ++ return ret; ++} ++ ++static void sun20i_codec_component_remove(struct snd_soc_component *component) ++{ ++ struct sun20i_codec *codec = snd_soc_component_get_drvdata(component); ++ ++ clk_disable_unprepare(codec->bus_clk); ++ reset_control_assert(codec->reset); ++} ++ ++static const struct snd_soc_component_driver sun20i_codec_component = { ++ .controls = sun20i_codec_controls, ++ .num_controls = ARRAY_SIZE(sun20i_codec_controls), ++ .dapm_widgets = sun20i_codec_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(sun20i_codec_widgets), ++ .dapm_routes = sun20i_codec_routes, ++ .num_dapm_routes = ARRAY_SIZE(sun20i_codec_routes), ++ .probe = sun20i_codec_component_probe, ++ .remove = sun20i_codec_component_remove, ++}; ++ ++static int sun20i_codec_init_card(struct device *dev, ++ struct sun20i_codec *codec) ++{ ++ struct snd_soc_dai_link *dai_link = &codec->dai_link; ++ struct snd_soc_card *card = &codec->card; ++ int ret; ++ ++ codec->dlcs[0].of_node = dev->of_node; ++ codec->dlcs[0].dai_name = DRIVER_NAME; ++ codec->dlcs[1].name = "snd-soc-dummy"; ++ codec->dlcs[1].dai_name = "snd-soc-dummy-dai"; ++ codec->dlcs[2].of_node = dev->of_node; ++ ++ dai_link->name = DRIVER_NAME; ++ dai_link->stream_name = DRIVER_NAME; ++ dai_link->cpus = &codec->dlcs[0]; ++ dai_link->num_cpus = 1; ++ dai_link->codecs = &codec->dlcs[1]; ++ dai_link->num_codecs = 1; ++ dai_link->platforms = &codec->dlcs[2]; ++ dai_link->num_platforms = 1; ++ ++ card->name = DRIVER_NAME; ++ card->dev = dev; ++ card->owner = THIS_MODULE; ++ card->dai_link = dai_link; ++ card->num_links = 1; ++ card->fully_routed = true; ++ ++ ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); ++ if (ret) ++ return ret; ++ ++ ret = snd_soc_of_parse_pin_switches(card, "pin-switches"); ++ if (ret) ++ return ret; ++ ++ ret = snd_soc_of_parse_audio_routing(card, "routing"); ++ if (ret) ++ return ret; ++ ++ ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets"); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct regmap_config sun20i_codec_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = SUN20I_CODEC_ADC_CUR, ++}; ++ ++static int sun20i_codec_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct sun20i_codec *codec; ++ struct regmap *regmap; ++ struct resource *res; ++ void __iomem *base; ++ int ret; ++ ++ codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL); ++ if (!codec) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, codec); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(base)) ++ return dev_err_probe(dev, PTR_ERR(base), ++ "Failed to map registers\n"); ++ ++ regmap = devm_regmap_init_mmio(dev, base, ++ &sun20i_codec_regmap_config); ++ if (IS_ERR(regmap)) ++ return dev_err_probe(dev, PTR_ERR(regmap), ++ "Failed to create regmap\n"); ++ ++ codec->bus_clk = devm_clk_get(dev, "bus"); ++ if (IS_ERR(codec->bus_clk)) ++ return dev_err_probe(dev, PTR_ERR(codec->bus_clk), ++ "Failed to get bus clock\n"); ++ ++ codec->adc_clk = devm_clk_get(dev, "adc"); ++ if (IS_ERR(codec->adc_clk)) ++ return dev_err_probe(dev, PTR_ERR(codec->adc_clk), ++ "Failed to get ADC clock\n"); ++ ++ codec->dac_clk = devm_clk_get(dev, "dac"); ++ if (IS_ERR(codec->dac_clk)) ++ return dev_err_probe(dev, PTR_ERR(codec->dac_clk), ++ "Failed to get DAC clock\n"); ++ ++ codec->reset = devm_reset_control_get_exclusive(dev, NULL); ++ if (IS_ERR(codec->reset)) ++ return dev_err_probe(dev, PTR_ERR(codec->reset), ++ "Failed to get reset\n"); ++ ++ ret = devm_snd_soc_register_component(dev, &sun20i_codec_component, ++ &sun20i_codec_dai, 1); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to register component\n"); ++ ++ codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = ++ res->start + SUN20I_CODEC_DAC_TXDATA; ++ codec->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 8; ++ codec->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = ++ res->start + SUN20I_CODEC_ADC_RXDATA; ++ codec->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 8; ++ ++ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to register PCM\n"); ++ ++ ret = sun20i_codec_init_card(dev, codec); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to initialize card\n"); ++ ++ ret = devm_snd_soc_register_card(dev, &codec->card); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to register card\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id sun20i_codec_of_match[] = { ++ { .compatible = "allwinner,sun20i-d1-codec" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, sun20i_codec_of_match); ++ ++static struct platform_driver sun20i_codec_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = sun20i_codec_of_match, ++ }, ++ .probe = sun20i_codec_probe, ++}; ++module_platform_driver(sun20i_codec_driver); ++ ++MODULE_DESCRIPTION("Allwinner D1 (sun20i) codec driver"); ++MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:sun20i-codec"); diff --git a/target/linux/d1/patches-6.1/0082-ASoC-sun20i-codec-What-is-this-ramp-thing.patch b/target/linux/d1/patches-6.1/0082-ASoC-sun20i-codec-What-is-this-ramp-thing.patch new file mode 100644 index 0000000000..d837c6afdc --- /dev/null +++ b/target/linux/d1/patches-6.1/0082-ASoC-sun20i-codec-What-is-this-ramp-thing.patch @@ -0,0 +1,23 @@ +From 87a77f803f5038e3fc64f45d5142ea402512029a Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 23 Jun 2021 21:18:47 -0500 +Subject: [PATCH 082/117] ASoC: sun20i-codec: What is this ramp thing? + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + sound/soc/sunxi/sun20i-codec.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/soc/sunxi/sun20i-codec.c ++++ b/sound/soc/sunxi/sun20i-codec.c +@@ -709,6 +709,10 @@ static int sun20i_codec_component_probe( + 0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN, + 0x3 << SUN20I_CODEC_ADC_DIG_CTRL_ADC_VOL_EN); + ++ /* Maaagic... */ ++ snd_soc_component_update_bits(component, SUN20I_CODEC_RAMP, ++ BIT(1) | BIT(0), BIT(0)); ++ + return 0; + + err_assert_reset: diff --git a/target/linux/d1/patches-6.1/0083-riscv-dts-allwinner-d1-Add-sound-cards-to-boards.patch b/target/linux/d1/patches-6.1/0083-riscv-dts-allwinner-d1-Add-sound-cards-to-boards.patch new file mode 100644 index 0000000000..b0f93c3a48 --- /dev/null +++ b/target/linux/d1/patches-6.1/0083-riscv-dts-allwinner-d1-Add-sound-cards-to-boards.patch @@ -0,0 +1,132 @@ +From 54b1030c72d74ba6390d62086cbfc6a511f58aa7 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 00:39:42 -0500 +Subject: [PATCH 083/117] riscv: dts: allwinner: d1: Add sound cards to boards + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../sun20i-d1-common-regulators.dtsi | 5 +++++ + .../sun20i-d1-lichee-rv-86-panel.dtsi | 21 +++++++++++++++++++ + .../allwinner/sun20i-d1-lichee-rv-dock.dts | 12 +++++++++++ + .../boot/dts/allwinner/sun20i-d1-nezha.dts | 12 +++++++++++ + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 13 +++++++++++- + 5 files changed, 62 insertions(+), 1 deletion(-) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-common-regulators.dtsi +@@ -18,6 +18,11 @@ + }; + }; + ++&codec { ++ avcc-supply = <®_aldo>; ++ hpvcc-supply = <®_hpldo>; ++}; ++ + &lradc { + vref-supply = <®_aldo>; + }; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel.dtsi +@@ -9,6 +9,12 @@ + ethernet1 = &xr829; + }; + ++ audio_amplifier: audio-amplifier { ++ compatible = "simple-audio-amplifier"; ++ enable-gpios = <&pio 1 10 GPIO_ACTIVE_HIGH>; /* PB10 */ ++ sound-name-prefix = "Amplifier"; ++ }; ++ + dmic_codec: dmic-codec { + compatible = "dmic-codec"; + num-channels = <2>; +@@ -51,6 +57,21 @@ + }; + }; + ++&codec { ++ aux-devs = <&audio_amplifier>; ++ routing = "Internal Speaker", "Amplifier OUTL", ++ "Internal Speaker", "Amplifier OUTR", ++ "Amplifier INL", "HPOUTL", ++ "Amplifier INR", "HPOUTR", ++ "LINEINL", "HPOUTL", ++ "LINEINR", "HPOUTR", ++ "MICIN3", "Internal Microphone", ++ "Internal Microphone", "HBIAS"; ++ widgets = "Microphone", "Internal Microphone", ++ "Speaker", "Internal Speaker"; ++ status = "okay"; ++}; ++ + &dmic { + pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>; + pinctrl-names = "default"; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-dock.dts +@@ -48,6 +48,18 @@ + }; + }; + ++&codec { ++ routing = "Internal Speaker", "HPOUTL", ++ "Internal Speaker", "HPOUTR", ++ "LINEINL", "HPOUTL", ++ "LINEINR", "HPOUTR", ++ "MICIN3", "Internal Microphone", ++ "Internal Microphone", "HBIAS"; ++ widgets = "Microphone", "Internal Microphone", ++ "Speaker", "Internal Speaker"; ++ status = "okay"; ++}; ++ + &dmic { + pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>; + pinctrl-names = "default"; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts +@@ -51,6 +51,18 @@ + }; + }; + ++&codec { ++ routing = "Headphone Jack", "HPOUTL", ++ "Headphone Jack", "HPOUTR", ++ "LINEINL", "HPOUTL", ++ "LINEINR", "HPOUTR", ++ "MICIN3", "Headset Microphone", ++ "Headset Microphone", "HBIAS"; ++ widgets = "Microphone", "Headset Microphone", ++ "Headphone", "Headphone Jack"; ++ status = "okay"; ++}; ++ + &cpu0 { + cpu-supply = <®_vdd_cpu>; + }; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -312,10 +312,21 @@ + }; + + codec: audio-codec@2030000 { +- compatible = "simple-mfd", "syscon"; ++ compatible = "allwinner,sun20i-d1-codec", "simple-mfd", "syscon"; + reg = <0x2030000 0x1000>; ++ interrupts = <41 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_AUDIO>, ++ <&ccu CLK_AUDIO_ADC>, ++ <&ccu CLK_AUDIO_DAC>, ++ <&osc24M>, ++ <&rtc CLK_OSC32K>; ++ clock-names = "bus", "adc", "dac", "hosc", "losc"; ++ resets = <&ccu RST_BUS_AUDIO>; ++ dmas = <&dma 7>, <&dma 7>; ++ dma-names = "rx", "tx"; + #address-cells = <1>; + #size-cells = <1>; ++ #sound-dai-cells = <0>; + + regulators@2030348 { + compatible = "allwinner,sun20i-d1-analog-ldos"; diff --git a/target/linux/d1/patches-6.1/0084-drm-sun4i-dsi-Allow-panel-attach-before-card-registr.patch b/target/linux/d1/patches-6.1/0084-drm-sun4i-dsi-Allow-panel-attach-before-card-registr.patch new file mode 100644 index 0000000000..e74ea35e5a --- /dev/null +++ b/target/linux/d1/patches-6.1/0084-drm-sun4i-dsi-Allow-panel-attach-before-card-registr.patch @@ -0,0 +1,39 @@ +From bae2790f627eb30ec3845167341b108e13328f6f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:46:43 -0500 +Subject: [PATCH 084/117] drm/sun4i: dsi: Allow panel attach before card + registration + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c ++++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +@@ -967,13 +967,12 @@ static int sun6i_dsi_attach(struct mipi_ + + if (IS_ERR(panel)) + return PTR_ERR(panel); +- if (!dsi->drm || !dsi->drm->registered) +- return -EPROBE_DEFER; + + dsi->panel = panel; + dsi->device = device; + +- drm_kms_helper_hotplug_event(dsi->drm); ++ if (dsi->drm && dsi->drm->registered) ++ drm_kms_helper_hotplug_event(dsi->drm); + + dev_info(host->dev, "Attached device %s\n", device->name); + +@@ -988,7 +987,8 @@ static int sun6i_dsi_detach(struct mipi_ + dsi->panel = NULL; + dsi->device = NULL; + +- drm_kms_helper_hotplug_event(dsi->drm); ++ if (dsi->drm && dsi->drm->registered) ++ drm_kms_helper_hotplug_event(dsi->drm); + + return 0; + } diff --git a/target/linux/d1/patches-6.1/0085-drm-sun4i-mixer-Remove-unused-CMA-headers.patch b/target/linux/d1/patches-6.1/0085-drm-sun4i-mixer-Remove-unused-CMA-headers.patch new file mode 100644 index 0000000000..ae47bbed26 --- /dev/null +++ b/target/linux/d1/patches-6.1/0085-drm-sun4i-mixer-Remove-unused-CMA-headers.patch @@ -0,0 +1,21 @@ +From 5755bea969adcb00b102271b0cbaa3002acd7a35 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 27 Apr 2022 18:50:01 -0500 +Subject: [PATCH 085/117] drm/sun4i: mixer: Remove unused CMA headers + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun8i_mixer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c ++++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c +@@ -17,7 +17,7 @@ + #include <drm/drm_atomic_helper.h> + #include <drm/drm_crtc.h> + #include <drm/drm_framebuffer.h> +-#include <drm/drm_gem_dma_helper.h> ++#include <drm/drm_print.h> + #include <drm/drm_probe_helper.h> + + #include "sun4i_drv.h" diff --git a/target/linux/d1/patches-6.1/0086-drm-sun4i-decouple-TCON_DCLK_DIV-value-from-pll_mipi.patch b/target/linux/d1/patches-6.1/0086-drm-sun4i-decouple-TCON_DCLK_DIV-value-from-pll_mipi.patch new file mode 100644 index 0000000000..8a6015bc56 --- /dev/null +++ b/target/linux/d1/patches-6.1/0086-drm-sun4i-decouple-TCON_DCLK_DIV-value-from-pll_mipi.patch @@ -0,0 +1,110 @@ +From 9a7acb8f03346705d7420a490d95b32309d90e22 Mon Sep 17 00:00:00 2001 +From: Roman Beranek <roman.beranek@prusa3d.com> +Date: Wed, 25 Nov 2020 13:07:35 +0100 +Subject: [PATCH 086/117] drm/sun4i: decouple TCON_DCLK_DIV value from + pll_mipi/dotclock ratio + +Observations showed that an actual refresh rate differs from the intended. +Specifically, in case of 4-lane panels it was reduced by 1/3, and in case of +2-lane panels by 2/3. + +BSP code apparently distinguishes between a `dsi_div` and a 'tcon inner div'. +While this 'inner' divider is under DSI always 4, the `dsi_div` is defined +as a number of bits per pixel over a number of DSI lanes. This value is then +involved in setting the rate of PLL_MIPI. + +I couldn't really figure out how to fit this into the dotclock driver, +so I opted for this hack where the requested rate is adjusted in such a way +that the sun4i_dotclock driver can remain untouched. + +Signed-off-by: Roman Beranek <roman.beranek@prusa3d.com> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun4i_tcon.c | 44 +++++++++++++++++------------- + 1 file changed, 25 insertions(+), 19 deletions(-) + +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c +@@ -291,18 +291,6 @@ static int sun4i_tcon_get_clk_delay(cons + return delay; + } + +-static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon, +- const struct drm_display_mode *mode) +-{ +- /* Configure the dot clock */ +- clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); +- +- /* Set the resolution */ +- regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, +- SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | +- SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); +-} +- + static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon, + const struct drm_connector *connector) + { +@@ -365,12 +353,18 @@ static void sun4i_tcon0_mode_set_cpu(str + u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format); + u8 lanes = device->lanes; + u32 block_space, start_delay; +- u32 tcon_div; + + tcon->dclk_min_div = SUN6I_DSI_TCON_DIV; + tcon->dclk_max_div = SUN6I_DSI_TCON_DIV; + +- sun4i_tcon0_mode_set_common(tcon, mode); ++ /* Configure the dot clock */ ++ clk_set_rate(tcon->dclk, mode->crtc_clock * 1000 ++ * bpp / (lanes * SUN6I_DSI_TCON_DIV)); ++ ++ /* Set the resolution */ ++ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, ++ SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | ++ SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); + + /* Set dithering if needed */ + sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder)); +@@ -394,9 +388,7 @@ static void sun4i_tcon0_mode_set_cpu(str + * The datasheet says that this should be set higher than 20 * + * pixel cycle, but it's not clear what a pixel cycle is. + */ +- regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div); +- tcon_div &= GENMASK(6, 0); +- block_space = mode->htotal * bpp / (tcon_div * lanes); ++ block_space = mode->htotal * bpp / (SUN6I_DSI_TCON_DIV * lanes); + block_space -= mode->hdisplay + 40; + + regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG, +@@ -438,7 +430,14 @@ static void sun4i_tcon0_mode_set_lvds(st + + tcon->dclk_min_div = 7; + tcon->dclk_max_div = 7; +- sun4i_tcon0_mode_set_common(tcon, mode); ++ ++ /* Configure the dot clock */ ++ clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); ++ ++ /* Set the resolution */ ++ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, ++ SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | ++ SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); + + /* Set dithering if needed */ + sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder)); +@@ -515,7 +514,14 @@ static void sun4i_tcon0_mode_set_rgb(str + + tcon->dclk_min_div = tcon->quirks->dclk_min_div; + tcon->dclk_max_div = 127; +- sun4i_tcon0_mode_set_common(tcon, mode); ++ ++ /* Configure the dot clock */ ++ clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); ++ ++ /* Set the resolution */ ++ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, ++ SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | ++ SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); + + /* Set dithering if needed */ + sun4i_tcon0_mode_set_dithering(tcon, connector); diff --git a/target/linux/d1/patches-6.1/0087-drm-sun4i-tcon-Always-protect-the-LCD-dotclock-rate.patch b/target/linux/d1/patches-6.1/0087-drm-sun4i-tcon-Always-protect-the-LCD-dotclock-rate.patch new file mode 100644 index 0000000000..7e404eecd1 --- /dev/null +++ b/target/linux/d1/patches-6.1/0087-drm-sun4i-tcon-Always-protect-the-LCD-dotclock-rate.patch @@ -0,0 +1,57 @@ +From 9ea0c216d4f85a8ea888a38853e9573bbd9e995a Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 21:09:39 -0500 +Subject: [PATCH 087/117] drm/sun4i: tcon: Always protect the LCD dotclock rate + +This handles the case where multiple CRTCs get their .mode_set function +called during the same atomic commit, before rate protection is applied +by enabling the CRTC. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun4i_dotclock.c | 4 ++++ + drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++-- + 2 files changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c ++++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c +@@ -6,6 +6,7 @@ + * Maxime Ripard <maxime.ripard@free-electrons.com> + */ + ++#include <linux/clk.h> + #include <linux/clk-provider.h> + #include <linux/regmap.h> + +@@ -194,12 +195,15 @@ int sun4i_dclk_create(struct device *dev + if (IS_ERR(tcon->dclk)) + return PTR_ERR(tcon->dclk); + ++ clk_rate_exclusive_get(tcon->dclk); ++ + return 0; + } + EXPORT_SYMBOL(sun4i_dclk_create); + + int sun4i_dclk_free(struct sun4i_tcon *tcon) + { ++ clk_rate_exclusive_put(tcon->dclk); + clk_unregister(tcon->dclk); + return 0; + } +--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c ++++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c +@@ -108,9 +108,11 @@ static void sun4i_tcon_channel_set_statu + + if (enabled) { + clk_prepare_enable(clk); +- clk_rate_exclusive_get(clk); ++ if (clk != tcon->dclk) ++ clk_rate_exclusive_get(clk); + } else { +- clk_rate_exclusive_put(clk); ++ if (clk != tcon->dclk) ++ clk_rate_exclusive_put(clk); + clk_disable_unprepare(clk); + } + } diff --git a/target/linux/d1/patches-6.1/0088-drm-sun4i-tcon_top-Register-reset-clock-gates-in-pro.patch b/target/linux/d1/patches-6.1/0088-drm-sun4i-tcon_top-Register-reset-clock-gates-in-pro.patch new file mode 100644 index 0000000000..fae19b8087 --- /dev/null +++ b/target/linux/d1/patches-6.1/0088-drm-sun4i-tcon_top-Register-reset-clock-gates-in-pro.patch @@ -0,0 +1,113 @@ +From f792492db1f42c43eb4b8bb72ce573418afc933d Mon Sep 17 00:00:00 2001 +From: Jagan Teki <jagan@amarulasolutions.com> +Date: Tue, 31 Dec 2019 18:35:24 +0530 +Subject: [PATCH 088/117] drm/sun4i: tcon_top: Register reset, clock gates in + probe + +TCON TOP is processing clock gates and reset control for +TV0, TV1 and DSI channels during bind and release the same +during unbind component ops. + +The usual DSI initialization would setup all controller +clocks along with DPHY clocking during probe. + +Since the actual clock gates (along with DSI clock gate) +are initialized during ton top bind, the DPHY is failed to +get the DSI clock during that time. + +To solve, this circular dependency move the reset control, +clock gate registration from bind to probe and release the +same from unbind to remove. + +This eventually give a chance DPHY to initialize the DSI +clock gate. + +Signed-off-by: Jagan Teki <jagan@amarulasolutions.com> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 42 ++++++++++++++------------ + 1 file changed, 22 insertions(+), 20 deletions(-) + +--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c ++++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +@@ -124,14 +124,29 @@ static struct clk_hw *sun8i_tcon_top_reg + static int sun8i_tcon_top_bind(struct device *dev, struct device *master, + void *data) + { +- struct platform_device *pdev = to_platform_device(dev); ++ return 0; ++} ++ ++static void sun8i_tcon_top_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++} ++ ++static const struct component_ops sun8i_tcon_top_ops = { ++ .bind = sun8i_tcon_top_bind, ++ .unbind = sun8i_tcon_top_unbind, ++}; ++ ++static int sun8i_tcon_top_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; + struct clk_hw_onecell_data *clk_data; + struct sun8i_tcon_top *tcon_top; + const struct sun8i_tcon_top_quirks *quirks; + void __iomem *regs; + int ret, i; + +- quirks = of_device_get_match_data(&pdev->dev); ++ quirks = of_device_get_match_data(dev); + + tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL); + if (!tcon_top) +@@ -222,7 +237,7 @@ static int sun8i_tcon_top_bind(struct de + + dev_set_drvdata(dev, tcon_top); + +- return 0; ++ return component_add(dev, &sun8i_tcon_top_ops); + + err_unregister_gates: + for (i = 0; i < CLK_NUM; i++) +@@ -235,13 +250,15 @@ err_assert_reset: + return ret; + } + +-static void sun8i_tcon_top_unbind(struct device *dev, struct device *master, +- void *data) ++static int sun8i_tcon_top_remove(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev); + struct clk_hw_onecell_data *clk_data = tcon_top->clk_data; + int i; + ++ component_del(dev, &sun8i_tcon_top_ops); ++ + of_clk_del_provider(dev->of_node); + for (i = 0; i < CLK_NUM; i++) + if (clk_data->hws[i]) +@@ -249,21 +266,6 @@ static void sun8i_tcon_top_unbind(struct + + clk_disable_unprepare(tcon_top->bus); + reset_control_assert(tcon_top->rst); +-} +- +-static const struct component_ops sun8i_tcon_top_ops = { +- .bind = sun8i_tcon_top_bind, +- .unbind = sun8i_tcon_top_unbind, +-}; +- +-static int sun8i_tcon_top_probe(struct platform_device *pdev) +-{ +- return component_add(&pdev->dev, &sun8i_tcon_top_ops); +-} +- +-static int sun8i_tcon_top_remove(struct platform_device *pdev) +-{ +- component_del(&pdev->dev, &sun8i_tcon_top_ops); + + return 0; + } diff --git a/target/linux/d1/patches-6.1/0089-riscv-dts-allwinner-lichee-rv-86-panel-480p-Add-pane.patch b/target/linux/d1/patches-6.1/0089-riscv-dts-allwinner-lichee-rv-86-panel-480p-Add-pane.patch new file mode 100644 index 0000000000..ce7510d156 --- /dev/null +++ b/target/linux/d1/patches-6.1/0089-riscv-dts-allwinner-lichee-rv-86-panel-480p-Add-pane.patch @@ -0,0 +1,75 @@ +From 03dbb926f6d65f75af902e421c44aeaaf84be66a Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:46:28 -0500 +Subject: [PATCH 089/117] riscv: dts: allwinner: lichee-rv-86-panel-480p: Add + panel + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../sun20i-d1-lichee-rv-86-panel-480p.dts | 51 +++++++++++++++++++ + 1 file changed, 51 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-480p.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-lichee-rv-86-panel-480p.dts +@@ -7,6 +7,40 @@ + model = "Sipeed Lichee RV 86 Panel (480p)"; + compatible = "sipeed,lichee-rv-86-panel-480p", "sipeed,lichee-rv", + "allwinner,sun20i-d1"; ++ ++ backlight: backlight { ++ compatible = "pwm-backlight"; ++ power-supply = <®_vcc>; ++ pwms = <&pwm 7 50000 0>; ++ }; ++ ++ spi { ++ compatible = "spi-gpio"; ++ cs-gpios = <&pio 4 14 GPIO_ACTIVE_LOW>; /* PE14 */ ++ mosi-gpios = <&pio 4 12 GPIO_ACTIVE_HIGH>; /* PE12 */ ++ sck-gpios = <&pio 4 15 GPIO_ACTIVE_HIGH>; /* PE15 */ ++ num-chipselects = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ panel@0 { ++ compatible = "sitronix,st7701s"; ++ reg = <0>; ++ backlight = <&backlight>; ++ reset-gpios = <&pio 6 13 GPIO_ACTIVE_LOW>; /* PG13 */ ++ spi-3wire; ++ ++ port { ++ panel_in_tcon_lcd0: endpoint { ++ remote-endpoint = <&tcon_lcd0_out_panel>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&de { ++ status = "okay"; + }; + + &i2c2 { +@@ -27,3 +61,20 @@ + wakeup-source; + }; + }; ++ ++&pwm { ++ pinctrl-0 = <&pwm7_pd22_pin>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&tcon_lcd0 { ++ pinctrl-0 = <&lcd_rgb666_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&tcon_lcd0_out { ++ tcon_lcd0_out_panel: endpoint { ++ remote-endpoint = <&panel_in_tcon_lcd0>; ++ }; ++}; diff --git a/target/linux/d1/patches-6.1/0090-riscv-dts-allwinner-d1-Add-DSI-pipeline.patch b/target/linux/d1/patches-6.1/0090-riscv-dts-allwinner-d1-Add-DSI-pipeline.patch new file mode 100644 index 0000000000..e6e992b9e6 --- /dev/null +++ b/target/linux/d1/patches-6.1/0090-riscv-dts-allwinner-d1-Add-DSI-pipeline.patch @@ -0,0 +1,82 @@ +From 4c72279c90469971ca5ec627a76e50bf51bf076f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:59:29 -0500 +Subject: [PATCH 090/117] riscv: dts: allwinner: d1: Add DSI pipeline + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 49 ++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -124,6 +124,14 @@ + #interrupt-cells = <3>; + + /omit-if-no-ref/ ++ dsi_4lane_pins: dsi-4lane-pins { ++ pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5", ++ "PD6", "PD7", "PD8", "PD9"; ++ drive-strength = <30>; ++ function = "dsi"; ++ }; ++ ++ /omit-if-no-ref/ + i2c0_pb10_pins: i2c0-pb10-pins { + pins = "PB10", "PB11"; + function = "i2c0"; +@@ -903,6 +911,40 @@ + }; + }; + ++ dsi: dsi@5450000 { ++ compatible = "allwinner,sun20i-d1-mipi-dsi", ++ "allwinner,sun50i-a100-mipi-dsi"; ++ reg = <0x5450000 0x1000>; ++ interrupts = <108 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_MIPI_DSI>, ++ <&tcon_top CLK_TCON_TOP_DSI>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_MIPI_DSI>; ++ phys = <&dphy>; ++ phy-names = "dphy"; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port { ++ dsi_in_tcon_lcd0: endpoint { ++ remote-endpoint = <&tcon_lcd0_out_dsi>; ++ }; ++ }; ++ }; ++ ++ dphy: phy@5451000 { ++ compatible = "allwinner,sun20i-d1-mipi-dphy", ++ "allwinner,sun50i-a100-mipi-dphy"; ++ reg = <0x5451000 0x1000>; ++ interrupts = <108 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_MIPI_DSI>, ++ <&ccu CLK_MIPI_DSI>; ++ clock-names = "bus", "mod"; ++ resets = <&ccu RST_BUS_MIPI_DSI>; ++ #phy-cells = <0>; ++ }; ++ + tcon_top: tcon-top@5460000 { + compatible = "allwinner,sun20i-d1-tcon-top"; + reg = <0x5460000 0x1000>; +@@ -1022,6 +1064,13 @@ + + tcon_lcd0_out: port@1 { + reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tcon_lcd0_out_dsi: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&dsi_in_tcon_lcd0>; ++ }; + }; + }; + }; diff --git a/target/linux/d1/patches-6.1/0091-riscv-dts-allwinner-devterm-Add-DSI-panel-and-backli.patch b/target/linux/d1/patches-6.1/0091-riscv-dts-allwinner-devterm-Add-DSI-panel-and-backli.patch new file mode 100644 index 0000000000..60855f0f1c --- /dev/null +++ b/target/linux/d1/patches-6.1/0091-riscv-dts-allwinner-devterm-Add-DSI-panel-and-backli.patch @@ -0,0 +1,62 @@ +From 7ac17ab7ea644ec27935865d6d0208ecc7fd4ed9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 11 Aug 2022 22:29:03 -0500 +Subject: [PATCH 091/117] riscv: dts: allwinner: devterm: Add DSI panel and + backlight + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../allwinner/sun20i-d1-clockworkpi-v3.14.dts | 8 +++++++- + .../dts/allwinner/sun20i-d1-devterm-v3.14.dts | 20 +++++++++++++++++++ + 2 files changed, 27 insertions(+), 1 deletion(-) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-clockworkpi-v3.14.dts +@@ -48,6 +48,12 @@ + }; + }; + ++ backlight: backlight { ++ compatible = "pwm-backlight"; ++ power-supply = <®_vcc>; ++ pwms = <&pwm 4 50000 0>; /* PD20/GPIO9 */ ++ }; ++ + reg_vdd_cpu: vdd-cpu { + compatible = "pwm-regulator"; + pwms = <&pwm 0 50000 0>; +@@ -252,7 +258,7 @@ + }; + + &pwm { +- pinctrl-0 = <&pwm0_pd16_pin>; ++ pinctrl-0 = <&pwm0_pd16_pin>, <&pwm4_pd20_pin>; + pinctrl-names = "default"; + status = "okay"; + }; +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1-devterm-v3.14.dts ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1-devterm-v3.14.dts +@@ -35,3 +35,23 @@ + }; + }; + }; ++ ++&de { ++ status = "okay"; ++}; ++ ++&dsi { ++ pinctrl-0 = <&dsi_4lane_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ panel@0 { ++ compatible = "clockwork,cwd686"; ++ reg = <0>; ++ backlight = <&backlight>; ++ reset-gpios = <&pio 3 19 GPIO_ACTIVE_LOW>; /* PD19/GPIO8 */ ++ rotation = <90>; ++ iovcc-supply = <®_dcdc3>; ++ vci-supply = <®_aldo2>; ++ }; ++}; diff --git a/target/linux/d1/patches-6.1/0092-dt-bindings-display-sun4i-tcon-Add-external-LVDS-PHY.patch b/target/linux/d1/patches-6.1/0092-dt-bindings-display-sun4i-tcon-Add-external-LVDS-PHY.patch new file mode 100644 index 0000000000..a8c6b685cd --- /dev/null +++ b/target/linux/d1/patches-6.1/0092-dt-bindings-display-sun4i-tcon-Add-external-LVDS-PHY.patch @@ -0,0 +1,29 @@ +From 822fdc3556b688103cdaf7b4b34e98fbe1676425 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:58:02 -0500 +Subject: [PATCH 092/117] dt-bindings: display: sun4i-tcon: Add external LVDS + PHY + +A100 and D1 use the same "combo" PHY for LVDS0 and DSI. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/display/allwinner,sun4i-a10-tcon.yaml | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tcon.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tcon.yaml +@@ -80,6 +80,13 @@ properties: + dmas: + maxItems: 1 + ++ phys: ++ maxItems: 1 ++ ++ phy-names: ++ items: ++ - const: "lvds0" ++ + resets: + anyOf: + - items: diff --git a/target/linux/d1/patches-6.1/0093-riscv-dts-allwinner-d1-Add-LVDS0-PHY.patch b/target/linux/d1/patches-6.1/0093-riscv-dts-allwinner-d1-Add-LVDS0-PHY.patch new file mode 100644 index 0000000000..f80b125c67 --- /dev/null +++ b/target/linux/d1/patches-6.1/0093-riscv-dts-allwinner-d1-Add-LVDS0-PHY.patch @@ -0,0 +1,21 @@ +From 7d95f6b52ea5f01c9e2414d4984e5a274328c021 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:58:57 -0500 +Subject: [PATCH 093/117] riscv: dts: allwinner: d1: Add LVDS0 PHY + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -1040,6 +1040,8 @@ + resets = <&ccu RST_BUS_TCON_LCD0>, + <&ccu RST_BUS_LVDS0>; + reset-names = "lcd", "lvds"; ++ phys = <&dphy>; ++ phy-names = "lvds0"; + #clock-cells = <0>; + + ports { diff --git a/target/linux/d1/patches-6.1/0094-dt-bindings-display-sun6i-dsi-Fix-clock-conditional.patch b/target/linux/d1/patches-6.1/0094-dt-bindings-display-sun6i-dsi-Fix-clock-conditional.patch new file mode 100644 index 0000000000..6006310298 --- /dev/null +++ b/target/linux/d1/patches-6.1/0094-dt-bindings-display-sun6i-dsi-Fix-clock-conditional.patch @@ -0,0 +1,38 @@ +From d0f7ed9dc803e09fb6c1e895efbd1182c9212483 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:49:30 -0500 +Subject: [PATCH 094/117] dt-bindings: display: sun6i-dsi: Fix clock + conditional + +The A64 case should have limited maxItems, instead of duplicating the +minItems value from the main binding. While here, simplify the binding +by making this an "else" case of the two-clock conditional block. + +Fixes: fe5040f2843a ("dt-bindings: sun6i-dsi: Document A64 MIPI-DSI controller") +Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +--- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +@@ -78,16 +78,10 @@ allOf: + required: + - clock-names + +- - if: +- properties: +- compatible: +- contains: +- const: allwinner,sun50i-a64-mipi-dsi +- +- then: ++ else: + properties: + clocks: +- minItems: 1 ++ maxItems: 1 + + unevaluatedProperties: false + diff --git a/target/linux/d1/patches-6.1/0095-dt-bindings-display-sun6i-dsi-Add-the-A100-variant.patch b/target/linux/d1/patches-6.1/0095-dt-bindings-display-sun6i-dsi-Add-the-A100-variant.patch new file mode 100644 index 0000000000..325c2528a5 --- /dev/null +++ b/target/linux/d1/patches-6.1/0095-dt-bindings-display-sun6i-dsi-Add-the-A100-variant.patch @@ -0,0 +1,85 @@ +From 30abd0e5f27bc57fba7084ba51aca671316b6d24 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 10:50:21 -0500 +Subject: [PATCH 095/117] dt-bindings: display: sun6i-dsi: Add the A100 variant + +The "40nm" MIPI DSI controller found in the A100 and D1 SoCs has the +same register layout as previous SoC integrations. However, its module +clock now comes from the TCON, which means it no longer runs at a fixed +rate, so this needs to be distinguished in the driver. + +The controller also now uses pins on Port D instead of dedicated pins, +so it drops the separate power domain. + +Commit-notes: +Removal of the vcc-dsi-supply is maybe a bit questionable. Since there +is no "VCC-DSI" pin anymore, it's not obvious which pin actually does +power the DSI controller/PHY. Possibly power comes from VCC-PD or VCC-IO +or VCC-LVDS. So far, all boards have all of these as always-on supplies, +so it is hard to test. +END + +Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../display/allwinner,sun6i-a31-mipi-dsi.yaml | 28 +++++++++++++++---- + 1 file changed, 23 insertions(+), 5 deletions(-) + +--- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml ++++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +@@ -12,9 +12,14 @@ maintainers: + + properties: + compatible: +- enum: +- - allwinner,sun6i-a31-mipi-dsi +- - allwinner,sun50i-a64-mipi-dsi ++ oneOf: ++ - enum: ++ - allwinner,sun6i-a31-mipi-dsi ++ - allwinner,sun50i-a64-mipi-dsi ++ - allwinner,sun50i-a100-mipi-dsi ++ - items: ++ - const: allwinner,sun20i-d1-mipi-dsi ++ - const: allwinner,sun50i-a100-mipi-dsi + + reg: + maxItems: 1 +@@ -59,7 +64,6 @@ required: + - phys + - phy-names + - resets +- - vcc-dsi-supply + - port + + allOf: +@@ -68,7 +72,9 @@ allOf: + properties: + compatible: + contains: +- const: allwinner,sun6i-a31-mipi-dsi ++ enum: ++ - allwinner,sun6i-a31-mipi-dsi ++ - allwinner,sun50i-a100-mipi-dsi + + then: + properties: +@@ -83,6 +89,18 @@ allOf: + clocks: + maxItems: 1 + ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - allwinner,sun6i-a31-mipi-dsi ++ - allwinner,sun50i-a64-mipi-dsi ++ ++ then: ++ required: ++ - vcc-dsi-supply ++ + unevaluatedProperties: false + + examples: diff --git a/target/linux/d1/patches-6.1/0096-drm-sun4i-dsi-Add-a-variant-structure.patch b/target/linux/d1/patches-6.1/0096-drm-sun4i-dsi-Add-a-variant-structure.patch new file mode 100644 index 0000000000..afe7a1ed42 --- /dev/null +++ b/target/linux/d1/patches-6.1/0096-drm-sun4i-dsi-Add-a-variant-structure.patch @@ -0,0 +1,158 @@ +From 28e64e830ef487b400b3b943fa3bda83dfb2a937 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 9 Aug 2022 22:03:42 -0500 +Subject: [PATCH 096/117] drm/sun4i: dsi: Add a variant structure + +Replace the ad-hoc calls to of_device_is_compatible() with a structure +describing the differences between variants. This is in preparation for +adding more variants to the driver. + +Series-changes: 2 + - Add the variant check to the probe error path + +Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 53 +++++++++++++++++--------- + drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 7 ++++ + 2 files changed, 42 insertions(+), 18 deletions(-) + +--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c ++++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +@@ -1101,12 +1101,16 @@ static const struct component_ops sun6i_ + + static int sun6i_dsi_probe(struct platform_device *pdev) + { ++ const struct sun6i_dsi_variant *variant; + struct device *dev = &pdev->dev; +- const char *bus_clk_name = NULL; + struct sun6i_dsi *dsi; + void __iomem *base; + int ret; + ++ variant = device_get_match_data(dev); ++ if (!variant) ++ return -EINVAL; ++ + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return -ENOMEM; +@@ -1114,10 +1118,7 @@ static int sun6i_dsi_probe(struct platfo + dsi->dev = dev; + dsi->host.ops = &sun6i_dsi_host_ops; + dsi->host.dev = dev; +- +- if (of_device_is_compatible(dev->of_node, +- "allwinner,sun6i-a31-mipi-dsi")) +- bus_clk_name = "bus"; ++ dsi->variant = variant; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) { +@@ -1142,7 +1143,7 @@ static int sun6i_dsi_probe(struct platfo + return PTR_ERR(dsi->regs); + } + +- dsi->bus_clk = devm_clk_get(dev, bus_clk_name); ++ dsi->bus_clk = devm_clk_get(dev, variant->has_mod_clk ? "bus" : NULL); + if (IS_ERR(dsi->bus_clk)) + return dev_err_probe(dev, PTR_ERR(dsi->bus_clk), + "Couldn't get the DSI bus clock\n"); +@@ -1151,21 +1152,21 @@ static int sun6i_dsi_probe(struct platfo + if (ret) + return ret; + +- if (of_device_is_compatible(dev->of_node, +- "allwinner,sun6i-a31-mipi-dsi")) { ++ if (variant->has_mod_clk) { + dsi->mod_clk = devm_clk_get(dev, "mod"); + if (IS_ERR(dsi->mod_clk)) { + dev_err(dev, "Couldn't get the DSI mod clock\n"); + ret = PTR_ERR(dsi->mod_clk); + goto err_attach_clk; + } +- } + +- /* +- * In order to operate properly, that clock seems to be always +- * set to 297MHz. +- */ +- clk_set_rate_exclusive(dsi->mod_clk, 297000000); ++ /* ++ * In order to operate properly, the module clock on the ++ * A31 variant always seems to be set to 297MHz. ++ */ ++ if (variant->set_mod_clk) ++ clk_set_rate_exclusive(dsi->mod_clk, 297000000); ++ } + + dsi->dphy = devm_phy_get(dev, "dphy"); + if (IS_ERR(dsi->dphy)) { +@@ -1191,7 +1192,8 @@ static int sun6i_dsi_probe(struct platfo + err_remove_dsi_host: + mipi_dsi_host_unregister(&dsi->host); + err_unprotect_clk: +- clk_rate_exclusive_put(dsi->mod_clk); ++ if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk) ++ clk_rate_exclusive_put(dsi->mod_clk); + err_attach_clk: + regmap_mmio_detach_clk(dsi->regs); + +@@ -1205,16 +1207,31 @@ static int sun6i_dsi_remove(struct platf + + component_del(&pdev->dev, &sun6i_dsi_ops); + mipi_dsi_host_unregister(&dsi->host); +- clk_rate_exclusive_put(dsi->mod_clk); ++ if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk) ++ clk_rate_exclusive_put(dsi->mod_clk); + + regmap_mmio_detach_clk(dsi->regs); + + return 0; + } + ++static const struct sun6i_dsi_variant sun6i_a31_mipi_dsi_variant = { ++ .has_mod_clk = true, ++ .set_mod_clk = true, ++}; ++ ++static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = { ++}; ++ + static const struct of_device_id sun6i_dsi_of_table[] = { +- { .compatible = "allwinner,sun6i-a31-mipi-dsi" }, +- { .compatible = "allwinner,sun50i-a64-mipi-dsi" }, ++ { ++ .compatible = "allwinner,sun6i-a31-mipi-dsi", ++ .data = &sun6i_a31_mipi_dsi_variant, ++ }, ++ { ++ .compatible = "allwinner,sun50i-a64-mipi-dsi", ++ .data = &sun50i_a64_mipi_dsi_variant, ++ }, + { } + }; + MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); +--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h ++++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h +@@ -15,6 +15,11 @@ + + #define SUN6I_DSI_TCON_DIV 4 + ++struct sun6i_dsi_variant { ++ bool has_mod_clk; ++ bool set_mod_clk; ++}; ++ + struct sun6i_dsi { + struct drm_connector connector; + struct drm_encoder encoder; +@@ -31,6 +36,8 @@ struct sun6i_dsi { + struct mipi_dsi_device *device; + struct drm_device *drm; + struct drm_panel *panel; ++ ++ const struct sun6i_dsi_variant *variant; + }; + + static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host) diff --git a/target/linux/d1/patches-6.1/0097-drm-sun4i-dsi-Add-the-A100-variant.patch b/target/linux/d1/patches-6.1/0097-drm-sun4i-dsi-Add-the-A100-variant.patch new file mode 100644 index 0000000000..0077e37ed4 --- /dev/null +++ b/target/linux/d1/patches-6.1/0097-drm-sun4i-dsi-Add-the-A100-variant.patch @@ -0,0 +1,66 @@ +From 713029c6a33df9218d11593bc5be79420715633f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 11:06:22 -0500 +Subject: [PATCH 097/117] drm/sun4i: dsi: Add the A100 variant + +The A100 variant of the MIPI DSI controller now gets its module clock +from the TCON via the TCON TOP, so the clock rate cannot be set to a +fixed value. Otherwise, it appears to be the same as the A31 variant. + +Cover-letter: +drm/sun4i: dsi: Support the A100/D1 controller variant +This series adds support for the digital part of the DSI controller +found in the A100 and D1 SoCs (plus T7, which is not supported by +mainline Linux). There are two changes to the hardware integration: + 1) the module clock routes through the TCON TOP, and + 2) the separate I/O domain is removed. + +The actual register interface appears to be the same as before. The +register definitions in the D1 BSP exactly match the A64 BSP. + +The BSP describes this as the "40nm" DSI controller variant. There is +also a "28nm" variant with a different register interface; that one is +found in a different subset of SoCs (V5 and A50). + +A100/D1 also come with an updated DPHY, described by the BSP as a +"combo" PHY, which is now also used for LVDS channel 0. (LVDS and DSI +share the same pins on Port D.) Since that is a different subsystem, +I am sending that as a separate series. +END + +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> +Series-to: Maxime Ripard <mripard@kernel.org> + +Series-version: 2 + +Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c ++++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +@@ -1223,6 +1223,10 @@ static const struct sun6i_dsi_variant su + static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = { + }; + ++static const struct sun6i_dsi_variant sun50i_a100_mipi_dsi_variant = { ++ .has_mod_clk = true, ++}; ++ + static const struct of_device_id sun6i_dsi_of_table[] = { + { + .compatible = "allwinner,sun6i-a31-mipi-dsi", +@@ -1232,6 +1236,10 @@ static const struct of_device_id sun6i_d + .compatible = "allwinner,sun50i-a64-mipi-dsi", + .data = &sun50i_a64_mipi_dsi_variant, + }, ++ { ++ .compatible = "allwinner,sun50i-a100-mipi-dsi", ++ .data = &sun50i_a100_mipi_dsi_variant, ++ }, + { } + }; + MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); diff --git a/target/linux/d1/patches-6.1/0098-riscv-Move-cast-inside-kernel_mapping_-pv-a_to_-vp-a.patch b/target/linux/d1/patches-6.1/0098-riscv-Move-cast-inside-kernel_mapping_-pv-a_to_-vp-a.patch new file mode 100644 index 0000000000..c4ac271b20 --- /dev/null +++ b/target/linux/d1/patches-6.1/0098-riscv-Move-cast-inside-kernel_mapping_-pv-a_to_-vp-a.patch @@ -0,0 +1,81 @@ +From b6af4b7f6f75904509747c08e87d91c1bb607bd4 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Thu, 22 Sep 2022 00:39:36 -0500 +Subject: [PATCH 098/117] riscv: Move cast inside kernel_mapping_[pv]a_to_[vp]a + +Before commit 44c922572952 ("RISC-V: enable XIP"), these macros cast +their argument to unsigned long. That commit moved the cast after an +assignment to an unsigned long variable, rendering it ineffectual. +Move the cast back, so we can remove the cast at each call site. + +Series-to: Palmer Dabbelt <palmer@dabbelt.com> +Series-to: linux-riscv@lists.infradead.org + +Series-version: 2 + +Reviewed-by: Alexandre Ghiti <alexandre.ghiti@canonical.com> +Reviewed-by: Heiko Stuebner <heiko@sntech.de> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/include/asm/page.h | 18 +++++++++--------- + arch/riscv/mm/init.c | 16 ++++++++-------- + 2 files changed, 17 insertions(+), 17 deletions(-) + +--- a/arch/riscv/include/asm/page.h ++++ b/arch/riscv/include/asm/page.h +@@ -123,20 +123,20 @@ extern phys_addr_t phys_ram_base; + ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE)) + + #define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset)) +-#define kernel_mapping_pa_to_va(y) ({ \ +- unsigned long _y = y; \ +- (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \ +- (void *)((unsigned long)(_y) + kernel_map.va_kernel_xip_pa_offset) : \ +- (void *)((unsigned long)(_y) + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \ ++#define kernel_mapping_pa_to_va(y) ({ \ ++ unsigned long _y = (unsigned long)(y); \ ++ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \ ++ (void *)(_y + kernel_map.va_kernel_xip_pa_offset) : \ ++ (void *)(_y + kernel_map.va_kernel_pa_offset + XIP_OFFSET); \ + }) + #define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x) + + #define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset) + #define kernel_mapping_va_to_pa(y) ({ \ +- unsigned long _y = y; \ +- (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \ +- ((unsigned long)(_y) - kernel_map.va_kernel_xip_pa_offset) : \ +- ((unsigned long)(_y) - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \ ++ unsigned long _y = (unsigned long)(y); \ ++ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \ ++ (_y - kernel_map.va_kernel_xip_pa_offset) : \ ++ (_y - kernel_map.va_kernel_pa_offset - XIP_OFFSET); \ + }) + + #define __va_to_pa_nodebug(x) ({ \ +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -903,15 +903,15 @@ static void __init pt_ops_set_early(void + */ + static void __init pt_ops_set_fixmap(void) + { +- pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap); +- pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap); ++ pt_ops.alloc_pte = kernel_mapping_pa_to_va(alloc_pte_fixmap); ++ pt_ops.get_pte_virt = kernel_mapping_pa_to_va(get_pte_virt_fixmap); + #ifndef __PAGETABLE_PMD_FOLDED +- pt_ops.alloc_pmd = kernel_mapping_pa_to_va((uintptr_t)alloc_pmd_fixmap); +- pt_ops.get_pmd_virt = kernel_mapping_pa_to_va((uintptr_t)get_pmd_virt_fixmap); +- pt_ops.alloc_pud = kernel_mapping_pa_to_va((uintptr_t)alloc_pud_fixmap); +- pt_ops.get_pud_virt = kernel_mapping_pa_to_va((uintptr_t)get_pud_virt_fixmap); +- pt_ops.alloc_p4d = kernel_mapping_pa_to_va((uintptr_t)alloc_p4d_fixmap); +- pt_ops.get_p4d_virt = kernel_mapping_pa_to_va((uintptr_t)get_p4d_virt_fixmap); ++ pt_ops.alloc_pmd = kernel_mapping_pa_to_va(alloc_pmd_fixmap); ++ pt_ops.get_pmd_virt = kernel_mapping_pa_to_va(get_pmd_virt_fixmap); ++ pt_ops.alloc_pud = kernel_mapping_pa_to_va(alloc_pud_fixmap); ++ pt_ops.get_pud_virt = kernel_mapping_pa_to_va(get_pud_virt_fixmap); ++ pt_ops.alloc_p4d = kernel_mapping_pa_to_va(alloc_p4d_fixmap); ++ pt_ops.get_p4d_virt = kernel_mapping_pa_to_va(get_p4d_virt_fixmap); + #endif + } + diff --git a/target/linux/d1/patches-6.1/0099-dt-bindings-sun6i-a31-mipi-dphy-Add-the-interrupts-p.patch b/target/linux/d1/patches-6.1/0099-dt-bindings-sun6i-a31-mipi-dphy-Add-the-interrupts-p.patch new file mode 100644 index 0000000000..056d92af36 --- /dev/null +++ b/target/linux/d1/patches-6.1/0099-dt-bindings-sun6i-a31-mipi-dphy-Add-the-interrupts-p.patch @@ -0,0 +1,38 @@ +From 20a204b31291befcd583f97dafc0a827f3bc7f00 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 12 Aug 2022 01:37:16 -0500 +Subject: [PATCH 099/117] dt-bindings: sun6i-a31-mipi-dphy: Add the interrupts + property + +The sun6i DPHY can generate several interrupts, mostly for reporting +error conditions, but also for detecting BTA and UPLS sequences. +Document this capability in order to accurately describe the hardware. + +The DPHY has no interrupt number provided in the vendor documentation +because its interrupt line is shared with the DSI controller. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml ++++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml +@@ -24,6 +24,9 @@ properties: + reg: + maxItems: 1 + ++ interrupts: ++ maxItems: 1 ++ + clocks: + items: + - description: Bus Clock +@@ -53,6 +56,7 @@ required: + - "#phy-cells" + - compatible + - reg ++ - interrupts + - clocks + - clock-names + - resets diff --git a/target/linux/d1/patches-6.1/0100-ARM-dts-sun8i-a33-Add-DPHY-interrupt.patch b/target/linux/d1/patches-6.1/0100-ARM-dts-sun8i-a33-Add-DPHY-interrupt.patch new file mode 100644 index 0000000000..36a4627e00 --- /dev/null +++ b/target/linux/d1/patches-6.1/0100-ARM-dts-sun8i-a33-Add-DPHY-interrupt.patch @@ -0,0 +1,22 @@ +From 7d47c62b378a4dbbf3e46a80c7b03966f8964da1 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 12 Aug 2022 02:24:14 -0500 +Subject: [PATCH 100/117] ARM: dts: sun8i: a33: Add DPHY interrupt + +The DPHY has an interrupt line which is shared with the DSI controller. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/arm/boot/dts/sun8i-a33.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/sun8i-a33.dtsi ++++ b/arch/arm/boot/dts/sun8i-a33.dtsi +@@ -278,6 +278,7 @@ + dphy: d-phy@1ca1000 { + compatible = "allwinner,sun6i-a31-mipi-dphy"; + reg = <0x01ca1000 0x1000>; ++ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_MIPI_DSI>, + <&ccu CLK_DSI_DPHY>; + clock-names = "bus", "mod"; diff --git a/target/linux/d1/patches-6.1/0101-arm64-dts-allwinner-a64-Add-DPHY-interrupt.patch b/target/linux/d1/patches-6.1/0101-arm64-dts-allwinner-a64-Add-DPHY-interrupt.patch new file mode 100644 index 0000000000..5734a84a19 --- /dev/null +++ b/target/linux/d1/patches-6.1/0101-arm64-dts-allwinner-a64-Add-DPHY-interrupt.patch @@ -0,0 +1,22 @@ +From 11d78fce09e80ec246016c19ecc28a724e1e5530 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Fri, 12 Aug 2022 02:25:55 -0500 +Subject: [PATCH 101/117] arm64: dts: allwinner: a64: Add DPHY interrupt + +The DPHY has an interrupt line which is shared with the DSI controller. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +@@ -1199,6 +1199,7 @@ + compatible = "allwinner,sun50i-a64-mipi-dphy", + "allwinner,sun6i-a31-mipi-dphy"; + reg = <0x01ca1000 0x1000>; ++ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_MIPI_DSI>, + <&ccu CLK_DSI_DPHY>; + clock-names = "bus", "mod"; diff --git a/target/linux/d1/patches-6.1/0102-dt-bindings-sun6i-a31-mipi-dphy-Add-the-A100-DPHY-va.patch b/target/linux/d1/patches-6.1/0102-dt-bindings-sun6i-a31-mipi-dphy-Add-the-A100-DPHY-va.patch new file mode 100644 index 0000000000..6c93a60296 --- /dev/null +++ b/target/linux/d1/patches-6.1/0102-dt-bindings-sun6i-a31-mipi-dphy-Add-the-A100-DPHY-va.patch @@ -0,0 +1,34 @@ +From c7fa1be12bf0ef02f5557dd1d1100d25af4e34f5 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 11:00:12 -0500 +Subject: [PATCH 102/117] dt-bindings: sun6i-a31-mipi-dphy: Add the A100 DPHY + variant + +A100 features an updated DPHY, which moves PLL control inside the DPHY +register space. (Previously PLL-MIPI was controlled from the CCU. This +does not affect the "clocks" property because the link between PLL-MIPI +and the DPHY was never represented in the devicetree.) It also requires +a modified analog power-on sequence. Finally, the new DPHY adds support +for operating as an LVDS PHY. D1 uses this same variant. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml ++++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml +@@ -17,9 +17,13 @@ properties: + compatible: + oneOf: + - const: allwinner,sun6i-a31-mipi-dphy ++ - const: allwinner,sun50i-a100-mipi-dphy + - items: + - const: allwinner,sun50i-a64-mipi-dphy + - const: allwinner,sun6i-a31-mipi-dphy ++ - items: ++ - const: allwinner,sun20i-d1-mipi-dphy ++ - const: allwinner,sun50i-a100-mipi-dphy + + reg: + maxItems: 1 diff --git a/target/linux/d1/patches-6.1/0103-phy-allwinner-phy-sun6i-mipi-dphy-Make-RX-support-op.patch b/target/linux/d1/patches-6.1/0103-phy-allwinner-phy-sun6i-mipi-dphy-Make-RX-support-op.patch new file mode 100644 index 0000000000..6a1f4f9af9 --- /dev/null +++ b/target/linux/d1/patches-6.1/0103-phy-allwinner-phy-sun6i-mipi-dphy-Make-RX-support-op.patch @@ -0,0 +1,80 @@ +From 27c0c2cbe7b30b907b031016d2cd15fe9505cb1b Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 12:11:53 -0500 +Subject: [PATCH 103/117] phy: allwinner: phy-sun6i-mipi-dphy: Make RX support + optional + +While all variants of the DPHY likely support RX mode, the new variant +in the A100 is not used in this direction by the BSP, and it has some +analog register changes, so its RX power-on sequence is unknown. To be +safe, limit RX support to variants where the power-on sequence is known. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 25 +++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c ++++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c +@@ -114,6 +114,10 @@ enum sun6i_dphy_direction { + SUN6I_DPHY_DIRECTION_RX, + }; + ++struct sun6i_dphy_variant { ++ bool supports_rx; ++}; ++ + struct sun6i_dphy { + struct clk *bus_clk; + struct clk *mod_clk; +@@ -123,6 +127,7 @@ struct sun6i_dphy { + struct phy *phy; + struct phy_configure_opts_mipi_dphy config; + ++ const struct sun6i_dphy_variant *variant; + enum sun6i_dphy_direction direction; + }; + +@@ -409,6 +414,10 @@ static int sun6i_dphy_probe(struct platf + if (!dphy) + return -ENOMEM; + ++ dphy->variant = device_get_match_data(&pdev->dev); ++ if (!dphy->variant) ++ return -EINVAL; ++ + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); +@@ -445,8 +454,13 @@ static int sun6i_dphy_probe(struct platf + ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction", + &direction); + +- if (!ret && !strncmp(direction, "rx", 2)) ++ if (!ret && !strncmp(direction, "rx", 2)) { ++ if (!dphy->variant->supports_rx) { ++ dev_err(&pdev->dev, "RX not supported on this variant\n"); ++ return -EOPNOTSUPP; ++ } + dphy->direction = SUN6I_DPHY_DIRECTION_RX; ++ } + + phy_set_drvdata(dphy->phy, dphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); +@@ -454,8 +468,15 @@ static int sun6i_dphy_probe(struct platf + return PTR_ERR_OR_ZERO(phy_provider); + } + ++static const struct sun6i_dphy_variant sun6i_a31_mipi_dphy_variant = { ++ .supports_rx = true, ++}; ++ + static const struct of_device_id sun6i_dphy_of_table[] = { +- { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, ++ { ++ .compatible = "allwinner,sun6i-a31-mipi-dphy", ++ .data = &sun6i_a31_mipi_dphy_variant, ++ }, + { } + }; + MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); diff --git a/target/linux/d1/patches-6.1/0104-phy-allwinner-phy-sun6i-mipi-dphy-Set-enable-bit-las.patch b/target/linux/d1/patches-6.1/0104-phy-allwinner-phy-sun6i-mipi-dphy-Set-enable-bit-las.patch new file mode 100644 index 0000000000..e8c6ef8c5a --- /dev/null +++ b/target/linux/d1/patches-6.1/0104-phy-allwinner-phy-sun6i-mipi-dphy-Set-enable-bit-las.patch @@ -0,0 +1,39 @@ +From 16993169c82c2c57e1df1e7f4598a7c2aa565fe2 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 11:12:02 -0500 +Subject: [PATCH 104/117] phy: allwinner: phy-sun6i-mipi-dphy: Set enable bit + last + +The A100 variant of the DPHY requires configuring the analog registers +before setting the global enable bit. Since this order also works on the +other variants, always use it, to minimize the differences between them. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c ++++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c +@@ -183,10 +183,6 @@ static int sun6i_dphy_tx_power_on(struct + SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | + SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); + +- regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, +- SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | +- SUN6I_DPHY_GCTL_EN); +- + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, + SUN6I_DPHY_ANA0_REG_PWS | + SUN6I_DPHY_ANA0_REG_DMPC | +@@ -244,6 +240,10 @@ static int sun6i_dphy_tx_power_on(struct + SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK, + SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask)); + ++ regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, ++ SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | ++ SUN6I_DPHY_GCTL_EN); ++ + return 0; + } + diff --git a/target/linux/d1/patches-6.1/0105-phy-allwinner-phy-sun6i-mipi-dphy-Add-a-variant-powe.patch b/target/linux/d1/patches-6.1/0105-phy-allwinner-phy-sun6i-mipi-dphy-Add-a-variant-powe.patch new file mode 100644 index 0000000000..6df659e80d --- /dev/null +++ b/target/linux/d1/patches-6.1/0105-phy-allwinner-phy-sun6i-mipi-dphy-Add-a-variant-powe.patch @@ -0,0 +1,109 @@ +From b953c09bde508c2edd8acd95abba8542b6cebff6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 11:44:09 -0500 +Subject: [PATCH 105/117] phy: allwinner: phy-sun6i-mipi-dphy: Add a variant + power-on hook + +The A100 variant uses the same values for the timing registers, and it +uses the same final power-on sequence, but it needs a different analog +register configuration in the middle. Support this by moving the +variant-specific parts to a hook provided by the variant. + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 59 ++++++++++++--------- + 1 file changed, 35 insertions(+), 24 deletions(-) + +--- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c ++++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c +@@ -114,7 +114,10 @@ enum sun6i_dphy_direction { + SUN6I_DPHY_DIRECTION_RX, + }; + ++struct sun6i_dphy; ++ + struct sun6i_dphy_variant { ++ void (*tx_power_on)(struct sun6i_dphy *dphy); + bool supports_rx; + }; + +@@ -156,33 +159,10 @@ static int sun6i_dphy_configure(struct p + return 0; + } + +-static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) ++static void sun6i_a31_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) + { + u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); + +- regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, +- SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); +- +- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, +- SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | +- SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | +- SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); +- +- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, +- SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | +- SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | +- SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | +- SUN6I_DPHY_TX_TIME1_CLK_POST(10)); +- +- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, +- SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); +- +- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); +- +- regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, +- SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | +- SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); +- + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, + SUN6I_DPHY_ANA0_REG_PWS | + SUN6I_DPHY_ANA0_REG_DMPC | +@@ -214,6 +194,36 @@ static int sun6i_dphy_tx_power_on(struct + SUN6I_DPHY_ANA3_EN_LDOC | + SUN6I_DPHY_ANA3_EN_LDOD); + udelay(1); ++} ++ ++static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) ++{ ++ u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, ++ SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, ++ SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | ++ SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | ++ SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, ++ SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | ++ SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | ++ SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | ++ SUN6I_DPHY_TX_TIME1_CLK_POST(10)); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, ++ SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, ++ SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | ++ SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); ++ ++ dphy->variant->tx_power_on(dphy); + + regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, + SUN6I_DPHY_ANA3_EN_VTTC | +@@ -469,6 +479,7 @@ static int sun6i_dphy_probe(struct platf + } + + static const struct sun6i_dphy_variant sun6i_a31_mipi_dphy_variant = { ++ .tx_power_on = sun6i_a31_mipi_dphy_tx_power_on, + .supports_rx = true, + }; + diff --git a/target/linux/d1/patches-6.1/0106-phy-allwinner-phy-sun6i-mipi-dphy-Add-the-A100-DPHY-.patch b/target/linux/d1/patches-6.1/0106-phy-allwinner-phy-sun6i-mipi-dphy-Add-the-A100-DPHY-.patch new file mode 100644 index 0000000000..751d382177 --- /dev/null +++ b/target/linux/d1/patches-6.1/0106-phy-allwinner-phy-sun6i-mipi-dphy-Add-the-A100-DPHY-.patch @@ -0,0 +1,229 @@ +From 474b608dee5e6285dd1981b00ab568a2f7f15fd0 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 10 Aug 2022 23:02:06 -0500 +Subject: [PATCH 106/117] phy: allwinner: phy-sun6i-mipi-dphy: Add the A100 + DPHY variant + +A100 features an updated DPHY, which moves PLL control inside the DPHY +register space (previously the PLL was controlled from the CCU). It also +requires a modified analog power-on sequence. This "combo PHY" can also +be used as an LVDS PHY, but that is not yet supported by the driver. + +Cover-letter: +phy: allwinner: phy-sun6i-mipi-dphy: Add the A100 DPHY +This series adds support for the updated DPHY found in a couple of +recent Allwinner SoCs. The first three patches fix an omission in the +existing binding. The remaining patches add the new hardware variant. +END + +Series-to: Kishon Vijay Abraham I <kishon@ti.com> +Series-to: Vinod Koul <vkoul@kernel.org> +Series-to: Chen-Yu Tsai <wens@csie.org> +Series-to: Jernej Skrabec <jernej.skrabec@gmail.com> +Series-to: Maxime Ripard <mripard@kernel.org> +Series-cc: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 143 +++++++++++++++++++- + 1 file changed, 142 insertions(+), 1 deletion(-) + +--- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c ++++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c +@@ -70,11 +70,19 @@ + + #define SUN6I_DPHY_ANA0_REG 0x4c + #define SUN6I_DPHY_ANA0_REG_PWS BIT(31) ++#define SUN6I_DPHY_ANA0_REG_PWEND BIT(30) ++#define SUN6I_DPHY_ANA0_REG_PWENC BIT(29) + #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) + #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) ++#define SUN6I_DPHY_ANA0_REG_SRXDT(n) (((n) & 0xf) << 20) ++#define SUN6I_DPHY_ANA0_REG_SRXCK(n) (((n) & 0xf) << 16) ++#define SUN6I_DPHY_ANA0_REG_SDIV2 BIT(15) + #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) + #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) ++#define SUN6I_DPHY_ANA0_REG_PLR(n) (((n) & 0xf) << 4) + #define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2) ++#define SUN6I_DPHY_ANA0_REG_RSD BIT(1) ++#define SUN6I_DPHY_ANA0_REG_SELSCK BIT(0) + + #define SUN6I_DPHY_ANA1_REG 0x50 + #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) +@@ -97,8 +105,13 @@ + #define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) + + #define SUN6I_DPHY_ANA4_REG 0x5c ++#define SUN6I_DPHY_ANA4_REG_EN_MIPI BIT(31) ++#define SUN6I_DPHY_ANA4_REG_EN_COMTEST BIT(30) ++#define SUN6I_DPHY_ANA4_REG_COMTEST(n) (((n) & 3) << 28) ++#define SUN6I_DPHY_ANA4_REG_IB(n) (((n) & 3) << 25) + #define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) + #define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) ++#define SUN6I_DPHY_ANA4_REG_VTT_SET(n) (((n) & 0x7) << 17) + #define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) + #define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) + #define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) +@@ -109,6 +122,56 @@ + + #define SUN6I_DPHY_DBG5_REG 0xf4 + ++#define SUN50I_DPHY_TX_SLEW_REG0 0xf8 ++#define SUN50I_DPHY_TX_SLEW_REG1 0xfc ++#define SUN50I_DPHY_TX_SLEW_REG2 0x100 ++ ++#define SUN50I_DPHY_PLL_REG0 0x104 ++#define SUN50I_DPHY_PLL_REG0_CP36_EN BIT(23) ++#define SUN50I_DPHY_PLL_REG0_LDO_EN BIT(22) ++#define SUN50I_DPHY_PLL_REG0_EN_LVS BIT(21) ++#define SUN50I_DPHY_PLL_REG0_PLL_EN BIT(20) ++#define SUN50I_DPHY_PLL_REG0_P(n) (((n) & 0xf) << 16) ++#define SUN50I_DPHY_PLL_REG0_N(n) (((n) & 0xff) << 8) ++#define SUN50I_DPHY_PLL_REG0_NDET BIT(7) ++#define SUN50I_DPHY_PLL_REG0_TDIV BIT(6) ++#define SUN50I_DPHY_PLL_REG0_M0(n) (((n) & 3) << 4) ++#define SUN50I_DPHY_PLL_REG0_M1(n) ((n) & 0xf) ++ ++#define SUN50I_DPHY_PLL_REG1 0x108 ++#define SUN50I_DPHY_PLL_REG1_UNLOCK_MDSEL(n) (((n) & 3) << 14) ++#define SUN50I_DPHY_PLL_REG1_LOCKMDSEL BIT(13) ++#define SUN50I_DPHY_PLL_REG1_LOCKDET_EN BIT(12) ++#define SUN50I_DPHY_PLL_REG1_VSETA(n) (((n) & 0x7) << 9) ++#define SUN50I_DPHY_PLL_REG1_VSETD(n) (((n) & 0x7) << 6) ++#define SUN50I_DPHY_PLL_REG1_LPF_SW BIT(5) ++#define SUN50I_DPHY_PLL_REG1_ICP_SEL(n) (((n) & 3) << 3) ++#define SUN50I_DPHY_PLL_REG1_ATEST_SEL(n) (((n) & 3) << 1) ++#define SUN50I_DPHY_PLL_REG1_TEST_EN BIT(0) ++ ++#define SUN50I_DPHY_PLL_REG2 0x10c ++#define SUN50I_DPHY_PLL_REG2_SDM_EN BIT(31) ++#define SUN50I_DPHY_PLL_REG2_FF_EN BIT(30) ++#define SUN50I_DPHY_PLL_REG2_SS_EN BIT(29) ++#define SUN50I_DPHY_PLL_REG2_SS_FRAC(n) (((n) & 0x1ff) << 20) ++#define SUN50I_DPHY_PLL_REG2_SS_INT(n) (((n) & 0xff) << 12) ++#define SUN50I_DPHY_PLL_REG2_FRAC(n) ((n) & 0xfff) ++ ++#define SUN50I_COMBO_PHY_REG0 0x110 ++#define SUN50I_COMBO_PHY_REG0_EN_TEST_COMBOLDO BIT(5) ++#define SUN50I_COMBO_PHY_REG0_EN_TEST_0P8 BIT(4) ++#define SUN50I_COMBO_PHY_REG0_EN_MIPI BIT(3) ++#define SUN50I_COMBO_PHY_REG0_EN_LVDS BIT(2) ++#define SUN50I_COMBO_PHY_REG0_EN_COMBOLDO BIT(1) ++#define SUN50I_COMBO_PHY_REG0_EN_CP BIT(0) ++ ++#define SUN50I_COMBO_PHY_REG1 0x114 ++#define SUN50I_COMBO_PHY_REG2_REG_VREF1P6(n) (((n) & 0x7) << 4) ++#define SUN50I_COMBO_PHY_REG2_REG_VREF0P8(n) ((n) & 0x7) ++ ++#define SUN50I_COMBO_PHY_REG2 0x118 ++#define SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(n) ((n) & 0xff) ++ + enum sun6i_dphy_direction { + SUN6I_DPHY_DIRECTION_TX, + SUN6I_DPHY_DIRECTION_RX, +@@ -196,6 +259,76 @@ static void sun6i_a31_mipi_dphy_tx_power + udelay(1); + } + ++static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) ++{ ++ unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; ++ unsigned int div, n; ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, ++ SUN6I_DPHY_ANA4_REG_IB(2) | ++ SUN6I_DPHY_ANA4_REG_DMPLVD(4) | ++ SUN6I_DPHY_ANA4_REG_VTT_SET(3) | ++ SUN6I_DPHY_ANA4_REG_CKDV(3) | ++ SUN6I_DPHY_ANA4_REG_TMSD(1) | ++ SUN6I_DPHY_ANA4_REG_TMSC(1) | ++ SUN6I_DPHY_ANA4_REG_TXPUSD(2) | ++ SUN6I_DPHY_ANA4_REG_TXPUSC(3) | ++ SUN6I_DPHY_ANA4_REG_TXDNSD(2) | ++ SUN6I_DPHY_ANA4_REG_TXDNSC(3)); ++ ++ regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, ++ SUN6I_DPHY_ANA2_EN_CK_CPU, ++ SUN6I_DPHY_ANA2_EN_CK_CPU); ++ ++ regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, ++ SUN6I_DPHY_ANA2_REG_ENIB, ++ SUN6I_DPHY_ANA2_REG_ENIB); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, ++ SUN6I_DPHY_ANA3_EN_LDOR | ++ SUN6I_DPHY_ANA3_EN_LDOC | ++ SUN6I_DPHY_ANA3_EN_LDOD); ++ ++ regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, ++ SUN6I_DPHY_ANA0_REG_PLR(4) | ++ SUN6I_DPHY_ANA0_REG_SFB(1)); ++ ++ regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0, ++ SUN50I_COMBO_PHY_REG0_EN_CP); ++ ++ /* Choose a divider to limit the VCO frequency to around 2 GHz. */ ++ div = 16 >> order_base_2(DIV_ROUND_UP(mipi_symbol_rate, 264000000)); ++ n = mipi_symbol_rate * div / 24000000; ++ ++ regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0, ++ SUN50I_DPHY_PLL_REG0_CP36_EN | ++ SUN50I_DPHY_PLL_REG0_LDO_EN | ++ SUN50I_DPHY_PLL_REG0_EN_LVS | ++ SUN50I_DPHY_PLL_REG0_PLL_EN | ++ SUN50I_DPHY_PLL_REG0_NDET | ++ SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) | ++ SUN50I_DPHY_PLL_REG0_N(n) | ++ SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) | ++ SUN50I_DPHY_PLL_REG0_M1(2)); ++ ++ /* Disable sigma-delta modulation. */ ++ regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0); ++ ++ regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG, ++ SUN6I_DPHY_ANA4_REG_EN_MIPI, ++ SUN6I_DPHY_ANA4_REG_EN_MIPI); ++ ++ regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0, ++ SUN50I_COMBO_PHY_REG0_EN_MIPI | ++ SUN50I_COMBO_PHY_REG0_EN_COMBOLDO, ++ SUN50I_COMBO_PHY_REG0_EN_MIPI | ++ SUN50I_COMBO_PHY_REG0_EN_COMBOLDO); ++ ++ regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2, ++ SUN50I_COMBO_PHY_REG2_HS_STOP_DLY(20)); ++ udelay(1); ++} ++ + static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) + { + u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); +@@ -408,7 +541,7 @@ static const struct regmap_config sun6i_ + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +- .max_register = SUN6I_DPHY_DBG5_REG, ++ .max_register = SUN50I_COMBO_PHY_REG2, + .name = "mipi-dphy", + }; + +@@ -483,11 +616,19 @@ static const struct sun6i_dphy_variant s + .supports_rx = true, + }; + ++static const struct sun6i_dphy_variant sun50i_a100_mipi_dphy_variant = { ++ .tx_power_on = sun50i_a100_mipi_dphy_tx_power_on, ++}; ++ + static const struct of_device_id sun6i_dphy_of_table[] = { + { + .compatible = "allwinner,sun6i-a31-mipi-dphy", + .data = &sun6i_a31_mipi_dphy_variant, + }, ++ { ++ .compatible = "allwinner,sun50i-a100-mipi-dphy", ++ .data = &sun50i_a100_mipi_dphy_variant, ++ }, + { } + }; + MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); diff --git a/target/linux/d1/patches-6.1/0107-drm-panel-Add-driver-for-Clockwork-cwd686-panel.patch b/target/linux/d1/patches-6.1/0107-drm-panel-Add-driver-for-Clockwork-cwd686-panel.patch new file mode 100644 index 0000000000..5dd0273b7e --- /dev/null +++ b/target/linux/d1/patches-6.1/0107-drm-panel-Add-driver-for-Clockwork-cwd686-panel.patch @@ -0,0 +1,518 @@ +From 5bf84a1a0a282a18bf9dd2d752537525aefc2e05 Mon Sep 17 00:00:00 2001 +From: Max Fierke <max@maxfierke.com> +Date: Wed, 1 Jun 2022 00:17:48 -0500 +Subject: [PATCH 107/117] drm: panel: Add driver for Clockwork cwd686 panel + +The Clockwork DevTerm (all models) uses a 6.86" IPS display +of unknown provenance, which uses the Chipone ICNL9707 IC driver. + +The display panel I have has two model numbers: TXW686001 and WTL068601G, +but cannot find any manufacturer associated with either, so opting for the +Clockwork model number. + +This driver is based on the GPL-licensed driver released by Clockwork, +authored by Pinfan Zhu, with some additional cleanup, rotation support, +and display sleep re-enabling done by me. + +Original driver here for reference: https://github.com/clockworkpi/DevTerm/blob/main/Code/patch/armbian_build_a06/patch/kernel-004-panel.patch +Display IC datasheet provided here: https://github.com/clockworkpi/DevTerm/blob/main/Schematics/ICNL9707_Datasheet.pdf + +Signed-off-by: Max Fierke <max@maxfierke.com> +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/Kconfig | 12 + + drivers/gpu/drm/panel/Makefile | 1 + + .../gpu/drm/panel/panel-clockwork-cwd686.c | 456 ++++++++++++++++++ + 3 files changed, 469 insertions(+) + create mode 100644 drivers/gpu/drm/panel/panel-clockwork-cwd686.c + +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -68,6 +68,18 @@ config DRM_PANEL_BOE_TV101WUM_NL6 + Say Y here if you want to support for BOE TV101WUM and AUO KD101N80 + 45NA WUXGA PANEL DSI Video Mode panel + ++config DRM_PANEL_CLOCKWORK_CWD686 ++ tristate "Clockwork CWD686 panel" ++ depends on OF ++ depends on DRM_MIPI_DSI ++ depends on BACKLIGHT_CLASS_DEVICE ++ help ++ Say Y here if you want to enable support for the Clockwork CWD686 ++ ICNL9707-based panel, e.g. as used within the Clockwork DevTerm. ++ The panel has a 480x1280 resolution and uses 24 bit RGB per pixel. ++ ++ To compile this driver as a module, choose M here. ++ + config DRM_PANEL_DSI_CM + tristate "Generic DSI command mode panels" + depends on OF +--- a/drivers/gpu/drm/panel/Makefile ++++ b/drivers/gpu/drm/panel/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_N + obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o + obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o + obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o ++obj-$(CONFIG_DRM_PANEL_CLOCKWORK_CWD686) += panel-clockwork-cwd686.o + obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o + obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o + obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o +--- /dev/null ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -0,0 +1,456 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2021 Clockwork Tech LLC ++ * Copyright (c) 2021-2022 Max Fierke <max@maxfierke.com> ++ * ++ * Based on Pinfan Zhu's work on panel-cwd686.c for ClockworkPi's 5.10 BSP ++ */ ++ ++#include <drm/drm_modes.h> ++#include <drm/drm_mipi_dsi.h> ++#include <drm/drm_panel.h> ++#include <linux/backlight.h> ++#include <linux/gpio/consumer.h> ++#include <linux/regulator/consumer.h> ++#include <linux/delay.h> ++#include <linux/of_device.h> ++#include <linux/module.h> ++#include <video/mipi_display.h> ++ ++struct cwd686 { ++ struct device *dev; ++ struct drm_panel panel; ++ struct regulator *supply; ++ struct gpio_desc *enable_gpio; ++ struct gpio_desc *reset_gpio; ++ struct backlight_device *backlight; ++ enum drm_panel_orientation orientation; ++ bool prepared; ++ bool enabled; ++}; ++ ++static const struct drm_display_mode default_mode = { ++ .clock = 54465, ++ .hdisplay = 480, ++ .hsync_start = 480 + 150, ++ .hsync_end = 480 + 150 + 24, ++ .htotal = 480 + 150 + 24 + 40, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 12, ++ .vsync_end = 1280 + 12 + 6, ++ .vtotal = 1280 + 12 + 6 + 10, ++}; ++ ++static inline struct cwd686 *panel_to_cwd686(struct drm_panel *panel) ++{ ++ return container_of(panel, struct cwd686, panel); ++} ++ ++#define ICNL9707_DCS(seq...) \ ++({ \ ++ static const u8 d[] = { seq }; \ ++ mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ ++}) ++ ++#define ICNL9707_CMD_CGOUTL 0xB3 ++#define ICNL9707_CMD_CGOUTR 0xB4 ++#define ICNL9707_P_CGOUT_VGL 0x00 ++#define ICNL9707_P_CGOUT_VGH 0x01 ++#define ICNL9707_P_CGOUT_HZ 0x02 ++#define ICNL9707_P_CGOUT_GND 0x03 ++#define ICNL9707_P_CGOUT_GSP1 0x04 ++#define ICNL9707_P_CGOUT_GSP2 0x05 ++#define ICNL9707_P_CGOUT_GSP3 0x06 ++#define ICNL9707_P_CGOUT_GSP4 0x07 ++#define ICNL9707_P_CGOUT_GSP5 0x08 ++#define ICNL9707_P_CGOUT_GSP6 0x09 ++#define ICNL9707_P_CGOUT_GSP7 0x0A ++#define ICNL9707_P_CGOUT_GSP8 0x0B ++#define ICNL9707_P_CGOUT_GCK1 0x0C ++#define ICNL9707_P_CGOUT_GCK2 0x0D ++#define ICNL9707_P_CGOUT_GCK3 0x0E ++#define ICNL9707_P_CGOUT_GCK4 0x0F ++#define ICNL9707_P_CGOUT_GCK5 0x10 ++#define ICNL9707_P_CGOUT_GCK6 0x11 ++#define ICNL9707_P_CGOUT_GCK7 0x12 ++#define ICNL9707_P_CGOUT_GCK8 0x13 ++#define ICNL9707_P_CGOUT_GCK9 0x14 ++#define ICNL9707_P_CGOUT_GCK10 0x15 ++#define ICNL9707_P_CGOUT_GCK11 0x16 ++#define ICNL9707_P_CGOUT_GCK12 0x17 ++#define ICNL9707_P_CGOUT_GCK13 0x18 ++#define ICNL9707_P_CGOUT_GCK14 0x19 ++#define ICNL9707_P_CGOUT_GCK15 0x1A ++#define ICNL9707_P_CGOUT_GCK16 0x1B ++#define ICNL9707_P_CGOUT_DIR 0x1C ++#define ICNL9707_P_CGOUT_DIRB 0x1D ++#define ICNL9707_P_CGOUT_ECLK_AC 0x1E ++#define ICNL9707_P_CGOUT_ECLK_ACB 0x1F ++#define ICNL9707_P_CGOUT_ECLK_AC2 0x20 ++#define ICNL9707_P_CGOUT_ECLK_AC2B 0x21 ++#define ICNL9707_P_CGOUT_GCH 0x22 ++#define ICNL9707_P_CGOUT_GCL 0x23 ++#define ICNL9707_P_CGOUT_XDON 0x24 ++#define ICNL9707_P_CGOUT_XDONB 0x25 ++ ++#define ICNL9707_MADCTL_ML 0x10 ++#define ICNL9707_MADCTL_RGB 0x00 ++#define ICNL9707_MADCTL_BGR 0x08 ++#define ICNL9707_MADCTL_MH 0x04 ++ ++#define ICNL9707_CMD_PWRCON_VCOM 0xB6 ++#define ICNL9707_P_PWRCON_VCOM_0495V 0x0D ++ ++#define ICNL9707_CMD_PWRCON_SEQ 0xB7 ++#define ICNL9707_CMD_PWRCON_CLK 0xB8 ++#define ICNL9707_CMD_PWRCON_BTA 0xB9 ++#define ICNL9707_CMD_PWRCON_MODE 0xBA ++#define ICNL9707_CMD_PWRCON_REG 0xBD ++ ++#define ICNL9707_CMD_TCON 0xC1 ++#define ICNL9707_CMD_TCON2 0xC2 ++#define ICNL9707_CMD_TCON3 0xC3 ++#define ICNL9707_CMD_SRC_TIM 0xC6 ++#define ICNL9707_CMD_SRCCON 0xC7 ++#define ICNL9707_CMD_SET_GAMMA 0xC8 ++ ++#define ICNL9707_CMD_ETC 0xD0 ++ ++#define ICNL9707_CMD_PASSWORD1 0xF0 ++#define ICNL9707_P_PASSWORD1_DEFAULT 0xA5 ++#define ICNL9707_P_PASSWORD1_ENABLE_LVL2 0x5A ++ ++#define ICNL9707_CMD_PASSWORD2 0xF1 ++#define ICNL9707_P_PASSWORD2_DEFAULT 0x5A ++#define ICNL9707_P_PASSWORD2_ENABLE_LVL2 0xA5 ++ ++static int cwd686_init_sequence(struct cwd686 *ctx) ++{ ++ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); ++ int err; ++ ++ /* Enable access to Level 2 registers */ ++ ICNL9707_DCS(ICNL9707_CMD_PASSWORD1, ++ ICNL9707_P_PASSWORD1_ENABLE_LVL2, ++ ICNL9707_P_PASSWORD1_ENABLE_LVL2); ++ ICNL9707_DCS(ICNL9707_CMD_PASSWORD2, ++ ICNL9707_P_PASSWORD2_ENABLE_LVL2, ++ ICNL9707_P_PASSWORD2_ENABLE_LVL2); ++ ++ /* Set PWRCON_VCOM (-0.495V, -0.495V) */ ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_VCOM, ++ ICNL9707_P_PWRCON_VCOM_0495V, ++ ICNL9707_P_PWRCON_VCOM_0495V); ++ ++ /* Map ASG output signals */ ++ ICNL9707_DCS(ICNL9707_CMD_CGOUTR, ++ ICNL9707_P_CGOUT_GSP7, ICNL9707_P_CGOUT_GSP5, ++ ICNL9707_P_CGOUT_GCK7, ICNL9707_P_CGOUT_GCK5, ++ ICNL9707_P_CGOUT_GCK3, ICNL9707_P_CGOUT_GCK1, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_VGL, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GSP1, ICNL9707_P_CGOUT_GSP3); ++ ICNL9707_DCS(ICNL9707_CMD_CGOUTL, ++ ICNL9707_P_CGOUT_GSP8, ICNL9707_P_CGOUT_GSP6, ++ ICNL9707_P_CGOUT_GCK8, ICNL9707_P_CGOUT_GCK6, ++ ICNL9707_P_CGOUT_GCK4, ICNL9707_P_CGOUT_GCK2, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_VGL, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, ++ ICNL9707_P_CGOUT_GSP2, ICNL9707_P_CGOUT_GSP4); ++ ++ /* Undocumented commands provided by the vendor */ ++ ICNL9707_DCS(0xB0, 0x54, 0x32, 0x23, 0x45, 0x44, 0x44, 0x44, 0x44, 0x90, 0x01, 0x90, 0x01); ++ ICNL9707_DCS(0xB1, 0x32, 0x84, 0x02, 0x83, 0x30, 0x01, 0x6B, 0x01); ++ ICNL9707_DCS(0xB2, 0x73); ++ ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_REG, ++ 0x4E, 0x0E, 0x50, 0x50, 0x26, ++ 0x1D, 0x00, 0x14, 0x42, 0x03); ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_SEQ, ++ 0x01, 0x01, 0x09, 0x11, 0x0D, 0x55, ++ 0x19, 0x19, 0x21, 0x1D, 0x00, 0x00, ++ 0x00, 0x00, 0x02, 0xFF, 0x3C); ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_CLK, 0x23, 0x01, 0x30, 0x34, 0x63); ++ ++ /* Disable abnormal power-off flag */ ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_BTA, 0xA0, 0x22, 0x00, 0x44); ++ ++ ICNL9707_DCS(ICNL9707_CMD_PWRCON_MODE, 0x12, 0x63); ++ ++ /* Set VBP, VFP, VSW, HBP, HFP, HSW */ ++ ICNL9707_DCS(ICNL9707_CMD_TCON, 0x0C, 0x16, 0x04, 0x0C, 0x10, 0x04); ++ ++ /* Set resolution */ ++ ICNL9707_DCS(ICNL9707_CMD_TCON2, 0x11, 0x41); ++ ++ /* Set frame blanking */ ++ ICNL9707_DCS(ICNL9707_CMD_TCON3, 0x22, 0x31, 0x04); ++ ++ ICNL9707_DCS(ICNL9707_CMD_SRCCON, 0x05, 0x23, 0x6B, 0x49, 0x00); ++ ++ /* Another undocumented command */ ++ ICNL9707_DCS(0xC5, 0x00); ++ ++ ICNL9707_DCS(ICNL9707_CMD_ETC, 0x37, 0xFF, 0xFF); ++ ++ /* Another set of undocumented commands */ ++ ICNL9707_DCS(0xD2, 0x63, 0x0B, 0x08, 0x88); ++ ICNL9707_DCS(0xD3, 0x01, 0x00, 0x00, 0x01, 0x01, 0x37, 0x25, 0x38, 0x31, 0x06, 0x07); ++ ++ /* Set Gamma to 2.2 */ ++ ICNL9707_DCS(ICNL9707_CMD_SET_GAMMA, ++ 0x7C, 0x6A, 0x5D, 0x53, 0x53, 0x45, 0x4B, ++ 0x35, 0x4D, 0x4A, 0x49, 0x66, 0x53, 0x57, ++ 0x4A, 0x48, 0x3B, 0x2A, 0x06, 0x7C, 0x6A, ++ 0x5D, 0x53, 0x53, 0x45, 0x4B, 0x35, 0x4D, ++ 0x4A, 0x49, 0x66, 0x53, 0x57, 0x4A, 0x48, ++ 0x3B, 0x2A, 0x06); ++ ++ ICNL9707_DCS(ICNL9707_CMD_SRC_TIM, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00); ++ ++ /* Another undocumented command */ ++ ICNL9707_DCS(0xF4, 0x08, 0x77); ++ ++ ICNL9707_DCS(MIPI_DCS_SET_ADDRESS_MODE, ++ ICNL9707_MADCTL_RGB | ICNL9707_MADCTL_ML | ICNL9707_MADCTL_MH); ++ ++ /* Enable tearing mode at VBLANK */ ++ err = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); ++ if (err) { ++ dev_err(ctx->dev, "failed to enable vblank TE (%d)\n", err); ++ return err; ++ } ++ ++ /* Disable access to Level 2 registers */ ++ ICNL9707_DCS(ICNL9707_CMD_PASSWORD2, ++ ICNL9707_P_PASSWORD2_DEFAULT, ++ ICNL9707_P_PASSWORD2_DEFAULT); ++ ICNL9707_DCS(ICNL9707_CMD_PASSWORD1, ++ ICNL9707_P_PASSWORD1_DEFAULT, ++ ICNL9707_P_PASSWORD1_DEFAULT); ++ ++ return 0; ++} ++ ++static int cwd686_disable(struct drm_panel *panel) ++{ ++ struct cwd686 *ctx = panel_to_cwd686(panel); ++ ++ if (!ctx->enabled) ++ return 0; ++ ++ backlight_disable(ctx->backlight); ++ ++ ctx->enabled = false; ++ ++ return 0; ++} ++ ++static int cwd686_unprepare(struct drm_panel *panel) ++{ ++ struct cwd686 *ctx = panel_to_cwd686(panel); ++ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); ++ int err; ++ ++ if (!ctx->prepared) ++ return 0; ++ ++ err = mipi_dsi_dcs_set_display_off(dsi); ++ if (err) { ++ dev_err(ctx->dev, "failed to turn display off (%d)\n", err); ++ return err; ++ } ++ ++ err = mipi_dsi_dcs_enter_sleep_mode(dsi); ++ if (err) { ++ dev_err(ctx->dev, "failed to enter sleep mode (%d)\n", err); ++ return err; ++ } ++ ++ msleep(120); ++ ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ ++ ctx->prepared = false; ++ ++ return 0; ++} ++ ++static int cwd686_prepare(struct drm_panel *panel) ++{ ++ struct cwd686 *ctx = panel_to_cwd686(panel); ++ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); ++ int err; ++ ++ if (ctx->prepared) ++ return 0; ++ ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ /* T2 */ ++ msleep(10); ++ ++ gpiod_set_value_cansleep(ctx->reset_gpio, 0); ++ /* T3 */ ++ msleep(20); ++ ++ /* Exit sleep mode and power on */ ++ ++ err = cwd686_init_sequence(ctx); ++ if (err) { ++ dev_err(ctx->dev, "failed to initialize display (%d)\n", err); ++ return err; ++ } ++ ++ err = mipi_dsi_dcs_exit_sleep_mode(dsi); ++ if (err) { ++ dev_err(ctx->dev, "failed to exit sleep mode (%d)\n", err); ++ return err; ++ } ++ /* T6 */ ++ msleep(120); ++ ++ err = mipi_dsi_dcs_set_display_on(dsi); ++ if (err) { ++ dev_err(ctx->dev, "failed to turn display on (%d)\n", err); ++ return err; ++ } ++ msleep(20); ++ ++ ctx->prepared = true; ++ ++ return 0; ++} ++ ++static int cwd686_enable(struct drm_panel *panel) ++{ ++ struct cwd686 *ctx = panel_to_cwd686(panel); ++ ++ if (ctx->enabled) ++ return 0; ++ ++ backlight_enable(ctx->backlight); ++ ++ ctx->enabled = true; ++ ++ return 0; ++} ++ ++static int cwd686_get_modes(struct drm_panel *panel, struct drm_connector *connector) ++{ ++ struct cwd686 *ctx = panel_to_cwd686(panel); ++ struct drm_display_mode *mode; ++ ++ mode = drm_mode_duplicate(connector->dev, &default_mode); ++ if (!mode) { ++ dev_err(panel->dev, "bad mode or failed to add mode\n"); ++ return -EINVAL; ++ } ++ drm_mode_set_name(mode); ++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ ++ connector->display_info.width_mm = mode->width_mm; ++ connector->display_info.height_mm = mode->height_mm; ++ ++ /* set up connector's "panel orientation" property */ ++ drm_connector_set_panel_orientation(connector, ctx->orientation); ++ ++ drm_mode_probed_add(connector, mode); ++ ++ return 1; /* Number of modes */ ++} ++ ++static const struct drm_panel_funcs cwd686_drm_funcs = { ++ .disable = cwd686_disable, ++ .unprepare = cwd686_unprepare, ++ .prepare = cwd686_prepare, ++ .enable = cwd686_enable, ++ .get_modes = cwd686_get_modes, ++}; ++ ++static int cwd686_probe(struct mipi_dsi_device *dsi) ++{ ++ struct device *dev = &dsi->dev; ++ struct cwd686 *ctx; ++ int err; ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ mipi_dsi_set_drvdata(dsi, ctx); ++ ctx->dev = dev; ++ ++ dsi->lanes = 4; ++ dsi->format = MIPI_DSI_FMT_RGB888; ++ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | ++ MIPI_DSI_MODE_VIDEO_BURST | ++ MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ++ ++ ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); ++ if (IS_ERR(ctx->reset_gpio)) { ++ err = PTR_ERR(ctx->reset_gpio); ++ if (err != -EPROBE_DEFER) ++ dev_err(dev, "failed to request GPIO (%d)\n", err); ++ return err; ++ } ++ ++ ctx->backlight = devm_of_find_backlight(dev); ++ if (IS_ERR(ctx->backlight)) ++ return PTR_ERR(ctx->backlight); ++ ++ err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); ++ if (err) { ++ dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); ++ return err; ++ } ++ ++ drm_panel_init(&ctx->panel, dev, &cwd686_drm_funcs, DRM_MODE_CONNECTOR_DSI); ++ ++ drm_panel_add(&ctx->panel); ++ ++ err = mipi_dsi_attach(dsi); ++ if (err < 0) { ++ dev_err(dev, "mipi_dsi_attach() failed: %d\n", err); ++ drm_panel_remove(&ctx->panel); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void cwd686_remove(struct mipi_dsi_device *dsi) ++{ ++ struct cwd686 *ctx = mipi_dsi_get_drvdata(dsi); ++ ++ mipi_dsi_detach(dsi); ++ drm_panel_remove(&ctx->panel); ++} ++ ++static const struct of_device_id cwd686_of_match[] = { ++ { .compatible = "clockwork,cwd686" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, cwd686_of_match); ++ ++static struct mipi_dsi_driver cwd686_driver = { ++ .probe = cwd686_probe, ++ .remove = cwd686_remove, ++ .driver = { ++ .name = "panel-clockwork-cwd686", ++ .of_match_table = cwd686_of_match, ++ }, ++}; ++module_mipi_dsi_driver(cwd686_driver); ++ ++MODULE_AUTHOR("Pinfan Zhu <zhu@clockworkpi.com>"); ++MODULE_AUTHOR("Max Fierke <max@maxfierke.com>"); ++MODULE_DESCRIPTION("ClockworkPi CWD686 panel driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/d1/patches-6.1/0108-drm-panel-cwd686-Add-regulators.patch b/target/linux/d1/patches-6.1/0108-drm-panel-cwd686-Add-regulators.patch new file mode 100644 index 0000000000..60b21168b5 --- /dev/null +++ b/target/linux/d1/patches-6.1/0108-drm-panel-cwd686-Add-regulators.patch @@ -0,0 +1,66 @@ +From 979271f803c1578087a965a2a4b845c87e7d922f Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 19:14:21 -0500 +Subject: [PATCH 108/117] drm: panel: cwd686: Add regulators + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../gpu/drm/panel/panel-clockwork-cwd686.c | 26 ++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -20,7 +20,8 @@ + struct cwd686 { + struct device *dev; + struct drm_panel panel; +- struct regulator *supply; ++ struct regulator *iovcc; ++ struct regulator *vci; + struct gpio_desc *enable_gpio; + struct gpio_desc *reset_gpio; + struct backlight_device *backlight; +@@ -279,6 +280,9 @@ static int cwd686_unprepare(struct drm_p + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + ++ regulator_disable(ctx->vci); ++ regulator_disable(ctx->iovcc); ++ + ctx->prepared = false; + + return 0; +@@ -293,6 +297,18 @@ static int cwd686_prepare(struct drm_pan + if (ctx->prepared) + return 0; + ++ err = regulator_enable(ctx->iovcc); ++ if (err) { ++ dev_err(ctx->dev, "failed to enable iovcc (%d)\n", err); ++ return err; ++ } ++ ++ err = regulator_enable(ctx->vci); ++ if (err) { ++ dev_err(ctx->dev, "failed to enable vci (%d)\n", err); ++ return err; ++ } ++ + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + /* T2 */ + msleep(10); +@@ -402,6 +418,14 @@ static int cwd686_probe(struct mipi_dsi_ + return err; + } + ++ ctx->iovcc = devm_regulator_get(dev, "iovcc"); ++ if (IS_ERR(ctx->iovcc)) ++ return PTR_ERR(ctx->iovcc); ++ ++ ctx->vci = devm_regulator_get(dev, "vci"); ++ if (IS_ERR(ctx->vci)) ++ return PTR_ERR(ctx->vci); ++ + ctx->backlight = devm_of_find_backlight(dev); + if (IS_ERR(ctx->backlight)) + return PTR_ERR(ctx->backlight); diff --git a/target/linux/d1/patches-6.1/0109-drm-panel-cwd686-Make-reset-gpio-mandatory.patch b/target/linux/d1/patches-6.1/0109-drm-panel-cwd686-Make-reset-gpio-mandatory.patch new file mode 100644 index 0000000000..786273bcfd --- /dev/null +++ b/target/linux/d1/patches-6.1/0109-drm-panel-cwd686-Make-reset-gpio-mandatory.patch @@ -0,0 +1,21 @@ +From 6112585994a6bdbd882709e7187c8c9289211b3b Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 19:16:03 -0500 +Subject: [PATCH 109/117] drm: panel: cwd686: Make reset gpio mandatory + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -410,7 +410,7 @@ static int cwd686_probe(struct mipi_dsi_ + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + +- ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); ++ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) { + err = PTR_ERR(ctx->reset_gpio); + if (err != -EPROBE_DEFER) diff --git a/target/linux/d1/patches-6.1/0110-drm-panel-cwd686-Increase-post-reset-delay.patch b/target/linux/d1/patches-6.1/0110-drm-panel-cwd686-Increase-post-reset-delay.patch new file mode 100644 index 0000000000..6551348a4f --- /dev/null +++ b/target/linux/d1/patches-6.1/0110-drm-panel-cwd686-Increase-post-reset-delay.patch @@ -0,0 +1,21 @@ +From 8d70f9f4a66522c2720de986623d1130337ff670 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 19:16:18 -0500 +Subject: [PATCH 110/117] drm: panel: cwd686: Increase post-reset delay + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -315,7 +315,7 @@ static int cwd686_prepare(struct drm_pan + + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + /* T3 */ +- msleep(20); ++ msleep(120); + + /* Exit sleep mode and power on */ + diff --git a/target/linux/d1/patches-6.1/0111-drm-panel-cwd686-Use-vendor-panel-init-sequence.patch b/target/linux/d1/patches-6.1/0111-drm-panel-cwd686-Use-vendor-panel-init-sequence.patch new file mode 100644 index 0000000000..df68d18557 --- /dev/null +++ b/target/linux/d1/patches-6.1/0111-drm-panel-cwd686-Use-vendor-panel-init-sequence.patch @@ -0,0 +1,171 @@ +From 8fc2a02d1d2e98a01a2dad3bf3da8e33366725eb Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 19:17:35 -0500 +Subject: [PATCH 111/117] drm: panel: cwd686: Use vendor panel init sequence + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../gpu/drm/panel/panel-clockwork-cwd686.c | 142 ++++-------------- + 1 file changed, 32 insertions(+), 110 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -47,10 +47,12 @@ static inline struct cwd686 *panel_to_cw + return container_of(panel, struct cwd686, panel); + } + +-#define ICNL9707_DCS(seq...) \ ++#define dcs_write_seq(seq...) \ + ({ \ + static const u8 d[] = { seq }; \ +- mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ ++ ssize_t r = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ ++ if (r < 0) \ ++ return r; \ + }) + + #define ICNL9707_CMD_CGOUTL 0xB3 +@@ -128,115 +130,35 @@ static inline struct cwd686 *panel_to_cw + static int cwd686_init_sequence(struct cwd686 *ctx) + { + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); +- int err; + +- /* Enable access to Level 2 registers */ +- ICNL9707_DCS(ICNL9707_CMD_PASSWORD1, +- ICNL9707_P_PASSWORD1_ENABLE_LVL2, +- ICNL9707_P_PASSWORD1_ENABLE_LVL2); +- ICNL9707_DCS(ICNL9707_CMD_PASSWORD2, +- ICNL9707_P_PASSWORD2_ENABLE_LVL2, +- ICNL9707_P_PASSWORD2_ENABLE_LVL2); +- +- /* Set PWRCON_VCOM (-0.495V, -0.495V) */ +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_VCOM, +- ICNL9707_P_PWRCON_VCOM_0495V, +- ICNL9707_P_PWRCON_VCOM_0495V); +- +- /* Map ASG output signals */ +- ICNL9707_DCS(ICNL9707_CMD_CGOUTR, +- ICNL9707_P_CGOUT_GSP7, ICNL9707_P_CGOUT_GSP5, +- ICNL9707_P_CGOUT_GCK7, ICNL9707_P_CGOUT_GCK5, +- ICNL9707_P_CGOUT_GCK3, ICNL9707_P_CGOUT_GCK1, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_VGL, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GSP1, ICNL9707_P_CGOUT_GSP3); +- ICNL9707_DCS(ICNL9707_CMD_CGOUTL, +- ICNL9707_P_CGOUT_GSP8, ICNL9707_P_CGOUT_GSP6, +- ICNL9707_P_CGOUT_GCK8, ICNL9707_P_CGOUT_GCK6, +- ICNL9707_P_CGOUT_GCK4, ICNL9707_P_CGOUT_GCK2, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_VGL, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_VGL, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GND, ICNL9707_P_CGOUT_GND, +- ICNL9707_P_CGOUT_GSP2, ICNL9707_P_CGOUT_GSP4); +- +- /* Undocumented commands provided by the vendor */ +- ICNL9707_DCS(0xB0, 0x54, 0x32, 0x23, 0x45, 0x44, 0x44, 0x44, 0x44, 0x90, 0x01, 0x90, 0x01); +- ICNL9707_DCS(0xB1, 0x32, 0x84, 0x02, 0x83, 0x30, 0x01, 0x6B, 0x01); +- ICNL9707_DCS(0xB2, 0x73); +- +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_REG, +- 0x4E, 0x0E, 0x50, 0x50, 0x26, +- 0x1D, 0x00, 0x14, 0x42, 0x03); +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_SEQ, +- 0x01, 0x01, 0x09, 0x11, 0x0D, 0x55, +- 0x19, 0x19, 0x21, 0x1D, 0x00, 0x00, +- 0x00, 0x00, 0x02, 0xFF, 0x3C); +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_CLK, 0x23, 0x01, 0x30, 0x34, 0x63); +- +- /* Disable abnormal power-off flag */ +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_BTA, 0xA0, 0x22, 0x00, 0x44); +- +- ICNL9707_DCS(ICNL9707_CMD_PWRCON_MODE, 0x12, 0x63); +- +- /* Set VBP, VFP, VSW, HBP, HFP, HSW */ +- ICNL9707_DCS(ICNL9707_CMD_TCON, 0x0C, 0x16, 0x04, 0x0C, 0x10, 0x04); +- +- /* Set resolution */ +- ICNL9707_DCS(ICNL9707_CMD_TCON2, 0x11, 0x41); +- +- /* Set frame blanking */ +- ICNL9707_DCS(ICNL9707_CMD_TCON3, 0x22, 0x31, 0x04); +- +- ICNL9707_DCS(ICNL9707_CMD_SRCCON, 0x05, 0x23, 0x6B, 0x49, 0x00); +- +- /* Another undocumented command */ +- ICNL9707_DCS(0xC5, 0x00); +- +- ICNL9707_DCS(ICNL9707_CMD_ETC, 0x37, 0xFF, 0xFF); +- +- /* Another set of undocumented commands */ +- ICNL9707_DCS(0xD2, 0x63, 0x0B, 0x08, 0x88); +- ICNL9707_DCS(0xD3, 0x01, 0x00, 0x00, 0x01, 0x01, 0x37, 0x25, 0x38, 0x31, 0x06, 0x07); +- +- /* Set Gamma to 2.2 */ +- ICNL9707_DCS(ICNL9707_CMD_SET_GAMMA, +- 0x7C, 0x6A, 0x5D, 0x53, 0x53, 0x45, 0x4B, +- 0x35, 0x4D, 0x4A, 0x49, 0x66, 0x53, 0x57, +- 0x4A, 0x48, 0x3B, 0x2A, 0x06, 0x7C, 0x6A, +- 0x5D, 0x53, 0x53, 0x45, 0x4B, 0x35, 0x4D, +- 0x4A, 0x49, 0x66, 0x53, 0x57, 0x4A, 0x48, +- 0x3B, 0x2A, 0x06); +- +- ICNL9707_DCS(ICNL9707_CMD_SRC_TIM, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00); +- +- /* Another undocumented command */ +- ICNL9707_DCS(0xF4, 0x08, 0x77); +- +- ICNL9707_DCS(MIPI_DCS_SET_ADDRESS_MODE, +- ICNL9707_MADCTL_RGB | ICNL9707_MADCTL_ML | ICNL9707_MADCTL_MH); +- +- /* Enable tearing mode at VBLANK */ +- err = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); +- if (err) { +- dev_err(ctx->dev, "failed to enable vblank TE (%d)\n", err); +- return err; +- } +- +- /* Disable access to Level 2 registers */ +- ICNL9707_DCS(ICNL9707_CMD_PASSWORD2, +- ICNL9707_P_PASSWORD2_DEFAULT, +- ICNL9707_P_PASSWORD2_DEFAULT); +- ICNL9707_DCS(ICNL9707_CMD_PASSWORD1, +- ICNL9707_P_PASSWORD1_DEFAULT, +- ICNL9707_P_PASSWORD1_DEFAULT); ++ dcs_write_seq(0xF0,0x5A,0x5A); ++ dcs_write_seq(0xF1,0xA5,0xA5); ++ dcs_write_seq(0xB6,0x0D,0x0D); ++ dcs_write_seq(0xB4,0x0A,0x08,0x12,0x10,0x0E,0x0C,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x06); ++ dcs_write_seq(0xB3,0x0B,0x09,0x13,0x11,0x0F,0x0D,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x05,0x07); ++ dcs_write_seq(0xB0,0x54,0x32,0x23,0x45,0x44,0x44,0x44,0x44,0x90,0x01,0x90,0x01); ++ dcs_write_seq(0xB1,0x32,0x84,0x02,0x83,0x30,0x01,0x6B,0x01); ++ dcs_write_seq(0xB2,0x73); ++ dcs_write_seq(0xBD,0x4E,0x0E,0x50,0x50,0x26,0x1D,0x00,0x14,0x42,0x03); ++ dcs_write_seq(0xB7,0x01,0x01,0x09,0x11,0x0D,0x55,0x19,0x19,0x21,0x1D,0x00,0x00,0x00,0x00,0x02,0xFF,0x3C); ++ dcs_write_seq(0xB8,0x23,0x01,0x30,0x34,0x63); ++ dcs_write_seq(0xB9,0xA0,0x22,0x00,0x44); ++ dcs_write_seq(0xBA,0x12,0x63); ++ dcs_write_seq(0xC1,0x0C,0x16,0x04,0x0C,0x10,0x04); ++ dcs_write_seq(0xC2,0x11,0x41); ++ dcs_write_seq(0xC3,0x22,0x31,0x04); ++ dcs_write_seq(0xC7,0x05,0x23,0x6B,0x49,0x00); ++ dcs_write_seq(0xC5,0x00); ++ dcs_write_seq(0xD0,0x37,0xFF,0xFF); ++ dcs_write_seq(0xD2,0x63,0x0B,0x08,0x88); ++ dcs_write_seq(0xD3,0x01,0x00,0x00,0x01,0x01,0x37,0x25,0x38,0x31,0x06,0x07); ++ dcs_write_seq(0xC8,0x7C,0x6A,0x5D,0x53,0x53,0x45,0x4B,0x35,0x4D,0x4A,0x49,0x66,0x53,0x57,0x4A,0x48,0x3B,0x2A,0x06,0x7C,0x6A,0x5D,0x53,0x53,0x45,0x4B,0x35,0x4D,0x4A,0x49,0x66,0x53,0x57,0x4A,0x48,0x3B,0x2A,0x06);//GAMMA2.2 ++ dcs_write_seq(0xC6,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00); ++ dcs_write_seq(0xF4,0x08,0x77); ++ dcs_write_seq(0x36,0x14); ++ dcs_write_seq(0x35,0x00); ++ dcs_write_seq(0xF1,0x5A,0x5A); ++ dcs_write_seq(0xF0,0xA5,0xA5); + + return 0; + } diff --git a/target/linux/d1/patches-6.1/0112-drm-panel-cwd686-Fix-timings.patch b/target/linux/d1/patches-6.1/0112-drm-panel-cwd686-Fix-timings.patch new file mode 100644 index 0000000000..08c0f59eed --- /dev/null +++ b/target/linux/d1/patches-6.1/0112-drm-panel-cwd686-Fix-timings.patch @@ -0,0 +1,37 @@ +From 6ea428297717faa16056076f7dd5a69e49c58fe6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Sun, 7 Aug 2022 23:34:35 -0500 +Subject: [PATCH 112/117] drm: panel: cwd686: Fix timings + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -31,15 +31,15 @@ struct cwd686 { + }; + + static const struct drm_display_mode default_mode = { +- .clock = 54465, +- .hdisplay = 480, +- .hsync_start = 480 + 150, +- .hsync_end = 480 + 150 + 24, +- .htotal = 480 + 150 + 24 + 40, +- .vdisplay = 1280, +- .vsync_start = 1280 + 12, +- .vsync_end = 1280 + 12 + 6, +- .vtotal = 1280 + 12 + 6 + 10, ++ .clock = 54465, ++ .hdisplay = 480, ++ .hsync_start = 480 + 64, ++ .hsync_end = 480 + 64 + 40, ++ .htotal = 480 + 64 + 40 + 110, ++ .vdisplay = 1280, ++ .vsync_start = 1280 + 16, ++ .vsync_end = 1280 + 16 + 10, ++ .vtotal = 1280 + 16 + 10 + 2, + }; + + static inline struct cwd686 *panel_to_cwd686(struct drm_panel *panel) diff --git a/target/linux/d1/patches-6.1/0113-drm-panel-cwd686-Disable-burst.patch b/target/linux/d1/patches-6.1/0113-drm-panel-cwd686-Disable-burst.patch new file mode 100644 index 0000000000..5e732945a9 --- /dev/null +++ b/target/linux/d1/patches-6.1/0113-drm-panel-cwd686-Disable-burst.patch @@ -0,0 +1,20 @@ +From 16359ba0c5f5011e4742672454b35ad91a02fabe Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Mon, 8 Aug 2022 00:30:17 -0500 +Subject: [PATCH 113/117] drm: panel: cwd686: Disable burst + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -329,7 +329,6 @@ static int cwd686_probe(struct mipi_dsi_ + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | +- MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); diff --git a/target/linux/d1/patches-6.1/0114-drm-panel-cwd686-Use-the-init-sequence-from-the-R-01.patch b/target/linux/d1/patches-6.1/0114-drm-panel-cwd686-Use-the-init-sequence-from-the-R-01.patch new file mode 100644 index 0000000000..334f75c68b --- /dev/null +++ b/target/linux/d1/patches-6.1/0114-drm-panel-cwd686-Use-the-init-sequence-from-the-R-01.patch @@ -0,0 +1,67 @@ +From 02da00f2215f3d755ec806636fe499331870e8d6 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 9 Aug 2022 20:14:59 -0500 +Subject: [PATCH 114/117] drm: panel: cwd686: Use the init sequence from the + R-01 BSP + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + .../gpu/drm/panel/panel-clockwork-cwd686.c | 44 ++++++++----------- + 1 file changed, 19 insertions(+), 25 deletions(-) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -131,34 +131,28 @@ static int cwd686_init_sequence(struct c + { + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + +- dcs_write_seq(0xF0,0x5A,0x5A); +- dcs_write_seq(0xF1,0xA5,0xA5); +- dcs_write_seq(0xB6,0x0D,0x0D); +- dcs_write_seq(0xB4,0x0A,0x08,0x12,0x10,0x0E,0x0C,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x06); +- dcs_write_seq(0xB3,0x0B,0x09,0x13,0x11,0x0F,0x0D,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x05,0x07); +- dcs_write_seq(0xB0,0x54,0x32,0x23,0x45,0x44,0x44,0x44,0x44,0x90,0x01,0x90,0x01); +- dcs_write_seq(0xB1,0x32,0x84,0x02,0x83,0x30,0x01,0x6B,0x01); ++ dcs_write_seq(0xF0,0x5A,0x59); ++ dcs_write_seq(0xF1,0xA5,0xA6); ++ dcs_write_seq(0xB0,0x54,0x32,0x23,0x45,0x44,0x44,0x44,0x44,0x9F,0x00,0x01,0x9F,0x00,0x01); ++ dcs_write_seq(0xB1,0x32,0x84,0x02,0x83,0x29,0x06,0x06,0x72,0x06,0x06); + dcs_write_seq(0xB2,0x73); +- dcs_write_seq(0xBD,0x4E,0x0E,0x50,0x50,0x26,0x1D,0x00,0x14,0x42,0x03); +- dcs_write_seq(0xB7,0x01,0x01,0x09,0x11,0x0D,0x55,0x19,0x19,0x21,0x1D,0x00,0x00,0x00,0x00,0x02,0xFF,0x3C); +- dcs_write_seq(0xB8,0x23,0x01,0x30,0x34,0x63); +- dcs_write_seq(0xB9,0xA0,0x22,0x00,0x44); +- dcs_write_seq(0xBA,0x12,0x63); +- dcs_write_seq(0xC1,0x0C,0x16,0x04,0x0C,0x10,0x04); +- dcs_write_seq(0xC2,0x11,0x41); +- dcs_write_seq(0xC3,0x22,0x31,0x04); +- dcs_write_seq(0xC7,0x05,0x23,0x6B,0x49,0x00); +- dcs_write_seq(0xC5,0x00); +- dcs_write_seq(0xD0,0x37,0xFF,0xFF); +- dcs_write_seq(0xD2,0x63,0x0B,0x08,0x88); +- dcs_write_seq(0xD3,0x01,0x00,0x00,0x01,0x01,0x37,0x25,0x38,0x31,0x06,0x07); +- dcs_write_seq(0xC8,0x7C,0x6A,0x5D,0x53,0x53,0x45,0x4B,0x35,0x4D,0x4A,0x49,0x66,0x53,0x57,0x4A,0x48,0x3B,0x2A,0x06,0x7C,0x6A,0x5D,0x53,0x53,0x45,0x4B,0x35,0x4D,0x4A,0x49,0x66,0x53,0x57,0x4A,0x48,0x3B,0x2A,0x06);//GAMMA2.2 +- dcs_write_seq(0xC6,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00); +- dcs_write_seq(0xF4,0x08,0x77); ++ dcs_write_seq(0xB3,0x0B,0x09,0x13,0x11,0x0F,0x0D,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x05,0x07); ++ dcs_write_seq(0xB4,0x0A,0x08,0x12,0x10,0x0E,0x0C,0x00,0x00,0x00,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x06); ++ dcs_write_seq(0xB6,0x13,0x13); ++ dcs_write_seq(0xB8,0xB4,0x43,0x02,0xCC); ++ dcs_write_seq(0xB9,0xA5,0x20,0xFF,0xC8); ++ dcs_write_seq(0xBA,0x88,0x23); ++ dcs_write_seq(0xBD,0x43,0x0E,0x0E,0x50,0x50,0x29,0x10,0x03,0x44,0x03); ++ dcs_write_seq(0xC1,0x00,0x0C,0x16,0x04,0x00,0x30,0x10,0x04); ++ dcs_write_seq(0xC2,0x21,0x81); ++ dcs_write_seq(0xC3,0x02,0x30); ++ dcs_write_seq(0xC7,0x25,0x6A); ++ dcs_write_seq(0xC8,0x7C,0x68,0x59,0x4E,0x4B,0x3C,0x41,0x2B,0x44,0x43,0x43,0x60,0x4E,0x55,0x47,0x44,0x38,0x27,0x06,0x7C,0x68,0x59,0x4E,0x4B,0x3C,0x41,0x2B,0x44,0x43,0x43,0x60,0x4E,0x55,0x47,0x44,0x38,0x27,0x06); ++ dcs_write_seq(0xD4,0x00,0x00,0x00,0x32,0x04,0x51); ++ dcs_write_seq(0xF1,0x5A,0x59); ++ dcs_write_seq(0xF0,0xA5,0xA6); + dcs_write_seq(0x36,0x14); + dcs_write_seq(0x35,0x00); +- dcs_write_seq(0xF1,0x5A,0x5A); +- dcs_write_seq(0xF0,0xA5,0xA5); + + return 0; + } diff --git a/target/linux/d1/patches-6.1/0115-drm-panel-cwd686-Power-up-sequence.patch b/target/linux/d1/patches-6.1/0115-drm-panel-cwd686-Power-up-sequence.patch new file mode 100644 index 0000000000..149e42d0cc --- /dev/null +++ b/target/linux/d1/patches-6.1/0115-drm-panel-cwd686-Power-up-sequence.patch @@ -0,0 +1,27 @@ +From 6b438292e6b86a5cb5bffee2e517f1335903e39e Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 9 Aug 2022 20:15:24 -0500 +Subject: [PATCH 115/117] drm: panel: cwd686: Power up sequence + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -218,12 +218,14 @@ static int cwd686_prepare(struct drm_pan + dev_err(ctx->dev, "failed to enable iovcc (%d)\n", err); + return err; + } ++ msleep(20); + + err = regulator_enable(ctx->vci); + if (err) { + dev_err(ctx->dev, "failed to enable vci (%d)\n", err); + return err; + } ++ msleep(120); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + /* T2 */ diff --git a/target/linux/d1/patches-6.1/0116-drm-panel-cwd686-Why-is-this-not-getting-called.patch b/target/linux/d1/patches-6.1/0116-drm-panel-cwd686-Why-is-this-not-getting-called.patch new file mode 100644 index 0000000000..b46a58752a --- /dev/null +++ b/target/linux/d1/patches-6.1/0116-drm-panel-cwd686-Why-is-this-not-getting-called.patch @@ -0,0 +1,21 @@ +From a19565eccfdc0fce7f41cfe70cd67a1a10d2113c Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Tue, 9 Aug 2022 20:15:39 -0500 +Subject: [PATCH 116/117] drm: panel: cwd686: Why is this not getting called? + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + drivers/gpu/drm/panel/panel-clockwork-cwd686.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/panel/panel-clockwork-cwd686.c ++++ b/drivers/gpu/drm/panel/panel-clockwork-cwd686.c +@@ -373,6 +373,8 @@ static void cwd686_remove(struct mipi_ds + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); ++ if (ctx->prepared) ++ cwd686_unprepare(&ctx->panel); + } + + static const struct of_device_id cwd686_of_match[] = { diff --git a/target/linux/d1/patches-6.1/0117-riscv-dts-allwinner-d1-Add-video-engine-node.patch b/target/linux/d1/patches-6.1/0117-riscv-dts-allwinner-d1-Add-video-engine-node.patch new file mode 100644 index 0000000000..fd25a0af48 --- /dev/null +++ b/target/linux/d1/patches-6.1/0117-riscv-dts-allwinner-d1-Add-video-engine-node.patch @@ -0,0 +1,56 @@ +From d6036571b774437bb3bdd378821033e118a01fe8 Mon Sep 17 00:00:00 2001 +From: Samuel Holland <samuel@sholland.org> +Date: Wed, 2 Nov 2022 23:42:52 -0500 +Subject: [PATCH 117/117] riscv: dts: allwinner: d1: Add video engine node + +Signed-off-by: Samuel Holland <samuel@sholland.org> +--- + arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi | 30 ++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi ++++ b/arch/riscv/boot/dts/allwinner/sun20i-d1.dtsi +@@ -105,6 +105,21 @@ + status = "reserved"; + }; + ++ ve: video-codec@1c0e000 { ++ compatible = "allwinner,sun20i-d1-video-engine"; ++ reg = <0x1c0e000 0x2000>; ++ interrupts = <82 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&ccu CLK_BUS_VE>, ++ <&ccu CLK_VE>, ++ <&ccu CLK_MBUS_VE>; ++ clock-names = "ahb", "mod", "ram"; ++ resets = <&ccu RST_BUS_VE>; ++ allwinner,sram = <&ve_sram 1>; ++ interconnects = <&mbus 4>; ++ interconnect-names = "dma-mem"; ++ iommus = <&iommu 0>; ++ }; ++ + pio: pinctrl@2000000 { + compatible = "allwinner,sun20i-d1-pinctrl"; + reg = <0x2000000 0x800>; +@@ -591,6 +606,21 @@ + #address-cells = <1>; + #size-cells = <1>; + ++ // FIXME: Address is not verified. It is copied from A64/H6. ++ sram@1d00000 { ++ compatible = "mmio-sram"; ++ reg = <0x1d00000 0x40000>; ++ ranges = <0 0x1d00000 0x40000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ve_sram: sram-section@0 { ++ compatible = "allwinner,sun20i-d1-sram-c1", ++ "allwinner,sun4i-a10-sram-c1"; ++ reg = <0 0x40000>; ++ }; ++ }; ++ + regulators@3000150 { + compatible = "allwinner,sun20i-d1-system-ldos"; + reg = <0x3000150 0x4>; |