1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cache Management Operations for StarFive's Starlink cache controller 4 * 5 * Copyright (C) 2024 Shanghai StarFive Technology Co., Ltd. 6 * 7 * Author: Joshua Yeong <joshua.yeong@starfivetech.com> 8 */ 9 10 #include <linux/bitfield.h> 11 #include <linux/cacheflush.h> 12 #include <linux/iopoll.h> 13 #include <linux/of_address.h> 14 15 #include <asm/dma-noncoherent.h> 16 17 #define STARLINK_CACHE_FLUSH_START_ADDR 0x0 18 #define STARLINK_CACHE_FLUSH_END_ADDR 0x8 19 #define STARLINK_CACHE_FLUSH_CTL 0x10 20 #define STARLINK_CACHE_ALIGN 0x40 21 22 #define STARLINK_CACHE_ADDRESS_RANGE_MASK GENMASK(39, 0) 23 #define STARLINK_CACHE_FLUSH_CTL_MODE_MASK GENMASK(2, 1) 24 #define STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK BIT(0) 25 26 #define STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE 0 27 #define STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE 1 28 #define STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED 2 29 #define STARLINK_CACHE_FLUSH_POLL_DELAY_US 1 30 #define STARLINK_CACHE_FLUSH_TIMEOUT_US 5000000 31 32 static void __iomem *starlink_cache_base; 33 34 static void starlink_cache_flush_complete(void) 35 { 36 volatile void __iomem *ctl = starlink_cache_base + STARLINK_CACHE_FLUSH_CTL; 37 u64 v; 38 int ret; 39 40 ret = readq_poll_timeout_atomic(ctl, v, !(v & STARLINK_CACHE_FLUSH_CTL_ENABLE_MASK), 41 STARLINK_CACHE_FLUSH_POLL_DELAY_US, 42 STARLINK_CACHE_FLUSH_TIMEOUT_US); 43 if (ret) 44 WARN(1, "StarFive Starlink cache flush operation timeout\n"); 45 } 46 47 static void starlink_cache_dma_cache_wback(phys_addr_t paddr, unsigned long size) 48 { 49 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), 50 starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); 51 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), 52 starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); 53 54 mb(); 55 writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, 56 STARLINK_CACHE_FLUSH_CTL_CLEAN_SHARED), 57 starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); 58 59 starlink_cache_flush_complete(); 60 } 61 62 static void starlink_cache_dma_cache_invalidate(phys_addr_t paddr, unsigned long size) 63 { 64 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), 65 starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); 66 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), 67 starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); 68 69 mb(); 70 writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, 71 STARLINK_CACHE_FLUSH_CTL_MAKE_INVALIDATE), 72 starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); 73 74 starlink_cache_flush_complete(); 75 } 76 77 static void starlink_cache_dma_cache_wback_inv(phys_addr_t paddr, unsigned long size) 78 { 79 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr), 80 starlink_cache_base + STARLINK_CACHE_FLUSH_START_ADDR); 81 writeq(FIELD_PREP(STARLINK_CACHE_ADDRESS_RANGE_MASK, paddr + size), 82 starlink_cache_base + STARLINK_CACHE_FLUSH_END_ADDR); 83 84 mb(); 85 writeq(FIELD_PREP(STARLINK_CACHE_FLUSH_CTL_MODE_MASK, 86 STARLINK_CACHE_FLUSH_CTL_CLEAN_INVALIDATE), 87 starlink_cache_base + STARLINK_CACHE_FLUSH_CTL); 88 89 starlink_cache_flush_complete(); 90 } 91 92 static const struct riscv_nonstd_cache_ops starlink_cache_ops = { 93 .wback = &starlink_cache_dma_cache_wback, 94 .inv = &starlink_cache_dma_cache_invalidate, 95 .wback_inv = &starlink_cache_dma_cache_wback_inv, 96 }; 97 98 static const struct of_device_id starlink_cache_ids[] = { 99 { .compatible = "starfive,jh8100-starlink-cache" }, 100 { /* sentinel */ } 101 }; 102 103 static int __init starlink_cache_init(void) 104 { 105 struct device_node *np; 106 u32 block_size; 107 int ret; 108 109 np = of_find_matching_node(NULL, starlink_cache_ids); 110 if (!of_device_is_available(np)) 111 return -ENODEV; 112 113 ret = of_property_read_u32(np, "cache-block-size", &block_size); 114 if (ret) 115 return ret; 116 117 if (block_size % STARLINK_CACHE_ALIGN) 118 return -EINVAL; 119 120 starlink_cache_base = of_iomap(np, 0); 121 if (!starlink_cache_base) 122 return -ENOMEM; 123 124 riscv_cbom_block_size = block_size; 125 riscv_noncoherent_supported(); 126 riscv_noncoherent_register_cache_ops(&starlink_cache_ops); 127 128 return 0; 129 } 130 arch_initcall(starlink_cache_init); 131