apm821xx: add linux 4.19 apm821xx patches
This patch updates the apm821xx target to use the 4.19 kernel. 4.19 ships with all the crypto4xx driver patches. Furthermore, the DW-DMA fix for the SATA controller has been backported from 4.20 and integrated. Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
This commit is contained in:
		
							
								
								
									
										337
									
								
								target/linux/apm821xx/config-4.19
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										337
									
								
								target/linux/apm821xx/config-4.19
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,337 @@ | |||||||
|  | # CONFIG_40x is not set | ||||||
|  | CONFIG_44x=y | ||||||
|  | CONFIG_460EX=y | ||||||
|  | CONFIG_4xx=y | ||||||
|  | CONFIG_4xx_SOC=y | ||||||
|  | # CONFIG_ADVANCED_OPTIONS is not set | ||||||
|  | CONFIG_APM821xx=y | ||||||
|  | CONFIG_APOLLO3G=y | ||||||
|  | # CONFIG_ARCHES is not set | ||||||
|  | CONFIG_ARCH_DMA_ADDR_T_64BIT=y | ||||||
|  | CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y | ||||||
|  | CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y | ||||||
|  | CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK=y | ||||||
|  | CONFIG_ARCH_HAS_ELF_RANDOMIZE=y | ||||||
|  | CONFIG_ARCH_HAS_FORTIFY_SOURCE=y | ||||||
|  | CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y | ||||||
|  | CONFIG_ARCH_HAS_MEMBARRIER_CALLBACKS=y | ||||||
|  | CONFIG_ARCH_HAS_PHYS_TO_DMA=y | ||||||
|  | CONFIG_ARCH_HAS_PTE_SPECIAL=y | ||||||
|  | CONFIG_ARCH_HAS_SG_CHAIN=y | ||||||
|  | CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y | ||||||
|  | CONFIG_ARCH_HAS_WALK_MEMORY=y | ||||||
|  | CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y | ||||||
|  | CONFIG_ARCH_HIBERNATION_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_MAY_HAVE_PC_FDC=y | ||||||
|  | CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y | ||||||
|  | CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y | ||||||
|  | CONFIG_ARCH_MMAP_RND_BITS=11 | ||||||
|  | CONFIG_ARCH_MMAP_RND_BITS_MAX=17 | ||||||
|  | CONFIG_ARCH_MMAP_RND_BITS_MIN=11 | ||||||
|  | CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17 | ||||||
|  | CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 | ||||||
|  | CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y | ||||||
|  | CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y | ||||||
|  | CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y | ||||||
|  | CONFIG_ARCH_SUPPORTS_UPROBES=y | ||||||
|  | CONFIG_ARCH_SUSPEND_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_USE_BUILTIN_BSWAP=y | ||||||
|  | CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y | ||||||
|  | CONFIG_ARCH_WEAK_RELEASE_ACQUIRE=y | ||||||
|  | CONFIG_AUDIT_ARCH=y | ||||||
|  | # CONFIG_BAMBOO is not set | ||||||
|  | CONFIG_BCH=y | ||||||
|  | # CONFIG_BLK_DEV_INITRD is not set | ||||||
|  | CONFIG_BLK_MQ_PCI=y | ||||||
|  | CONFIG_BLUESTONE=y | ||||||
|  | CONFIG_BOOKE=y | ||||||
|  | CONFIG_BOOKE_WDT=y | ||||||
|  | # CONFIG_BOUNCE is not set | ||||||
|  | CONFIG_BUILD_SALT="" | ||||||
|  | # CONFIG_CANYONLANDS is not set | ||||||
|  | CONFIG_CC_HAS_SANCOV_TRACE_PC=y | ||||||
|  | CONFIG_CC_HAS_STACKPROTECTOR_NONE=y | ||||||
|  | CONFIG_CC_IS_GCC=y | ||||||
|  | CONFIG_CLANG_VERSION=0 | ||||||
|  | CONFIG_CLONE_BACKWARDS=y | ||||||
|  | CONFIG_CMDLINE="rootfstype=squashfs noinitrd" | ||||||
|  | CONFIG_CMDLINE_BOOL=y | ||||||
|  | CONFIG_CONSISTENT_SIZE=0x00200000 | ||||||
|  | CONFIG_CONSOLE_LOGLEVEL_QUIET=4 | ||||||
|  | CONFIG_CPU_BIG_ENDIAN=y | ||||||
|  | CONFIG_CRC16=y | ||||||
|  | CONFIG_CRYPTO_ACOMP2=y | ||||||
|  | CONFIG_CRYPTO_AEAD=y | ||||||
|  | CONFIG_CRYPTO_AEAD2=y | ||||||
|  | CONFIG_CRYPTO_AKCIPHER2=y | ||||||
|  | CONFIG_CRYPTO_CCM=y | ||||||
|  | CONFIG_CRYPTO_CFB=y | ||||||
|  | CONFIG_CRYPTO_CTR=y | ||||||
|  | CONFIG_CRYPTO_DEFLATE=y | ||||||
|  | CONFIG_CRYPTO_DEV_PPC4XX=y | ||||||
|  | CONFIG_CRYPTO_DRBG=y | ||||||
|  | CONFIG_CRYPTO_DRBG_HMAC=y | ||||||
|  | CONFIG_CRYPTO_DRBG_MENU=y | ||||||
|  | CONFIG_CRYPTO_ECB=y | ||||||
|  | CONFIG_CRYPTO_GCM=y | ||||||
|  | CONFIG_CRYPTO_GF128MUL=y | ||||||
|  | CONFIG_CRYPTO_GHASH=y | ||||||
|  | CONFIG_CRYPTO_HASH=y | ||||||
|  | CONFIG_CRYPTO_HASH2=y | ||||||
|  | CONFIG_CRYPTO_HMAC=y | ||||||
|  | CONFIG_CRYPTO_HW=y | ||||||
|  | CONFIG_CRYPTO_JITTERENTROPY=y | ||||||
|  | CONFIG_CRYPTO_KPP2=y | ||||||
|  | CONFIG_CRYPTO_LZO=y | ||||||
|  | CONFIG_CRYPTO_MANAGER=y | ||||||
|  | CONFIG_CRYPTO_MANAGER2=y | ||||||
|  | CONFIG_CRYPTO_MD5_PPC=y | ||||||
|  | CONFIG_CRYPTO_NULL=y | ||||||
|  | CONFIG_CRYPTO_NULL2=y | ||||||
|  | CONFIG_CRYPTO_RNG=y | ||||||
|  | CONFIG_CRYPTO_RNG2=y | ||||||
|  | CONFIG_CRYPTO_RNG_DEFAULT=y | ||||||
|  | CONFIG_CRYPTO_SEQIV=y | ||||||
|  | CONFIG_CRYPTO_SHA1_PPC=y | ||||||
|  | CONFIG_CRYPTO_SHA256=y | ||||||
|  | CONFIG_CRYPTO_WORKQUEUE=y | ||||||
|  | CONFIG_DECOMPRESS_GZIP=y | ||||||
|  | CONFIG_DTC=y | ||||||
|  | # CONFIG_E200 is not set | ||||||
|  | CONFIG_EARLY_PRINTK=y | ||||||
|  | # CONFIG_EBONY is not set | ||||||
|  | CONFIG_EDAC_ATOMIC_SCRUB=y | ||||||
|  | CONFIG_EDAC_SUPPORT=y | ||||||
|  | # CONFIG_EIGER is not set | ||||||
|  | CONFIG_EXTRA_TARGETS="uImage" | ||||||
|  | CONFIG_FIXED_PHY=y | ||||||
|  | CONFIG_FREEZER=y | ||||||
|  | # CONFIG_FSL_LBC is not set | ||||||
|  | CONFIG_GCC_VERSION=70300 | ||||||
|  | CONFIG_GENERIC_ATOMIC64=y | ||||||
|  | CONFIG_GENERIC_BUG=y | ||||||
|  | CONFIG_GENERIC_CLOCKEVENTS=y | ||||||
|  | CONFIG_GENERIC_CMOS_UPDATE=y | ||||||
|  | CONFIG_GENERIC_CPU=y | ||||||
|  | CONFIG_GENERIC_CPU_AUTOPROBE=y | ||||||
|  | CONFIG_GENERIC_IRQ_SHOW=y | ||||||
|  | CONFIG_GENERIC_IRQ_SHOW_LEVEL=y | ||||||
|  | CONFIG_GENERIC_ISA_DMA=y | ||||||
|  | CONFIG_GENERIC_MSI_IRQ=y | ||||||
|  | CONFIG_GENERIC_NVRAM=y | ||||||
|  | CONFIG_GENERIC_PCI_IOMAP=y | ||||||
|  | CONFIG_GENERIC_SMP_IDLE_THREAD=y | ||||||
|  | CONFIG_GENERIC_STRNCPY_FROM_USER=y | ||||||
|  | CONFIG_GENERIC_STRNLEN_USER=y | ||||||
|  | CONFIG_GENERIC_TIME_VSYSCALL=y | ||||||
|  | # CONFIG_GEN_RTC is not set | ||||||
|  | # CONFIG_GLACIER is not set | ||||||
|  | CONFIG_GPIOLIB=y | ||||||
|  | CONFIG_GPIOLIB_FASTPATH_LIMIT=512 | ||||||
|  | CONFIG_GPIO_GENERIC=y | ||||||
|  | CONFIG_GPIO_GENERIC_PLATFORM=y | ||||||
|  | CONFIG_GPIO_SYSFS=y | ||||||
|  | CONFIG_HAS_DMA=y | ||||||
|  | CONFIG_HAS_IOMEM=y | ||||||
|  | CONFIG_HAS_IOPORT_MAP=y | ||||||
|  | CONFIG_HAVE_ARCH_AUDITSYSCALL=y | ||||||
|  | CONFIG_HAVE_ARCH_JUMP_LABEL=y | ||||||
|  | CONFIG_HAVE_ARCH_KGDB=y | ||||||
|  | CONFIG_HAVE_ARCH_SECCOMP_FILTER=y | ||||||
|  | CONFIG_HAVE_ARCH_TRACEHOOK=y | ||||||
|  | CONFIG_HAVE_CBPF_JIT=y | ||||||
|  | CONFIG_HAVE_DEBUG_KMEMLEAK=y | ||||||
|  | CONFIG_HAVE_DEBUG_STACKOVERFLOW=y | ||||||
|  | CONFIG_HAVE_DYNAMIC_FTRACE=y | ||||||
|  | CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y | ||||||
|  | CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y | ||||||
|  | CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y | ||||||
|  | CONFIG_HAVE_FUNCTION_TRACER=y | ||||||
|  | CONFIG_HAVE_GENERIC_GUP=y | ||||||
|  | CONFIG_HAVE_IDE=y | ||||||
|  | CONFIG_HAVE_IOREMAP_PROT=y | ||||||
|  | CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y | ||||||
|  | CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y | ||||||
|  | CONFIG_HAVE_KPROBES_ON_FTRACE=y | ||||||
|  | CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y | ||||||
|  | CONFIG_HAVE_MEMBLOCK=y | ||||||
|  | CONFIG_HAVE_MEMBLOCK_NODE_MAP=y | ||||||
|  | CONFIG_HAVE_MOD_ARCH_SPECIFIC=y | ||||||
|  | CONFIG_HAVE_NET_DSA=y | ||||||
|  | CONFIG_HAVE_OPROFILE=y | ||||||
|  | CONFIG_HAVE_PERF_EVENTS=y | ||||||
|  | CONFIG_HAVE_PERF_REGS=y | ||||||
|  | CONFIG_HAVE_PERF_USER_STACK_DUMP=y | ||||||
|  | CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y | ||||||
|  | CONFIG_HAVE_RSEQ=y | ||||||
|  | CONFIG_HAVE_SYSCALL_TRACEPOINTS=y | ||||||
|  | CONFIG_HAVE_VIRT_CPU_ACCOUNTING=y | ||||||
|  | CONFIG_HW_RANDOM=y | ||||||
|  | CONFIG_HW_RANDOM_PPC4XX=y | ||||||
|  | CONFIG_HZ=1000 | ||||||
|  | # CONFIG_HZ_100 is not set | ||||||
|  | CONFIG_HZ_1000=y | ||||||
|  | CONFIG_HZ_PERIODIC=y | ||||||
|  | CONFIG_I2C=y | ||||||
|  | CONFIG_I2C_BOARDINFO=y | ||||||
|  | CONFIG_I2C_CHARDEV=y | ||||||
|  | CONFIG_I2C_IBM_IIC=y | ||||||
|  | CONFIG_IBM_EMAC=y | ||||||
|  | CONFIG_IBM_EMAC_EMAC4=y | ||||||
|  | CONFIG_IBM_EMAC_POLL_WEIGHT=32 | ||||||
|  | CONFIG_IBM_EMAC_RGMII=y | ||||||
|  | CONFIG_IBM_EMAC_RXB=128 | ||||||
|  | CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256 | ||||||
|  | CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0 | ||||||
|  | CONFIG_IBM_EMAC_TAH=y | ||||||
|  | CONFIG_IBM_EMAC_TXB=128 | ||||||
|  | # CONFIG_ICE is not set | ||||||
|  | # CONFIG_ICON is not set | ||||||
|  | CONFIG_ILLEGAL_POINTER_VALUE=0 | ||||||
|  | CONFIG_INITRAMFS_SOURCE="" | ||||||
|  | CONFIG_IRQCHIP=y | ||||||
|  | CONFIG_IRQ_DOMAIN=y | ||||||
|  | CONFIG_IRQ_FORCED_THREADING=y | ||||||
|  | CONFIG_IRQ_WORK=y | ||||||
|  | CONFIG_ISA_DMA_API=y | ||||||
|  | # CONFIG_JFFS2_FS is not set | ||||||
|  | # CONFIG_KATMAI is not set | ||||||
|  | CONFIG_KERNEL_GZIP=y | ||||||
|  | CONFIG_KERNEL_START=0xc0000000 | ||||||
|  | CONFIG_LEDS_TRIGGER_MTD=y | ||||||
|  | CONFIG_LIBFDT=y | ||||||
|  | CONFIG_LOCK_DEBUGGING_SUPPORT=y | ||||||
|  | CONFIG_LOWMEM_SIZE=0x30000000 | ||||||
|  | CONFIG_LZO_COMPRESS=y | ||||||
|  | CONFIG_LZO_DECOMPRESS=y | ||||||
|  | # CONFIG_MATH_EMULATION is not set | ||||||
|  | CONFIG_MDIO_BUS=y | ||||||
|  | CONFIG_MDIO_DEVICE=y | ||||||
|  | CONFIG_MEMFD_CREATE=y | ||||||
|  | CONFIG_MODULES_USE_ELF_RELA=y | ||||||
|  | CONFIG_MTD_CFI_ADV_OPTIONS=y | ||||||
|  | # CONFIG_MTD_CFI_GEOMETRY is not set | ||||||
|  | CONFIG_MTD_NAND=y | ||||||
|  | CONFIG_MTD_NAND_BCH=y | ||||||
|  | CONFIG_MTD_NAND_ECC=y | ||||||
|  | CONFIG_MTD_NAND_ECC_BCH=y | ||||||
|  | CONFIG_MTD_NAND_ECC_SMC=y | ||||||
|  | CONFIG_MTD_NAND_NDFC=y | ||||||
|  | # CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set | ||||||
|  | CONFIG_NEED_DMA_MAP_STATE=y | ||||||
|  | CONFIG_NEED_PER_CPU_KM=y | ||||||
|  | CONFIG_NEED_SG_DMA_LENGTH=y | ||||||
|  | # CONFIG_NF_LOG_BRIDGE is not set | ||||||
|  | CONFIG_NOT_COHERENT_CACHE=y | ||||||
|  | CONFIG_NO_BOOTMEM=y | ||||||
|  | CONFIG_NR_IRQS=512 | ||||||
|  | CONFIG_OF=y | ||||||
|  | CONFIG_OF_ADDRESS=y | ||||||
|  | CONFIG_OF_EARLY_FLATTREE=y | ||||||
|  | CONFIG_OF_FLATTREE=y | ||||||
|  | CONFIG_OF_GPIO=y | ||||||
|  | CONFIG_OF_IRQ=y | ||||||
|  | CONFIG_OF_KOBJ=y | ||||||
|  | CONFIG_OF_MDIO=y | ||||||
|  | CONFIG_OF_NET=y | ||||||
|  | CONFIG_OF_RESERVED_MEM=y | ||||||
|  | CONFIG_OLD_SIGACTION=y | ||||||
|  | CONFIG_OLD_SIGSUSPEND=y | ||||||
|  | # CONFIG_OVERLAY_FS_METACOPY is not set | ||||||
|  | CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y | ||||||
|  | # CONFIG_OVERLAY_FS_XINO_AUTO is not set | ||||||
|  | CONFIG_PAGE_OFFSET=0xc0000000 | ||||||
|  | CONFIG_PCI=y | ||||||
|  | CONFIG_PCIEAER=y | ||||||
|  | CONFIG_PCIEPORTBUS=y | ||||||
|  | CONFIG_PCIE_PME=y | ||||||
|  | CONFIG_PCI_DISABLE_COMMON_QUIRKS=y | ||||||
|  | CONFIG_PCI_DOMAINS=y | ||||||
|  | CONFIG_PCI_MSI=y | ||||||
|  | CONFIG_PGTABLE_LEVELS=2 | ||||||
|  | CONFIG_PHYLIB=y | ||||||
|  | CONFIG_PHYSICAL_START=0x00000000 | ||||||
|  | CONFIG_PHYS_64BIT=y | ||||||
|  | CONFIG_PHYS_ADDR_T_64BIT=y | ||||||
|  | CONFIG_PM=y | ||||||
|  | CONFIG_PM_AUTOSLEEP=y | ||||||
|  | # CONFIG_PM_DEBUG is not set | ||||||
|  | CONFIG_PM_SLEEP=y | ||||||
|  | CONFIG_PM_WAKELOCKS=y | ||||||
|  | CONFIG_PM_WAKELOCKS_GC=y | ||||||
|  | CONFIG_PM_WAKELOCKS_LIMIT=100 | ||||||
|  | CONFIG_PPC=y | ||||||
|  | CONFIG_PPC32=y | ||||||
|  | CONFIG_PPC44x_SIMPLE=y | ||||||
|  | CONFIG_PPC4xx_CPM=y | ||||||
|  | CONFIG_PPC4xx_GPIO=y | ||||||
|  | CONFIG_PPC4xx_MSI=y | ||||||
|  | CONFIG_PPC4xx_OCM=y | ||||||
|  | CONFIG_PPC4xx_PCI_EXPRESS=y | ||||||
|  | # CONFIG_PPC64 is not set | ||||||
|  | # CONFIG_PPC_47x is not set | ||||||
|  | # CONFIG_PPC_85xx is not set | ||||||
|  | # CONFIG_PPC_8xx is not set | ||||||
|  | CONFIG_PPC_ADV_DEBUG_DACS=2 | ||||||
|  | CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y | ||||||
|  | CONFIG_PPC_ADV_DEBUG_DVCS=2 | ||||||
|  | CONFIG_PPC_ADV_DEBUG_IACS=4 | ||||||
|  | CONFIG_PPC_ADV_DEBUG_REGS=y | ||||||
|  | # CONFIG_PPC_BOOK3S_32 is not set | ||||||
|  | CONFIG_PPC_DCR=y | ||||||
|  | CONFIG_PPC_DCR_NATIVE=y | ||||||
|  | # CONFIG_PPC_EARLY_DEBUG is not set | ||||||
|  | CONFIG_PPC_FPU=y | ||||||
|  | CONFIG_PPC_INDIRECT_PCI=y | ||||||
|  | # CONFIG_PPC_IRQ_SOFT_MASK_DEBUG is not set | ||||||
|  | CONFIG_PPC_LIB_RHEAP=y | ||||||
|  | CONFIG_PPC_MMU_NOHASH=y | ||||||
|  | CONFIG_PPC_MSI_BITMAP=y | ||||||
|  | CONFIG_PPC_PCI_CHOICE=y | ||||||
|  | # CONFIG_PPC_PTDUMP is not set | ||||||
|  | CONFIG_PPC_UDBG_16550=y | ||||||
|  | CONFIG_PPC_WERROR=y | ||||||
|  | CONFIG_PTE_64BIT=y | ||||||
|  | # CONFIG_RAINIER is not set | ||||||
|  | # CONFIG_RANDOM_TRUST_CPU is not set | ||||||
|  | CONFIG_RAS=y | ||||||
|  | CONFIG_RD_GZIP=y | ||||||
|  | # CONFIG_RENESAS_PHY is not set | ||||||
|  | # CONFIG_RPMSG_VIRTIO is not set | ||||||
|  | CONFIG_RSEQ=y | ||||||
|  | CONFIG_RWSEM_XCHGADD_ALGORITHM=y | ||||||
|  | # CONFIG_SAM440EP is not set | ||||||
|  | # CONFIG_SEQUOIA is not set | ||||||
|  | CONFIG_SERIAL_8250_EXTENDED=y | ||||||
|  | CONFIG_SERIAL_8250_FSL=y | ||||||
|  | CONFIG_SERIAL_8250_SHARE_IRQ=y | ||||||
|  | CONFIG_SERIAL_OF_PLATFORM=y | ||||||
|  | CONFIG_SGL_ALLOC=y | ||||||
|  | CONFIG_SIMPLE_GPIO=y | ||||||
|  | CONFIG_SPARSE_IRQ=y | ||||||
|  | CONFIG_SRCU=y | ||||||
|  | CONFIG_SUSPEND=y | ||||||
|  | CONFIG_SUSPEND_FREEZER=y | ||||||
|  | CONFIG_SWPHY=y | ||||||
|  | CONFIG_SYSCTL_EXCEPTION_TRACE=y | ||||||
|  | # CONFIG_TAISHAN is not set | ||||||
|  | CONFIG_TASK_SIZE=0xc0000000 | ||||||
|  | CONFIG_THREAD_SHIFT=13 | ||||||
|  | CONFIG_TICK_CPU_ACCOUNTING=y | ||||||
|  | CONFIG_TINY_SRCU=y | ||||||
|  | CONFIG_USB_SUPPORT=y | ||||||
|  | CONFIG_VDSO32=y | ||||||
|  | # CONFIG_VIRTIO_MENU is not set | ||||||
|  | # CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set | ||||||
|  | # CONFIG_WARP is not set | ||||||
|  | CONFIG_WATCHDOG_CORE=y | ||||||
|  | # CONFIG_WNDR4700 is not set | ||||||
|  | # CONFIG_XILINX_SYSACE is not set | ||||||
|  | # CONFIG_XILINX_VCU is not set | ||||||
|  | # CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set | ||||||
|  | # CONFIG_XIL_AXIS_FIFO is not set | ||||||
|  | CONFIG_XZ_DEC_BCJ=y | ||||||
|  | CONFIG_XZ_DEC_POWERPC=y | ||||||
|  | # CONFIG_YOSEMITE is not set | ||||||
|  | CONFIG_ZLIB_DEFLATE=y | ||||||
|  | CONFIG_ZLIB_INFLATE=y | ||||||
| @@ -21,6 +21,7 @@ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #include <dt-bindings/dma/dw-dmac.h> | ||||||
| #include <dt-bindings/input/input.h> | #include <dt-bindings/input/input.h> | ||||||
| #include <dt-bindings/interrupt-controller/irq.h> | #include <dt-bindings/interrupt-controller/irq.h> | ||||||
| #include <dt-bindings/gpio/gpio.h> | #include <dt-bindings/gpio/gpio.h> | ||||||
| @@ -384,7 +385,20 @@ | |||||||
| 			interrupt-parent = <&UIC0>; | 			interrupt-parent = <&UIC0>; | ||||||
| 			interrupts = <0x19 IRQ_TYPE_LEVEL_HIGH>; | 			interrupts = <0x19 IRQ_TYPE_LEVEL_HIGH>; | ||||||
| 			#dma-cells = <3>; | 			#dma-cells = <3>; | ||||||
| 			/* use autoconfiguration for the dma setup */ |  | ||||||
|  | 			dma-channels = <2>; | ||||||
|  | 			dma-masters = <3>; | ||||||
|  | 			block_size = <4095>; | ||||||
|  | 			data-width = <4>, <4>, <4>; | ||||||
|  | 			multi-block = <1>, <1>; | ||||||
|  |  | ||||||
|  | 			chan_allocation_order = <1>; | ||||||
|  | 			chan_priority = <1>; | ||||||
|  |  | ||||||
|  | 			snps,dma-protection-control = | ||||||
|  | 				<(DW_DMAC_HPROT1_PRIVILEGED_MODE | | ||||||
|  | 				  DW_DMAC_HPROT2_BUFFERABLE)>; | ||||||
|  | 			is_memcpy; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		SATA0: sata@bffd1000 { | 		SATA0: sata@bffd1000 { | ||||||
|   | |||||||
| @@ -0,0 +1,155 @@ | |||||||
|  | From 7b0c03ecc42fb223baf015877fee9d517c2c8af1 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | Date: Sat, 17 Nov 2018 17:17:21 +0100 | ||||||
|  | Subject: dmaengine: dw-dmac: implement dma protection control setting | ||||||
|  |  | ||||||
|  | This patch adds a new device-tree property that allows to | ||||||
|  | specify the dma protection control bits for the all of the | ||||||
|  | DMA controller's channel uniformly. | ||||||
|  |  | ||||||
|  | Setting the "correct" bits can have a huge impact on the | ||||||
|  | PPC460EX and APM82181 that use this DMA engine in combination | ||||||
|  | with a DesignWare' SATA-II core (sata_dwc_460ex driver). | ||||||
|  |  | ||||||
|  | In the OpenWrt Forum, the user takimata reported that: | ||||||
|  | |It seems your patch unleashed the full power of the SATA port. | ||||||
|  | |Where I was previously hitting a really hard limit at around | ||||||
|  | |82 MB/s for reading and 27 MB/s for writing, I am now getting this: | ||||||
|  | | | ||||||
|  | |root@OpenWrt:/mnt# time dd if=/dev/zero of=tempfile bs=1M count=1024 | ||||||
|  | |1024+0 records in | ||||||
|  | |1024+0 records out | ||||||
|  | |real    0m 13.65s | ||||||
|  | |user    0m 0.01s | ||||||
|  | |sys     0m 11.89s | ||||||
|  | | | ||||||
|  | |root@OpenWrt:/mnt# time dd if=tempfile of=/dev/null bs=1M count=1024 | ||||||
|  | |1024+0 records in | ||||||
|  | |1024+0 records out | ||||||
|  | |real    0m 8.41s | ||||||
|  | |user    0m 0.01s | ||||||
|  | |sys     0m 4.70s | ||||||
|  | | | ||||||
|  | |This means: 121 MB/s reading and 75 MB/s writing! | ||||||
|  | | | ||||||
|  | |The drive is a WD Green WD10EARX taken from an older MBL Single. | ||||||
|  | |I repeated the test a few times with even larger files to rule out | ||||||
|  | |any caching, I'm still seeing the same great performance. OpenWrt is | ||||||
|  | |now completely on par with the original MBL firmware's performance. | ||||||
|  |  | ||||||
|  | Another user And.short reported: | ||||||
|  | |I can report that your fix worked! Boots up fine with two | ||||||
|  | |drives even with more partitions, and no more reboot on | ||||||
|  | |concurrent disk access! | ||||||
|  |  | ||||||
|  | A closer look into the sata_dwc_460ex code revealed that | ||||||
|  | the driver did initally set the correct protection control | ||||||
|  | bits. However, this feature was lost when the sata_dwc_460ex | ||||||
|  | driver was converted to the generic DMA driver framework. | ||||||
|  |  | ||||||
|  | BugLink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/55 | ||||||
|  | BugLink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/50 | ||||||
|  | Fixes: 8b3444852a2b ("sata_dwc_460ex: move to generic DMA driver") | ||||||
|  | Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||||
|  | Signed-off-by: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | Signed-off-by: Vinod Koul <vkoul@kernel.org> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c | ||||||
|  | index d0c3e50b39fb..2c5ca1961256 100644 | ||||||
|  | --- a/drivers/dma/dw/core.c | ||||||
|  | +++ b/drivers/dma/dw/core.c | ||||||
|  | @@ -160,12 +160,14 @@ static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc) | ||||||
|  |   | ||||||
|  |  static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc) | ||||||
|  |  { | ||||||
|  | +	struct dw_dma *dw = to_dw_dma(dwc->chan.device); | ||||||
|  |  	u32 cfghi = DWC_CFGH_FIFO_MODE; | ||||||
|  |  	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); | ||||||
|  |  	bool hs_polarity = dwc->dws.hs_polarity; | ||||||
|  |   | ||||||
|  |  	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id); | ||||||
|  |  	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id); | ||||||
|  | +	cfghi |= DWC_CFGH_PROTCTL(dw->pdata->protctl); | ||||||
|  |   | ||||||
|  |  	/* Set polarity of handshake interface */ | ||||||
|  |  	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0; | ||||||
|  | diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c | ||||||
|  | index f01b2c173fa6..31ff8113c3de 100644 | ||||||
|  | --- a/drivers/dma/dw/platform.c | ||||||
|  | +++ b/drivers/dma/dw/platform.c | ||||||
|  | @@ -162,6 +162,12 @@ dw_dma_parse_dt(struct platform_device *pdev) | ||||||
|  |  			pdata->multi_block[tmp] = 1; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { | ||||||
|  | +		if (tmp > CHAN_PROTCTL_MASK) | ||||||
|  | +			return NULL; | ||||||
|  | +		pdata->protctl = tmp; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	return pdata; | ||||||
|  |  } | ||||||
|  |  #else | ||||||
|  | diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h | ||||||
|  | index 09e7dfdbb790..646c9c960c07 100644 | ||||||
|  | --- a/drivers/dma/dw/regs.h | ||||||
|  | +++ b/drivers/dma/dw/regs.h | ||||||
|  | @@ -200,6 +200,10 @@ enum dw_dma_msize { | ||||||
|  |  #define DWC_CFGH_FCMODE		(1 << 0) | ||||||
|  |  #define DWC_CFGH_FIFO_MODE	(1 << 1) | ||||||
|  |  #define DWC_CFGH_PROTCTL(x)	((x) << 2) | ||||||
|  | +#define DWC_CFGH_PROTCTL_DATA	(0 << 2)	/* data access - always set */ | ||||||
|  | +#define DWC_CFGH_PROTCTL_PRIV	(1 << 2)	/* privileged -> AHB HPROT[1] */ | ||||||
|  | +#define DWC_CFGH_PROTCTL_BUFFER	(2 << 2)	/* bufferable -> AHB HPROT[2] */ | ||||||
|  | +#define DWC_CFGH_PROTCTL_CACHE	(4 << 2)	/* cacheable  -> AHB HPROT[3] */ | ||||||
|  |  #define DWC_CFGH_DS_UPD_EN	(1 << 5) | ||||||
|  |  #define DWC_CFGH_SS_UPD_EN	(1 << 6) | ||||||
|  |  #define DWC_CFGH_SRC_PER(x)	((x) << 7) | ||||||
|  | diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h | ||||||
|  | index 896cb71a382c..1a1d58ebffbf 100644 | ||||||
|  | --- a/include/linux/platform_data/dma-dw.h | ||||||
|  | +++ b/include/linux/platform_data/dma-dw.h | ||||||
|  | @@ -49,6 +49,7 @@  struct dw_dma_slave { | ||||||
|  |   * @data_width: Maximum data width supported by hardware per AHB master | ||||||
|  |   *		(in bytes, power of 2) | ||||||
|  |   * @multi_block: Multi block transfers supported by hardware per channel. | ||||||
|  | + * @protctl: Protection control signals setting per channel. | ||||||
|  |   */ | ||||||
|  |  struct dw_dma_platform_data { | ||||||
|  |  	unsigned int	nr_channels; | ||||||
|  | @@ -65,6 +66,11 @@  struct dw_dma_platform_data { | ||||||
|  |  	unsigned char	nr_masters; | ||||||
|  |  	unsigned char	data_width[DW_DMA_MAX_NR_MASTERS]; | ||||||
|  |  	unsigned char	multi_block[DW_DMA_MAX_NR_CHANNELS]; | ||||||
|  | +#define CHAN_PROTCTL_PRIVILEGED		BIT(0) | ||||||
|  | +#define CHAN_PROTCTL_BUFFERABLE		BIT(1) | ||||||
|  | +#define CHAN_PROTCTL_CACHEABLE		BIT(2) | ||||||
|  | +#define CHAN_PROTCTL_MASK		GENMASK(2, 0) | ||||||
|  | +	unsigned char	protctl; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  #endif /* _PLATFORM_DATA_DMA_DW_H */ | ||||||
|  | diff --git a/include/dt-bindings/dma/dw-dmac.h b/include/dt-bindings/dma/dw-dmac.h | ||||||
|  | new file mode 100644 | ||||||
|  | index 000000000000..d1ca705c95b3 | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/include/dt-bindings/dma/dw-dmac.h | ||||||
|  | @@ -0,0 +1,14 @@  | ||||||
|  | +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ | ||||||
|  | + | ||||||
|  | +#ifndef __DT_BINDINGS_DMA_DW_DMAC_H__ | ||||||
|  | +#define __DT_BINDINGS_DMA_DW_DMAC_H__ | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * Protection Control bits provide protection against illegal transactions. | ||||||
|  | + * The protection bits[0:2] are one-to-one mapped to AHB HPROT[3:1] signals. | ||||||
|  | + */ | ||||||
|  | +#define DW_DMAC_HPROT1_PRIVILEGED_MODE	(1 << 0)	/* Privileged Mode */ | ||||||
|  | +#define DW_DMAC_HPROT2_BUFFERABLE	(1 << 1)	/* DMA is bufferable */ | ||||||
|  | +#define DW_DMAC_HPROT3_CACHEABLE	(1 << 2)	/* DMA is cacheable */ | ||||||
|  | + | ||||||
|  | +#endif /* __DT_BINDINGS_DMA_DW_DMAC_H__ */ | ||||||
|  | -- | ||||||
|  | cgit 1.2-0.3.lf.el7 | ||||||
|  |  | ||||||
| @@ -0,0 +1,169 @@ | |||||||
|  | From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Tue, 12 Aug 2014 20:49:27 +0200 | ||||||
|  | Subject: [PATCH 30/36] GPIO: add named gpio exports | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  drivers/gpio/gpiolib.c        |   11 +++++-- | ||||||
|  |  include/asm-generic/gpio.h    |    5 +++ | ||||||
|  |  include/linux/gpio/consumer.h |    8 +++++ | ||||||
|  |  4 files changed, 90 insertions(+), 2 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/gpio/gpiolib-of.c | ||||||
|  | +++ b/drivers/gpio/gpiolib-of.c | ||||||
|  | @@ -23,6 +23,8 @@ | ||||||
|  |  #include <linux/pinctrl/pinctrl.h> | ||||||
|  |  #include <linux/slab.h> | ||||||
|  |  #include <linux/gpio/machine.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  |   | ||||||
|  |  #include "gpiolib.h" | ||||||
|  |   | ||||||
|  | @@ -654,3 +656,72 @@ void of_gpiochip_remove(struct gpio_chip | ||||||
|  |  	gpiochip_remove_pin_ranges(chip); | ||||||
|  |  	of_node_put(chip->of_node); | ||||||
|  |  } | ||||||
|  | + | ||||||
|  | +#ifdef CONFIG_GPIO_SYSFS | ||||||
|  | + | ||||||
|  | +static struct of_device_id gpio_export_ids[] = { | ||||||
|  | +	{ .compatible = "gpio-export" }, | ||||||
|  | +	{ /* sentinel */ } | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int of_gpio_export_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct device_node *np = pdev->dev.of_node; | ||||||
|  | +	struct device_node *cnp; | ||||||
|  | +	u32 val; | ||||||
|  | +	int nb = 0; | ||||||
|  | + | ||||||
|  | +	for_each_child_of_node(np, cnp) { | ||||||
|  | +		const char *name = NULL; | ||||||
|  | +		int gpio; | ||||||
|  | +		bool dmc; | ||||||
|  | +		int max_gpio = 1; | ||||||
|  | +		int i; | ||||||
|  | + | ||||||
|  | +		of_property_read_string(cnp, "gpio-export,name", &name); | ||||||
|  | + | ||||||
|  | +		if (!name) | ||||||
|  | +			max_gpio = of_gpio_count(cnp); | ||||||
|  | + | ||||||
|  | +		for (i = 0; i < max_gpio; i++) { | ||||||
|  | +			unsigned flags = 0; | ||||||
|  | +			enum of_gpio_flags of_flags; | ||||||
|  | + | ||||||
|  | +			gpio = of_get_gpio_flags(cnp, i, &of_flags); | ||||||
|  | +			if (!gpio_is_valid(gpio)) | ||||||
|  | +				return gpio; | ||||||
|  | + | ||||||
|  | +			if (of_flags == OF_GPIO_ACTIVE_LOW) | ||||||
|  | +				flags |= GPIOF_ACTIVE_LOW; | ||||||
|  | + | ||||||
|  | +			if (!of_property_read_u32(cnp, "gpio-export,output", &val)) | ||||||
|  | +				flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||||||
|  | +			else | ||||||
|  | +				flags |= GPIOF_IN; | ||||||
|  | + | ||||||
|  | +			if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) | ||||||
|  | +				continue; | ||||||
|  | + | ||||||
|  | +			dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); | ||||||
|  | +			gpio_export_with_name(gpio, dmc, name); | ||||||
|  | +			nb++; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct platform_driver gpio_export_driver = { | ||||||
|  | +	.driver		= { | ||||||
|  | +		.name		= "gpio-export", | ||||||
|  | +		.owner	= THIS_MODULE, | ||||||
|  | +		.of_match_table	= of_match_ptr(gpio_export_ids), | ||||||
|  | +	}, | ||||||
|  | +	.probe		= of_gpio_export_probe, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(gpio_export_driver); | ||||||
|  | + | ||||||
|  | +#endif | ||||||
|  | --- a/include/asm-generic/gpio.h | ||||||
|  | +++ b/include/asm-generic/gpio.h | ||||||
|  | @@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g | ||||||
|  |  	return gpiod_export(gpio_to_desc(gpio), direction_may_change); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); | ||||||
|  | +static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name) | ||||||
|  | +{ | ||||||
|  | +	return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static inline int gpio_export_link(struct device *dev, const char *name, | ||||||
|  |  				   unsigned gpio) | ||||||
|  |  { | ||||||
|  | --- a/include/linux/gpio/consumer.h | ||||||
|  | +++ b/include/linux/gpio/consumer.h | ||||||
|  | @@ -531,6 +531,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_ | ||||||
|  |   | ||||||
|  |  #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) | ||||||
|  |   | ||||||
|  | +int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); | ||||||
|  |  int gpiod_export(struct gpio_desc *desc, bool direction_may_change); | ||||||
|  |  int gpiod_export_link(struct device *dev, const char *name, | ||||||
|  |  		      struct gpio_desc *desc); | ||||||
|  | @@ -538,6 +539,13 @@ void gpiod_unexport(struct gpio_desc *de | ||||||
|  |   | ||||||
|  |  #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ | ||||||
|  |   | ||||||
|  | +static inline int _gpiod_export(struct gpio_desc *desc, | ||||||
|  | +			       bool direction_may_change, | ||||||
|  | +			       const char *name) | ||||||
|  | +{ | ||||||
|  | +	return -ENOSYS; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static inline int gpiod_export(struct gpio_desc *desc, | ||||||
|  |  			       bool direction_may_change) | ||||||
|  |  { | ||||||
|  | --- a/drivers/gpio/gpiolib-sysfs.c | ||||||
|  | +++ b/drivers/gpio/gpiolib-sysfs.c | ||||||
|  | @@ -568,7 +568,7 @@ static struct class gpio_class = { | ||||||
|  |   * | ||||||
|  |   * Returns zero on success, else an error. | ||||||
|  |   */ | ||||||
|  | -int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | ||||||
|  | +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) | ||||||
|  |  { | ||||||
|  |  	struct gpio_chip	*chip; | ||||||
|  |  	struct gpio_device	*gdev; | ||||||
|  | @@ -630,6 +630,8 @@ int gpiod_export(struct gpio_desc *desc, | ||||||
|  |  	offset = gpio_chip_hwgpio(desc); | ||||||
|  |  	if (chip->names && chip->names[offset]) | ||||||
|  |  		ioname = chip->names[offset]; | ||||||
|  | +	if (name) | ||||||
|  | +		ioname = name; | ||||||
|  |   | ||||||
|  |  	dev = device_create_with_groups(&gpio_class, &gdev->dev, | ||||||
|  |  					MKDEV(0, 0), data, gpio_groups, | ||||||
|  | @@ -651,6 +653,12 @@ err_unlock: | ||||||
|  |  	gpiod_dbg(desc, "%s: status %d\n", __func__, status); | ||||||
|  |  	return status; | ||||||
|  |  } | ||||||
|  | +EXPORT_SYMBOL_GPL(__gpiod_export); | ||||||
|  | + | ||||||
|  | +int gpiod_export(struct gpio_desc *desc, bool direction_may_change) | ||||||
|  | +{ | ||||||
|  | +	return __gpiod_export(desc, direction_may_change, NULL); | ||||||
|  | +} | ||||||
|  |  EXPORT_SYMBOL_GPL(gpiod_export); | ||||||
|  |   | ||||||
|  |  static int match_export(struct device *dev, const void *desc) | ||||||
| @@ -0,0 +1,30 @@ | |||||||
|  | --- a/arch/powerpc/platforms/44x/Kconfig | ||||||
|  | +++ b/arch/powerpc/platforms/44x/Kconfig | ||||||
|  | @@ -144,6 +144,17 @@ config CANYONLANDS | ||||||
|  |  	help | ||||||
|  |  	  This option enables support for the AMCC PPC460EX evaluation board. | ||||||
|  |   | ||||||
|  | +config APOLLO3G | ||||||
|  | +	bool "Apollo3G" | ||||||
|  | +	depends on 44x | ||||||
|  | +	default n | ||||||
|  | +	select PPC44x_SIMPLE | ||||||
|  | +	select APM821xx | ||||||
|  | +	select IBM_EMAC_RGMII | ||||||
|  | +	select 460EX | ||||||
|  | +	help | ||||||
|  | +	  This option enables support for the AMCC Apollo 3G board. | ||||||
|  | + | ||||||
|  |  config GLACIER | ||||||
|  |  	bool "Glacier" | ||||||
|  |  	depends on 44x | ||||||
|  | --- a/arch/powerpc/platforms/44x/ppc44x_simple.c | ||||||
|  | +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c | ||||||
|  | @@ -50,6 +50,7 @@ machine_device_initcall(ppc44x_simple, p | ||||||
|  |   * board.c file for it rather than adding it to this list. | ||||||
|  |   */ | ||||||
|  |  static char *board[] __initdata = { | ||||||
|  | +	"amcc,apollo3g", | ||||||
|  |  	"amcc,arches", | ||||||
|  |  	"amcc,bamboo", | ||||||
|  |  	"apm,bluestone", | ||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | --- a/arch/powerpc/platforms/44x/Makefile | ||||||
|  | +++ b/arch/powerpc/platforms/44x/Makefile | ||||||
|  | @@ -4,6 +4,7 @@ ifneq ($(CONFIG_PPC4xx_CPM),y) | ||||||
|  |  obj-y	+= idle.o | ||||||
|  |  endif | ||||||
|  |  obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o | ||||||
|  | +obj-$(CONFIG_WNDR4700) += wndr4700.o | ||||||
|  |  obj-$(CONFIG_EBONY)	+= ebony.o | ||||||
|  |  obj-$(CONFIG_SAM440EP) 	+= sam440ep.o | ||||||
|  |  obj-$(CONFIG_WARP)	+= warp.o | ||||||
|  | --- a/arch/powerpc/platforms/44x/Kconfig | ||||||
|  | +++ b/arch/powerpc/platforms/44x/Kconfig | ||||||
|  | @@ -273,6 +273,19 @@ config ICON | ||||||
|  |  	help | ||||||
|  |  	  This option enables support for the AMCC PPC440SPe evaluation board. | ||||||
|  |   | ||||||
|  | +config WNDR4700 | ||||||
|  | +	bool "WNDR4700" | ||||||
|  | +	depends on 44x | ||||||
|  | +	default n | ||||||
|  | +	select APM821xx | ||||||
|  | +	select PCI_MSI | ||||||
|  | +	select PPC4xx_MSI | ||||||
|  | +	select PPC4xx_PCI_EXPRESS | ||||||
|  | +	select IBM_EMAC_RGMII | ||||||
|  | +	select 460EX | ||||||
|  | +	help | ||||||
|  | +	  This option enables support for the Netgear WNDR4700/WNDR4720 board. | ||||||
|  | + | ||||||
|  |  config XILINX_VIRTEX440_GENERIC_BOARD | ||||||
|  |  	bool "Generic Xilinx Virtex 5 FXT board support" | ||||||
|  |  	depends on 44x | ||||||
| @@ -0,0 +1,51 @@ | |||||||
|  | --- a/arch/powerpc/platforms/4xx/pci.c | ||||||
|  | +++ b/arch/powerpc/platforms/4xx/pci.c | ||||||
|  | @@ -1060,15 +1060,24 @@ static int __init apm821xx_pciex_init_po | ||||||
|  |  	u32 val; | ||||||
|  |   | ||||||
|  |  	/* | ||||||
|  | -	 * Do a software reset on PCIe ports. | ||||||
|  | -	 * This code is to fix the issue that pci drivers doesn't re-assign | ||||||
|  | -	 * bus number for PCIE devices after Uboot | ||||||
|  | -	 * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 | ||||||
|  | -	 * PT quad port, SAS LSI 1064E) | ||||||
|  | +	 * Only reset the PHY when no link is currently established. | ||||||
|  | +	 * This is for the Atheros PCIe board which has problems to establish | ||||||
|  | +	 * the link (again) after this PHY reset. All other currently tested | ||||||
|  | +	 * PCIe boards don't show this problem. | ||||||
|  |  	 */ | ||||||
|  | - | ||||||
|  | -	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); | ||||||
|  | -	mdelay(10); | ||||||
|  | +	val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | ||||||
|  | +	if (!(val & 0x00001000)) { | ||||||
|  | +		/* | ||||||
|  | +		 * Do a software reset on PCIe ports. | ||||||
|  | +		 * This code is to fix the issue that pci drivers doesn't re-assign | ||||||
|  | +		 * bus number for PCIE devices after Uboot | ||||||
|  | +		 * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 | ||||||
|  | +		 * PT quad port, SAS LSI 1064E) | ||||||
|  | +		 */ | ||||||
|  | + | ||||||
|  | +		mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); | ||||||
|  | +		mdelay(10); | ||||||
|  | +	} | ||||||
|  |   | ||||||
|  |  	if (port->endpoint) | ||||||
|  |  		val = PTYPE_LEGACY_ENDPOINT << 20; | ||||||
|  | @@ -1085,9 +1094,12 @@ static int __init apm821xx_pciex_init_po | ||||||
|  |  	mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); | ||||||
|  |  	mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); | ||||||
|  |   | ||||||
|  | -	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); | ||||||
|  | -	mdelay(50); | ||||||
|  | -	mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); | ||||||
|  | +	val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | ||||||
|  | +	if (!(val & 0x00001000)) { | ||||||
|  | +		mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); | ||||||
|  | +		mdelay(50); | ||||||
|  | +		mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); | ||||||
|  | +	} | ||||||
|  |   | ||||||
|  |  	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||||||
|  |  		mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | --- a/arch/powerpc/platforms/4xx/pci.c | ||||||
|  | +++ b/arch/powerpc/platforms/4xx/pci.c | ||||||
|  | @@ -1905,9 +1905,9 @@ static void __init ppc4xx_configure_pcie | ||||||
|  |  		 * if it works | ||||||
|  |  		 */ | ||||||
|  |  		out_le32(mbase + PECFG_PIM0LAL, 0x00000000); | ||||||
|  | -		out_le32(mbase + PECFG_PIM0LAH, 0x00000000); | ||||||
|  | +		out_le32(mbase + PECFG_PIM0LAH, 0x00000008); | ||||||
|  |  		out_le32(mbase + PECFG_PIM1LAL, 0x00000000); | ||||||
|  | -		out_le32(mbase + PECFG_PIM1LAH, 0x00000000); | ||||||
|  | +		out_le32(mbase + PECFG_PIM1LAH, 0x0000000c); | ||||||
|  |  		out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); | ||||||
|  |  		out_le32(mbase + PECFG_PIM01SAL, 0x00000000); | ||||||
|  |   | ||||||
| @@ -0,0 +1,545 @@ | |||||||
|  | From 419992bae5aaa4e06402e0b7c79fcf7bcb6b4764 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Christian Lamparter <chunkeey@googlemail.com> | ||||||
|  | Date: Thu, 2 Jun 2016 00:48:46 +0200 | ||||||
|  | Subject: [PATCH] usb: xhci: add firmware loader for uPD720201 and uPD720202 | ||||||
|  |  w/o ROM | ||||||
|  |  | ||||||
|  | This patch adds a firmware loader for the uPD720201K8-711-BAC-A | ||||||
|  | and uPD720202K8-711-BAA-A variant. Both of these chips are listed | ||||||
|  | in Renesas' R19UH0078EJ0500 Rev.5.00 "User's Manual: Hardware" as | ||||||
|  | devices which need the firmware loader on page 2 in order to | ||||||
|  | work as they "do not support the External ROM". | ||||||
|  |  | ||||||
|  | The "Firmware Download Sequence" is describe in chapter | ||||||
|  | "7.1 FW Download Interface" R19UH0078EJ0500 Rev.5.00 page 131. | ||||||
|  |  | ||||||
|  | The firmware "K2013080.mem" is available from a USB3.0 Host to | ||||||
|  | PCIe Adapter (PP2U-E card) "Firmware download" archive. An | ||||||
|  | alternative version can be sourced from Netgear's WNDR4700 GPL | ||||||
|  | archives. | ||||||
|  |  | ||||||
|  | The release notes of the PP2U-E's "Firmware Download" ver 2.0.1.3 | ||||||
|  | (2012-06-15) state that the firmware is for the following devices: | ||||||
|  |  - uPD720201 ES 2.0 sample whose revision ID is 2. | ||||||
|  |  - uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3. | ||||||
|  |  - uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2. | ||||||
|  |  | ||||||
|  | If someone from Renesas is listening: It would be great, if these | ||||||
|  | firmwares could be added to linux-firmware.git. | ||||||
|  |  | ||||||
|  | Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | ||||||
|  | Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> | ||||||
|  | --- | ||||||
|  |  drivers/usb/host/xhci-pci.c | 492 ++++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 492 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/usb/host/xhci-pci.c | ||||||
|  | +++ b/drivers/usb/host/xhci-pci.c | ||||||
|  | @@ -12,6 +12,8 @@ | ||||||
|  |  #include <linux/slab.h> | ||||||
|  |  #include <linux/module.h> | ||||||
|  |  #include <linux/acpi.h> | ||||||
|  | +#include <linux/firmware.h> | ||||||
|  | +#include <asm/unaligned.h> | ||||||
|  |   | ||||||
|  |  #include "xhci.h" | ||||||
|  |  #include "xhci-trace.h" | ||||||
|  | @@ -248,6 +250,458 @@ static void xhci_pme_acpi_rtd3_enable(st | ||||||
|  |  static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { } | ||||||
|  |  #endif /* CONFIG_ACPI */ | ||||||
|  |   | ||||||
|  | +static const struct renesas_fw_entry { | ||||||
|  | +	const char *firmware_name; | ||||||
|  | +	u16 device; | ||||||
|  | +	u8 revision; | ||||||
|  | +	u16 expected_version; | ||||||
|  | +} renesas_fw_table[] = { | ||||||
|  | +	/* | ||||||
|  | +	 * Only the uPD720201K8-711-BAC-A or uPD720202K8-711-BAA-A | ||||||
|  | +	 * are listed in R19UH0078EJ0500 Rev.5.00 as devices which | ||||||
|  | +	 * need the software loader. | ||||||
|  | +	 * | ||||||
|  | +	 * PP2U/ReleaseNote_USB3-201-202-FW.txt: | ||||||
|  | +	 * | ||||||
|  | +	 * Note: This firmware is for the following devices. | ||||||
|  | +	 *  - uPD720201 ES 2.0 sample whose revision ID is 2. | ||||||
|  | +	 *  - uPD720201 ES 2.1 sample & CS sample & Mass product, ID is 3. | ||||||
|  | +	 *  - uPD720202 ES 2.0 sample & CS sample & Mass product, ID is 2. | ||||||
|  | +	 */ | ||||||
|  | +	{ "K2013080.mem", 0x0014, 0x02, 0x2013 }, | ||||||
|  | +	{ "K2013080.mem", 0x0014, 0x03, 0x2013 }, | ||||||
|  | +	{ "K2013080.mem", 0x0015, 0x02, 0x2013 }, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static const struct renesas_fw_entry *renesas_needs_fw_dl(struct pci_dev *dev) | ||||||
|  | +{ | ||||||
|  | +	const struct renesas_fw_entry *entry; | ||||||
|  | +	size_t i; | ||||||
|  | + | ||||||
|  | +	/* This loader will only work with a RENESAS device. */ | ||||||
|  | +	if (!(dev->vendor == PCI_VENDOR_ID_RENESAS)) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < ARRAY_SIZE(renesas_fw_table); i++) { | ||||||
|  | +		entry = &renesas_fw_table[i]; | ||||||
|  | +		if (entry->device == dev->device && | ||||||
|  | +		    entry->revision == dev->revision) | ||||||
|  | +			return entry; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return NULL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_download_image(struct pci_dev *dev, | ||||||
|  | +				     const u32 *fw, | ||||||
|  | +				     size_t step) | ||||||
|  | +{ | ||||||
|  | +	size_t i; | ||||||
|  | +	int err; | ||||||
|  | +	u8 fw_status; | ||||||
|  | +	bool data0_or_data1; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The hardware does alternate between two 32-bit pages. | ||||||
|  | +	 * (This is because each row of the firmware is 8 bytes). | ||||||
|  | +	 * | ||||||
|  | +	 * for even steps we use DATA0, for odd steps DATA1. | ||||||
|  | +	 */ | ||||||
|  | +	data0_or_data1 = (step & 1) == 1; | ||||||
|  | + | ||||||
|  | +	/* step+1. Read "Set DATAX" and confirm it is cleared. */ | ||||||
|  | +	for (i = 0; i < 10000; i++) { | ||||||
|  | +		err = pci_read_config_byte(dev, 0xF5, &fw_status); | ||||||
|  | +		if (err) | ||||||
|  | +			return pcibios_err_to_errno(err); | ||||||
|  | +		if (!(fw_status & BIT(data0_or_data1))) | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		udelay(1); | ||||||
|  | +	} | ||||||
|  | +	if (i == 10000) | ||||||
|  | +		return -ETIMEDOUT; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * step+2. Write FW data to "DATAX". | ||||||
|  | +	 * "LSB is left" => force little endian | ||||||
|  | +	 */ | ||||||
|  | +	err = pci_write_config_dword(dev, data0_or_data1 ? 0xFC : 0xF8, | ||||||
|  | +				     (__force u32) cpu_to_le32(fw[step])); | ||||||
|  | +	if (err) | ||||||
|  | +		return pcibios_err_to_errno(err); | ||||||
|  | + | ||||||
|  | +	udelay(100); | ||||||
|  | + | ||||||
|  | +	/* step+3. Set "Set DATAX". */ | ||||||
|  | +	err = pci_write_config_byte(dev, 0xF5, BIT(data0_or_data1)); | ||||||
|  | +	if (err) | ||||||
|  | +		return pcibios_err_to_errno(err); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_verify(struct pci_dev *dev, | ||||||
|  | +			     const void *fw_data, | ||||||
|  | +			     size_t length) | ||||||
|  | +{ | ||||||
|  | +	const struct renesas_fw_entry *entry = renesas_needs_fw_dl(dev); | ||||||
|  | +	u16 fw_version_pointer; | ||||||
|  | +	u16 fw_version; | ||||||
|  | + | ||||||
|  | +	if (!entry) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The Firmware's Data Format is describe in | ||||||
|  | +	 * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124 | ||||||
|  | +	 */ | ||||||
|  | + | ||||||
|  | +	/* "Each row is 8 bytes". => firmware size must be a multiple of 8. */ | ||||||
|  | +	if (length % 8 != 0) { | ||||||
|  | +		dev_err(&dev->dev, "firmware size is not a multipe of 8."); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The bootrom chips of the big brother have sizes up to 64k, let's | ||||||
|  | +	 * assume that's the biggest the firmware can get. | ||||||
|  | +	 */ | ||||||
|  | +	if (length < 0x1000 || length >= 0x10000) { | ||||||
|  | +		dev_err(&dev->dev, "firmware is size %zd is not (4k - 64k).", | ||||||
|  | +			length); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* The First 2 bytes are fixed value (55aa). "LSB on Left" */ | ||||||
|  | +	if (get_unaligned_le16(fw_data) != 0x55aa) { | ||||||
|  | +		dev_err(&dev->dev, "no valid firmware header found."); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* verify the firmware version position and print it. */ | ||||||
|  | +	fw_version_pointer = get_unaligned_le16(fw_data + 4); | ||||||
|  | +	if (fw_version_pointer + 2 >= length) { | ||||||
|  | +		dev_err(&dev->dev, "firmware version pointer is outside of the firmware image."); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	fw_version = get_unaligned_le16(fw_data + fw_version_pointer); | ||||||
|  | +	dev_dbg(&dev->dev, "got firmware version: %02x.", fw_version); | ||||||
|  | + | ||||||
|  | +	if (fw_version != entry->expected_version) { | ||||||
|  | +		dev_err(&dev->dev, "firmware version mismatch, expected version: %02x.", | ||||||
|  | +			 entry->expected_version); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_check_running(struct pci_dev *pdev) | ||||||
|  | +{ | ||||||
|  | +	int err; | ||||||
|  | +	u8 fw_state; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Test if the device is actually needing the firmware. As most | ||||||
|  | +	 * BIOSes will initialize the device for us. If the device is | ||||||
|  | +	 * initialized. | ||||||
|  | +	 */ | ||||||
|  | +	err = pci_read_config_byte(pdev, 0xF4, &fw_state); | ||||||
|  | +	if (err) | ||||||
|  | +		return pcibios_err_to_errno(err); | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Check if "FW Download Lock" is locked. If it is and the FW is | ||||||
|  | +	 * ready we can simply continue. If the FW is not ready, we have | ||||||
|  | +	 * to give up. | ||||||
|  | +	 */ | ||||||
|  | +	if (fw_state & BIT(1)) { | ||||||
|  | +		dev_dbg(&pdev->dev, "FW Download Lock is engaged."); | ||||||
|  | + | ||||||
|  | +		if (fw_state & BIT(4)) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		dev_err(&pdev->dev, "FW Download Lock is set and FW is not ready. Giving Up."); | ||||||
|  | +		return -EIO; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Check if "FW Download Enable" is set. If someone (us?) tampered | ||||||
|  | +	 * with it and it can't be resetted, we have to give up too... and | ||||||
|  | +	 * ask for a forgiveness and a reboot. | ||||||
|  | +	 */ | ||||||
|  | +	if (fw_state & BIT(0)) { | ||||||
|  | +		dev_err(&pdev->dev, "FW Download Enable is stale. Giving Up (poweroff/reboot needed)."); | ||||||
|  | +		return -EIO; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */ | ||||||
|  | +	switch ((fw_state & 0x70)) { | ||||||
|  | +	case 0: /* No result yet */ | ||||||
|  | +		dev_dbg(&pdev->dev, "FW is not ready/loaded yet."); | ||||||
|  | + | ||||||
|  | +		/* tell the caller, that this device needs the firmware. */ | ||||||
|  | +		return 1; | ||||||
|  | + | ||||||
|  | +	case BIT(4): /* Success, device should be working. */ | ||||||
|  | +		dev_dbg(&pdev->dev, "FW is ready."); | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	case BIT(5): /* Error State */ | ||||||
|  | +		dev_err(&pdev->dev, "hardware is in an error state. Giving up (poweroff/reboot needed)."); | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	default: /* All other states are marked as "Reserved states" */ | ||||||
|  | +		dev_err(&pdev->dev, "hardware is in an invalid state %x. Giving up (poweroff/reboot needed).", | ||||||
|  | +			(fw_state & 0x70) >> 4); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_hw_check_run_stop_busy(struct pci_dev *pdev) | ||||||
|  | +{ | ||||||
|  | +#if 0 | ||||||
|  | +	u32 val; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * 7.1.3 Note 3: "... must not set 'FW Download Enable' when | ||||||
|  | +	 * 'RUN/STOP' of USBCMD Register is set" | ||||||
|  | +	 */ | ||||||
|  | +	val = readl(hcd->regs + 0x20); | ||||||
|  | +	if (val & BIT(0)) { | ||||||
|  | +		dev_err(&pdev->dev, "hardware is busy and can't receive a FW."); | ||||||
|  | +		return -EBUSY; | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_download(struct pci_dev *pdev, | ||||||
|  | +	const struct firmware *fw, unsigned int retry_counter) | ||||||
|  | +{ | ||||||
|  | +	const u32 *fw_data = (const u32 *) fw->data; | ||||||
|  | +	size_t i; | ||||||
|  | +	int err; | ||||||
|  | +	u8 fw_status; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * For more information and the big picture: please look at the | ||||||
|  | +	 * "Firmware Download Sequence" in "7.1 FW Download Interface" | ||||||
|  | +	 * of R19UH0078EJ0500 Rev.5.00 page 131 | ||||||
|  | +	 */ | ||||||
|  | +	err = renesas_hw_check_run_stop_busy(pdev); | ||||||
|  | +	if (err) | ||||||
|  | +		return err; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * 0. Set "FW Download Enable" bit in the | ||||||
|  | +	 * "FW Download Control & Status Register" at 0xF4 | ||||||
|  | +	 */ | ||||||
|  | +	err = pci_write_config_byte(pdev, 0xF4, BIT(0)); | ||||||
|  | +	if (err) | ||||||
|  | +		return pcibios_err_to_errno(err); | ||||||
|  | + | ||||||
|  | +	/* 1 - 10 follow one step after the other. */ | ||||||
|  | +	for (i = 0; i < fw->size / 4; i++) { | ||||||
|  | +		err = renesas_fw_download_image(pdev, fw_data, i); | ||||||
|  | +		if (err) { | ||||||
|  | +			dev_err(&pdev->dev, "Firmware Download Step %zd failed at position %zd bytes with (%d).", | ||||||
|  | +				 i, i * 4, err); | ||||||
|  | +			return err; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * This sequence continues until the last data is written to | ||||||
|  | +	 * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1" | ||||||
|  | +	 * is cleared by the hardware beforehand. | ||||||
|  | +	 */ | ||||||
|  | +	for (i = 0; i < 10000; i++) { | ||||||
|  | +		err = pci_read_config_byte(pdev, 0xF5, &fw_status); | ||||||
|  | +		if (err) | ||||||
|  | +			return pcibios_err_to_errno(err); | ||||||
|  | +		if (!(fw_status & (BIT(0) | BIT(1)))) | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		udelay(1); | ||||||
|  | +	} | ||||||
|  | +	if (i == 10000) | ||||||
|  | +		dev_warn(&pdev->dev, "Final Firmware Download step timed out."); | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * 11. After finishing writing the last data of FW, the | ||||||
|  | +	 * System Software must clear "FW Download Enable" | ||||||
|  | +	 */ | ||||||
|  | +	err = pci_write_config_byte(pdev, 0xF4, 0); | ||||||
|  | +	if (err) | ||||||
|  | +		return pcibios_err_to_errno(err); | ||||||
|  | + | ||||||
|  | +	/* 12. Read "Result Code" and confirm it is good. */ | ||||||
|  | +	for (i = 0; i < 10000; i++) { | ||||||
|  | +		err = pci_read_config_byte(pdev, 0xF4, &fw_status); | ||||||
|  | +		if (err) | ||||||
|  | +			return pcibios_err_to_errno(err); | ||||||
|  | +		if (fw_status & BIT(4)) | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		udelay(1); | ||||||
|  | +	} | ||||||
|  | +	if (i == 10000) { | ||||||
|  | +		/* Timed out / Error - let's see if we can fix this */ | ||||||
|  | +		err = renesas_fw_check_running(pdev); | ||||||
|  | +		switch (err) { | ||||||
|  | +		case 0: /* | ||||||
|  | +			 * we shouldn't end up here. | ||||||
|  | +			 * maybe it took a little bit longer. | ||||||
|  | +			 * But all should be well? | ||||||
|  | +			 */ | ||||||
|  | +			break; | ||||||
|  | + | ||||||
|  | +		case 1: /* (No result yet? - we can try to retry) */ | ||||||
|  | +			if (retry_counter < 10) { | ||||||
|  | +				retry_counter++; | ||||||
|  | +				dev_warn(&pdev->dev, "Retry Firmware download: %d try.", | ||||||
|  | +					  retry_counter); | ||||||
|  | +				return renesas_fw_download(pdev, fw, | ||||||
|  | +							   retry_counter); | ||||||
|  | +			} | ||||||
|  | +			return -ETIMEDOUT; | ||||||
|  | + | ||||||
|  | +		default: | ||||||
|  | +			return err; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	/* | ||||||
|  | +	 * Optional last step: Engage Firmware Lock | ||||||
|  | +	 * | ||||||
|  | +	 * err = pci_write_config_byte(pdev, 0xF4, BIT(2)); | ||||||
|  | +	 * if (err) | ||||||
|  | +	 *	return pcibios_err_to_errno(err); | ||||||
|  | +	 */ | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +struct renesas_fw_ctx { | ||||||
|  | +	struct pci_dev *pdev; | ||||||
|  | +	const struct pci_device_id *id; | ||||||
|  | +	bool resume; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int xhci_pci_probe(struct pci_dev *pdev, | ||||||
|  | +			  const struct pci_device_id *id); | ||||||
|  | + | ||||||
|  | +static void renesas_fw_callback(const struct firmware *fw, | ||||||
|  | +				void *context) | ||||||
|  | +{ | ||||||
|  | +	struct renesas_fw_ctx *ctx = context; | ||||||
|  | +	struct pci_dev *pdev = ctx->pdev; | ||||||
|  | +	struct device *parent = pdev->dev.parent; | ||||||
|  | +	int err = -ENOENT; | ||||||
|  | + | ||||||
|  | +	if (fw) { | ||||||
|  | +		err = renesas_fw_verify(pdev, fw->data, fw->size); | ||||||
|  | +		if (!err) { | ||||||
|  | +			err = renesas_fw_download(pdev, fw, 0); | ||||||
|  | +			release_firmware(fw); | ||||||
|  | +			if (!err) { | ||||||
|  | +				if (ctx->resume) | ||||||
|  | +					return; | ||||||
|  | + | ||||||
|  | +				err = xhci_pci_probe(pdev, ctx->id); | ||||||
|  | +				if (!err) { | ||||||
|  | +					/* everything worked */ | ||||||
|  | +					devm_kfree(&pdev->dev, ctx); | ||||||
|  | +					return; | ||||||
|  | +				} | ||||||
|  | + | ||||||
|  | +				/* in case of an error - fall through */ | ||||||
|  | +			} else { | ||||||
|  | +				dev_err(&pdev->dev, "firmware failed to download (%d).", | ||||||
|  | +					err); | ||||||
|  | +			} | ||||||
|  | +		} | ||||||
|  | +	} else { | ||||||
|  | +		dev_err(&pdev->dev, "firmware failed to load (%d).", err); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "Unloading driver"); | ||||||
|  | + | ||||||
|  | +	if (parent) | ||||||
|  | +		device_lock(parent); | ||||||
|  | + | ||||||
|  | +	device_release_driver(&pdev->dev); | ||||||
|  | + | ||||||
|  | +	if (parent) | ||||||
|  | +		device_unlock(parent); | ||||||
|  | + | ||||||
|  | +	pci_dev_put(pdev); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_alive_check(struct pci_dev *pdev) | ||||||
|  | +{ | ||||||
|  | +	const struct renesas_fw_entry *entry; | ||||||
|  | +	int err; | ||||||
|  | + | ||||||
|  | +	/* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */ | ||||||
|  | +	entry = renesas_needs_fw_dl(pdev); | ||||||
|  | +	if (!entry) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	err = renesas_fw_check_running(pdev); | ||||||
|  | +	/* Also go ahead, if the firmware is running */ | ||||||
|  | +	if (err == 0) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	/* At this point, we can be sure that the FW isn't ready. */ | ||||||
|  | +	return err; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int renesas_fw_download_to_hw(struct pci_dev *pdev, | ||||||
|  | +				     const struct pci_device_id *id, | ||||||
|  | +				     bool do_resume) | ||||||
|  | +{ | ||||||
|  | +	const struct renesas_fw_entry *entry; | ||||||
|  | +	struct renesas_fw_ctx *ctx; | ||||||
|  | +	int err; | ||||||
|  | + | ||||||
|  | +	/* check if we have a eligible RENESAS' uPD720201/2 w/o FW. */ | ||||||
|  | +	entry = renesas_needs_fw_dl(pdev); | ||||||
|  | +	if (!entry) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	err = renesas_fw_check_running(pdev); | ||||||
|  | +	/* Continue ahead, if the firmware is already running. */ | ||||||
|  | +	if (err == 0) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	if (err != 1) | ||||||
|  | +		return err; | ||||||
|  | + | ||||||
|  | +	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | ||||||
|  | +	if (!ctx) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	ctx->pdev = pdev; | ||||||
|  | +	ctx->resume = do_resume; | ||||||
|  | +	ctx->id = id; | ||||||
|  | + | ||||||
|  | +	pci_dev_get(pdev); | ||||||
|  | +	err = request_firmware_nowait(THIS_MODULE, 1, entry->firmware_name, | ||||||
|  | +		&pdev->dev, GFP_KERNEL, ctx, renesas_fw_callback); | ||||||
|  | +	if (err) { | ||||||
|  | +		pci_dev_put(pdev); | ||||||
|  | +		return err; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The renesas_fw_callback() callback will continue the probe | ||||||
|  | +	 * process, once it aquires the firmware. | ||||||
|  | +	 */ | ||||||
|  | +	return 1; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* called during probe() after chip reset completes */ | ||||||
|  |  static int xhci_pci_setup(struct usb_hcd *hcd) | ||||||
|  |  { | ||||||
|  | @@ -286,6 +740,22 @@ static int xhci_pci_probe(struct pci_dev | ||||||
|  |  	struct hc_driver *driver; | ||||||
|  |  	struct usb_hcd *hcd; | ||||||
|  |   | ||||||
|  | +	/* | ||||||
|  | +	 * Check if this device is a RENESAS uPD720201/2 device. | ||||||
|  | +	 * Otherwise, we can continue with xhci_pci_probe as usual. | ||||||
|  | +	 */ | ||||||
|  | +	retval = renesas_fw_download_to_hw(dev, id, false); | ||||||
|  | +	switch (retval) { | ||||||
|  | +	case 0: | ||||||
|  | +		break; | ||||||
|  | + | ||||||
|  | +	case 1: /* let it load the firmware and recontinue the probe. */ | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	default: | ||||||
|  | +		return retval; | ||||||
|  | +	}; | ||||||
|  | + | ||||||
|  |  	driver = (struct hc_driver *)id->driver_data; | ||||||
|  |   | ||||||
|  |  	/* Prevent runtime suspending between USB-2 and USB-3 initialization */ | ||||||
|  | @@ -347,6 +817,16 @@ static void xhci_pci_remove(struct pci_d | ||||||
|  |  { | ||||||
|  |  	struct xhci_hcd *xhci; | ||||||
|  |   | ||||||
|  | +	if (renesas_fw_alive_check(dev)) { | ||||||
|  | +		/* | ||||||
|  | +		 * bail out early, if this was a renesas device w/o FW. | ||||||
|  | +		 * Else we might hit the NMI watchdog in xhci_handsake | ||||||
|  | +		 * during xhci_reset as part of the driver's unloading. | ||||||
|  | +		 * which we forced in the renesas_fw_callback(). | ||||||
|  | +		 */ | ||||||
|  | +		return; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	xhci = hcd_to_xhci(pci_get_drvdata(dev)); | ||||||
|  |  	xhci->xhc_state |= XHCI_STATE_REMOVING; | ||||||
|  |  	if (xhci->shared_hcd) { | ||||||
| @@ -0,0 +1,53 @@ | |||||||
|  | From a0dc613140bab907a3d5787a7ae7b0638bf674d0 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | Date: Thu, 23 Jun 2016 20:28:20 +0200 | ||||||
|  | Subject: [PATCH] usb: xhci: force MSI for uPD720201 and | ||||||
|  |  uPD720202 | ||||||
|  |  | ||||||
|  | The APM82181 does not support MSI-X. When probed, it will | ||||||
|  | produce a noisy warning. | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  drivers/usb/host/pci-quirks.c | 362 ++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 362 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/usb/host/xhci-pci.c | ||||||
|  | +++ b/drivers/usb/host/xhci-pci.c | ||||||
|  | @@ -206,6 +206,7 @@ static void xhci_pci_quirks(struct devic | ||||||
|  |  	    pdev->device == 0x0015) { | ||||||
|  |  		xhci->quirks |= XHCI_RESET_ON_RESUME; | ||||||
|  |  		xhci->quirks |= XHCI_ZERO_64B_REGS; | ||||||
|  | +		xhci->quirks |= XHCI_FORCE_MSI; | ||||||
|  |  	} | ||||||
|  |  	if (pdev->vendor == PCI_VENDOR_ID_VIA) | ||||||
|  |  		xhci->quirks |= XHCI_RESET_ON_RESUME; | ||||||
|  | --- a/drivers/usb/host/xhci.c | ||||||
|  | +++ b/drivers/usb/host/xhci.c | ||||||
|  | @@ -424,10 +424,14 @@ static int xhci_try_enable_msi(struct us | ||||||
|  |  		free_irq(hcd->irq, hcd); | ||||||
|  |  	hcd->irq = 0; | ||||||
|  |   | ||||||
|  | -	ret = xhci_setup_msix(xhci); | ||||||
|  | -	if (ret) | ||||||
|  | -		/* fall back to msi*/ | ||||||
|  | +	if (xhci->quirks & XHCI_FORCE_MSI) { | ||||||
|  |  		ret = xhci_setup_msi(xhci); | ||||||
|  | +	} else { | ||||||
|  | +		ret = xhci_setup_msix(xhci); | ||||||
|  | +		if (ret) | ||||||
|  | +			/* fall back to msi*/ | ||||||
|  | +			ret = xhci_setup_msi(xhci); | ||||||
|  | +	} | ||||||
|  |   | ||||||
|  |  	if (!ret) { | ||||||
|  |  		hcd->msi_enabled = 1; | ||||||
|  | --- a/drivers/usb/host/xhci.h | ||||||
|  | +++ b/drivers/usb/host/xhci.h | ||||||
|  | @@ -1857,6 +1857,7 @@ struct xhci_hcd { | ||||||
|  |  	/* support xHCI 0.96 spec USB2 software LPM */ | ||||||
|  |  	unsigned		sw_lpm_support:1; | ||||||
|  |  	/* support xHCI 1.0 spec USB2 hardware LPM */ | ||||||
|  | +#define XHCI_FORCE_MSI		(1 << 24) | ||||||
|  |  	unsigned		hw_lpm_support:1; | ||||||
|  |  	/* cached usb2 extened protocol capabilites */ | ||||||
|  |  	u32                     *ext_caps; | ||||||
| @@ -0,0 +1,65 @@ | |||||||
|  | From 694f9bfb8efaef8a33e8992015ff9d0866faf4a2 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | Date: Sun, 17 Dec 2017 17:27:15 +0100 | ||||||
|  | Subject: [PATCH 1/2] hwmon: tc654 add detection routine | ||||||
|  |  | ||||||
|  | This patch adds a detection routine for the TC654/TC655 | ||||||
|  | chips.  Both IDs are listed in the Datasheet. | ||||||
|  |  | ||||||
|  | Signed-off-by: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | --- | ||||||
|  |  drivers/hwmon/tc654.c | 29 +++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 29 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/hwmon/tc654.c | ||||||
|  | +++ b/drivers/hwmon/tc654.c | ||||||
|  | @@ -64,6 +64,11 @@ enum tc654_regs { | ||||||
|  |  /* Register data is read (and cached) at most once per second. */ | ||||||
|  |  #define TC654_UPDATE_INTERVAL		HZ | ||||||
|  |   | ||||||
|  | +/* Manufacturer and Version Identification Register Values */ | ||||||
|  | +#define TC654_MFR_ID_MICROCHIP		0x84 | ||||||
|  | +#define TC654_VER_ID			0x00 | ||||||
|  | +#define TC655_VER_ID			0x01 | ||||||
|  | + | ||||||
|  |  struct tc654_data { | ||||||
|  |  	struct i2c_client *client; | ||||||
|  |   | ||||||
|  | @@ -497,6 +502,29 @@ static const struct i2c_device_id tc654_ | ||||||
|  |  	{} | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +static int | ||||||
|  | +tc654_detect(struct i2c_client *new_client, struct i2c_board_info *info) | ||||||
|  | +{ | ||||||
|  | +	struct i2c_adapter *adapter = new_client->adapter; | ||||||
|  | +	int manufacturer, product; | ||||||
|  | + | ||||||
|  | +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	manufacturer = i2c_smbus_read_byte_data(new_client, TC654_REG_MFR_ID); | ||||||
|  | +	if (manufacturer != TC654_MFR_ID_MICROCHIP) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	product = i2c_smbus_read_byte_data(new_client, TC654_REG_VER_ID); | ||||||
|  | +	if (!((product == TC654_VER_ID) || (product == TC655_VER_ID))) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	strlcpy(info->type, product == TC654_VER_ID ? "tc654" : "tc655", | ||||||
|  | +		I2C_NAME_SIZE); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  MODULE_DEVICE_TABLE(i2c, tc654_id); | ||||||
|  |   | ||||||
|  |  static struct i2c_driver tc654_driver = { | ||||||
|  | @@ -505,6 +533,7 @@ static struct i2c_driver tc654_driver = | ||||||
|  |  		   }, | ||||||
|  |  	.probe = tc654_probe, | ||||||
|  |  	.id_table = tc654_id, | ||||||
|  | +	.detect = tc654_detect, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  module_i2c_driver(tc654_driver); | ||||||
| @@ -0,0 +1,174 @@ | |||||||
|  | From 15ae701189744d321d3a1264ff46f8871e8765ee Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | Date: Sun, 17 Dec 2017 17:29:13 +0100 | ||||||
|  | Subject: [PATCH] hwmon: tc654: add thermal_cooling device | ||||||
|  |  | ||||||
|  | This patch adds a thermaL_cooling device to the tc654 driver. | ||||||
|  | This allows the chip to be used for DT-based cooling. | ||||||
|  |  | ||||||
|  | Signed-off-by: Christian Lamparter <chunkeey@gmail.com> | ||||||
|  | --- | ||||||
|  |  drivers/hwmon/tc654.c | 103 +++++++++++++++++++++++++++++++++++++++++--------- | ||||||
|  |  1 file changed, 86 insertions(+), 17 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/hwmon/tc654.c | ||||||
|  | +++ b/drivers/hwmon/tc654.c | ||||||
|  | @@ -24,6 +24,7 @@ | ||||||
|  |  #include <linux/module.h> | ||||||
|  |  #include <linux/mutex.h> | ||||||
|  |  #include <linux/slab.h> | ||||||
|  | +#include <linux/thermal.h> | ||||||
|  |  #include <linux/util_macros.h> | ||||||
|  |   | ||||||
|  |  enum tc654_regs { | ||||||
|  | @@ -141,6 +142,9 @@ struct tc654_data { | ||||||
|  |  			 * writable register used to control the duty | ||||||
|  |  			 * cycle of the V OUT output. | ||||||
|  |  			 */ | ||||||
|  | + | ||||||
|  | +	/* optional cooling device */ | ||||||
|  | +	struct thermal_cooling_device *cdev; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /* helper to grab and cache data, at most one time per second */ | ||||||
|  | @@ -376,36 +380,30 @@ static ssize_t set_pwm_mode(struct devic | ||||||
|  |  static const int tc654_pwm_map[16] = { 77,  88, 102, 112, 124, 136, 148, 160, | ||||||
|  |  				      172, 184, 196, 207, 219, 231, 243, 255}; | ||||||
|  |   | ||||||
|  | +static int get_pwm(struct tc654_data *data) | ||||||
|  | +{ | ||||||
|  | +	if (data->config & TC654_REG_CONFIG_SDM) | ||||||
|  | +		return 0; | ||||||
|  | +	else | ||||||
|  | +		return tc654_pwm_map[data->duty_cycle]; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static ssize_t show_pwm(struct device *dev, struct device_attribute *da, | ||||||
|  |  			char *buf) | ||||||
|  |  { | ||||||
|  |  	struct tc654_data *data = tc654_update_client(dev); | ||||||
|  | -	int pwm; | ||||||
|  |   | ||||||
|  |  	if (IS_ERR(data)) | ||||||
|  |  		return PTR_ERR(data); | ||||||
|  |   | ||||||
|  | -	if (data->config & TC654_REG_CONFIG_SDM) | ||||||
|  | -		pwm = 0; | ||||||
|  | -	else | ||||||
|  | -		pwm = tc654_pwm_map[data->duty_cycle]; | ||||||
|  | - | ||||||
|  | -	return sprintf(buf, "%d\n", pwm); | ||||||
|  | +	return sprintf(buf, "%d\n", get_pwm(data)); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static ssize_t set_pwm(struct device *dev, struct device_attribute *da, | ||||||
|  | -		       const char *buf, size_t count) | ||||||
|  | +static int _set_pwm(struct tc654_data *data, unsigned long val) | ||||||
|  |  { | ||||||
|  | -	struct tc654_data *data = dev_get_drvdata(dev); | ||||||
|  |  	struct i2c_client *client = data->client; | ||||||
|  | -	unsigned long val; | ||||||
|  |  	int ret; | ||||||
|  |   | ||||||
|  | -	if (kstrtoul(buf, 10, &val)) | ||||||
|  | -		return -EINVAL; | ||||||
|  | -	if (val > 255) | ||||||
|  | -		return -EINVAL; | ||||||
|  | - | ||||||
|  |  	mutex_lock(&data->update_lock); | ||||||
|  |   | ||||||
|  |  	if (val == 0) | ||||||
|  | @@ -425,6 +423,22 @@ static ssize_t set_pwm(struct device *de | ||||||
|  |   | ||||||
|  |  out: | ||||||
|  |  	mutex_unlock(&data->update_lock); | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static ssize_t set_pwm(struct device *dev, struct device_attribute *da, | ||||||
|  | +		       const char *buf, size_t count) | ||||||
|  | +{ | ||||||
|  | +	struct tc654_data *data = dev_get_drvdata(dev); | ||||||
|  | +	unsigned long val; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	if (kstrtoul(buf, 10, &val)) | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	if (val > 255) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	ret = _set_pwm(data, val); | ||||||
|  |  	return ret < 0 ? ret : count; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -462,6 +476,47 @@ static struct attribute *tc654_attrs[] = | ||||||
|  |   | ||||||
|  |  ATTRIBUTE_GROUPS(tc654); | ||||||
|  |   | ||||||
|  | +/* cooling device */ | ||||||
|  | + | ||||||
|  | +static int tc654_get_max_state(struct thermal_cooling_device *cdev, | ||||||
|  | +			       unsigned long *state) | ||||||
|  | +{ | ||||||
|  | +	*state = 255; | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int tc654_get_cur_state(struct thermal_cooling_device *cdev, | ||||||
|  | +                              unsigned long *state) | ||||||
|  | +{ | ||||||
|  | +	struct tc654_data *data = tc654_update_client(cdev->devdata); | ||||||
|  | + | ||||||
|  | +	if (IS_ERR(data)) | ||||||
|  | +		return PTR_ERR(data); | ||||||
|  | + | ||||||
|  | +	*state = get_pwm(data); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int tc654_set_cur_state(struct thermal_cooling_device *cdev, | ||||||
|  | +			       unsigned long state) | ||||||
|  | +{ | ||||||
|  | +	struct tc654_data *data = tc654_update_client(cdev->devdata); | ||||||
|  | + | ||||||
|  | +	if (IS_ERR(data)) | ||||||
|  | +		return PTR_ERR(data); | ||||||
|  | + | ||||||
|  | +	if (state > 255) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	return _set_pwm(data, state); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct thermal_cooling_device_ops tc654_fan_cool_ops = { | ||||||
|  | +	.get_max_state = tc654_get_max_state, | ||||||
|  | +	.get_cur_state = tc654_get_cur_state, | ||||||
|  | +	.set_cur_state = tc654_set_cur_state, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  |  /* | ||||||
|  |   * device probe and removal | ||||||
|  |   */ | ||||||
|  | @@ -493,7 +548,21 @@ static int tc654_probe(struct i2c_client | ||||||
|  |  	hwmon_dev = | ||||||
|  |  	    devm_hwmon_device_register_with_groups(dev, client->name, data, | ||||||
|  |  						   tc654_groups); | ||||||
|  | -	return PTR_ERR_OR_ZERO(hwmon_dev); | ||||||
|  | +	if (IS_ERR(hwmon_dev)) | ||||||
|  | +		return PTR_ERR(hwmon_dev); | ||||||
|  | + | ||||||
|  | +#if IS_ENABLED(CONFIG_OF) | ||||||
|  | +	/* Optional cooling device register for Device tree platforms */ | ||||||
|  | +	data->cdev = thermal_of_cooling_device_register(client->dev.of_node, | ||||||
|  | +							"tc654", hwmon_dev, | ||||||
|  | +							&tc654_fan_cool_ops); | ||||||
|  | +#else /* CONFIG_OF */ | ||||||
|  | +	/* Optional cooling device register for non Device tree platforms */ | ||||||
|  | +	data->cdev = thermal_cooling_device_register("tc654", hwmon_dev, | ||||||
|  | +						     &tc654_fan_cool_ops); | ||||||
|  | +#endif /* CONFIG_OF */ | ||||||
|  | + | ||||||
|  | +	return PTR_ERR_OR_ZERO(data->cdev); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static const struct i2c_device_id tc654_id[] = { | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| # CONFIG_IKAREM is not set |  | ||||||
| CONFIG_APOLLO3G=y | CONFIG_APOLLO3G=y | ||||||
| CONFIG_BROADCOM_PHY=y | CONFIG_BROADCOM_PHY=y | ||||||
| CONFIG_EXT4_FS=y | CONFIG_EXT4_FS=y | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Christian Lamparter
					Christian Lamparter