1 // SPDX-License-Identifier: GPL-2.0
3 * Cache Management Operations for StarFive's Starlink cache controller
5 * Copyright (C) 2024 Shanghai StarFive Technology Co., Ltd.
7 * Author: Joshua Yeong <joshua.yeong@starfivetech.com>
10 #include <linux/bitfield.h>
11 #include <linux/cacheflush.h>
12 #include <linux/iopoll.h>
13 #include <linux/of_address.h>
15 #include <asm/dma-noncoherent.h>
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
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)
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
32 static void __iomem
*starlink_cache_base
;
34 static void starlink_cache_flush_complete(void)
36 volatile void __iomem
*ctl
= starlink_cache_base
+ STARLINK_CACHE_FLUSH_CTL
;
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
);
44 WARN(1, "StarFive Starlink cache flush operation timeout\n");
47 static void starlink_cache_dma_cache_wback(phys_addr_t paddr
, unsigned long size
)
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
);
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
);
59 starlink_cache_flush_complete();
62 static void starlink_cache_dma_cache_invalidate(phys_addr_t paddr
, unsigned long size
)
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
);
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
);
74 starlink_cache_flush_complete();
77 static void starlink_cache_dma_cache_wback_inv(phys_addr_t paddr
, unsigned long size
)
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
);
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
);
89 starlink_cache_flush_complete();
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
,
98 static const struct of_device_id starlink_cache_ids
[] = {
99 { .compatible
= "starfive,jh8100-starlink-cache" },
103 static int __init
starlink_cache_init(void)
105 struct device_node
*np
;
109 np
= of_find_matching_node(NULL
, starlink_cache_ids
);
110 if (!of_device_is_available(np
))
113 ret
= of_property_read_u32(np
, "cache-block-size", &block_size
);
117 if (block_size
% STARLINK_CACHE_ALIGN
)
120 starlink_cache_base
= of_iomap(np
, 0);
121 if (!starlink_cache_base
)
124 riscv_cbom_block_size
= block_size
;
125 riscv_noncoherent_supported();
126 riscv_noncoherent_register_cache_ops(&starlink_cache_ops
);
130 arch_initcall(starlink_cache_init
);