forked from mirrors/linux
		
	cache: Add StarFive StarLink cache management
Add StarFive Starlink cache management driver. The driver enables RISC-V non-standard cache operation on SoC that does not support Zicbom extension instructions. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
This commit is contained in:
		
							parent
							
								
									c6005d4dd2
								
							
						
					
					
						commit
						cabff60ca7
					
				
					 3 changed files with 142 additions and 2 deletions
				
			
		
							
								
								
									
										9
									
								
								drivers/cache/Kconfig
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								drivers/cache/Kconfig
									
									
									
									
										vendored
									
									
								
							|  | @ -14,4 +14,13 @@ config SIFIVE_CCACHE | ||||||
| 	help | 	help | ||||||
| 	  Support for the composable cache controller on SiFive platforms. | 	  Support for the composable cache controller on SiFive platforms. | ||||||
| 
 | 
 | ||||||
|  | config STARFIVE_STARLINK_CACHE | ||||||
|  | 	bool "StarFive StarLink Cache controller" | ||||||
|  | 	depends on RISCV | ||||||
|  | 	depends on ARCH_STARFIVE | ||||||
|  | 	select RISCV_DMA_NONCOHERENT | ||||||
|  | 	select RISCV_NONSTANDARD_CACHE_OPS | ||||||
|  | 	help | ||||||
|  | 	  Support for the StarLink cache controller IP from StarFive. | ||||||
|  | 
 | ||||||
| endmenu | endmenu | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								drivers/cache/Makefile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								drivers/cache/Makefile
									
									
									
									
										vendored
									
									
								
							|  | @ -2,3 +2,4 @@ | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_AX45MP_L2_CACHE)		+= ax45mp_cache.o | obj-$(CONFIG_AX45MP_L2_CACHE)		+= ax45mp_cache.o | ||||||
| obj-$(CONFIG_SIFIVE_CCACHE)		+= sifive_ccache.o | obj-$(CONFIG_SIFIVE_CCACHE)		+= sifive_ccache.o | ||||||
|  | obj-$(CONFIG_STARFIVE_STARLINK_CACHE)	+= starfive_starlink_cache.o | ||||||
|  |  | ||||||
							
								
								
									
										130
									
								
								drivers/cache/starfive_starlink_cache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								drivers/cache/starfive_starlink_cache.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * Cache Management Operations for StarFive's Starlink cache controller | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2024 Shanghai StarFive Technology Co., Ltd. | ||||||
|  |  * | ||||||
|  |  * Author: Joshua Yeong <joshua.yeong@starfivetech.com> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/bitfield.h> | ||||||
|  | #include <linux/cacheflush.h> | ||||||
|  | #include <linux/iopoll.h> | ||||||
|  | #include <linux/of_address.h> | ||||||
|  | 
 | ||||||
|  | #include <asm/dma-noncoherent.h> | ||||||
|  | 
 | ||||||
|  | #define STARLINK_CACHE_FLUSH_START_ADDR			0x0 | ||||||
|  | #define STARLINK_CACHE_FLUSH_END_ADDR			0x8 | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL			0x10 | ||||||
|  | #define STARLINK_CACHE_ALIGN				0x40 | ||||||
|  | 
 | ||||||
|  | #define STARLINK_CACHE_ADDRESS_RANGE_MASK		GENMASK(39, 0) | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL_MODE_MASK		GENMASK(2, 1) | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK		BIT(0) | ||||||
|  | 
 | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE	0 | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE	1 | ||||||
|  | #define STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED		2 | ||||||
|  | #define STARLINK_CACHE_FLUSH_POLL_DELAY_US		1 | ||||||
|  | #define STARLINK_CACHE_FLUSH_TIMEOUT_US			5000000 | ||||||
|  | 
 | ||||||
|  | static void __iomem *starlink_cache_base; | ||||||
|  | 
 | ||||||
|  | static void starlink_cache_flush_complete(void) | ||||||
|  | { | ||||||
|  | 	volatile void __iomem *ctl = starlink_cache_base + STARLINK_CACHE_FLUSH_CTL; | ||||||
|  | 	u64 v; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = readq_poll_timeout_atomic(ctl, v, !(v & STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK), | ||||||
|  | 					STARLINK_CACHE_FLUSH_POLL_DELAY_US, | ||||||
|  | 					STARLINK_CACHE_FLUSH_TIMEOUT_US); | ||||||
|  | 	if (ret) | ||||||
|  | 		WARN(1, "StarFive Starlink cache flush operation timeout\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void starlink_cache_dma_cache_wback(phys_addr_t paddr, unsigned long size) | ||||||
|  | { | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); | ||||||
|  | 
 | ||||||
|  | 	mb(); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, | ||||||
|  | 			  STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); | ||||||
|  | 
 | ||||||
|  | 	starlink_cache_flush_complete(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void starlink_cache_dma_cache_invalidate(phys_addr_t paddr, unsigned long size) | ||||||
|  | { | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); | ||||||
|  | 
 | ||||||
|  | 	mb(); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, | ||||||
|  | 			  STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); | ||||||
|  | 
 | ||||||
|  | 	starlink_cache_flush_complete(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void starlink_cache_dma_cache_wback_inv(phys_addr_t paddr, unsigned long size) | ||||||
|  | { | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); | ||||||
|  | 
 | ||||||
|  | 	mb(); | ||||||
|  | 	writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, | ||||||
|  | 			  STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE), | ||||||
|  | 	       starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); | ||||||
|  | 
 | ||||||
|  | 	starlink_cache_flush_complete(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct riscv_nonstd_cache_ops starlink_cache_ops = { | ||||||
|  | 	.wback = &starlink_cache_dma_cache_wback, | ||||||
|  | 	.inv = &starlink_cache_dma_cache_invalidate, | ||||||
|  | 	.wback_inv = &starlink_cache_dma_cache_wback_inv, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct of_device_id starlink_cache_ids[] = { | ||||||
|  | 	{ .compatible = "starfive,jh8100-starlink-cache" }, | ||||||
|  | 	{ /* sentinel */ } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int __init starlink_cache_init(void) | ||||||
|  | { | ||||||
|  | 	struct device_node *np; | ||||||
|  | 	u32 block_size; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	np = of_find_matching_node(NULL, starlink_cache_ids); | ||||||
|  | 	if (!of_device_is_available(np)) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	ret = of_property_read_u32(np, "cache-block-size", &block_size); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	if (block_size % STARLINK_CACHE_ALIGN) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	starlink_cache_base = of_iomap(np, 0); | ||||||
|  | 	if (!starlink_cache_base) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	riscv_cbom_block_size = block_size; | ||||||
|  | 	riscv_noncoherent_supported(); | ||||||
|  | 	riscv_noncoherent_register_cache_ops(&starlink_cache_ops); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | arch_initcall(starlink_cache_init); | ||||||
		Loading…
	
		Reference in a new issue
	
	 Joshua Yeong
						Joshua Yeong