Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 32static void __iomem *starlink_cache_base;
 33
 34static 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
 47static 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
 62static 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
 77static 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
 92static 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
 98static const struct of_device_id starlink_cache_ids[] = {
 99	{ .compatible = "starfive,jh8100-starlink-cache" },
100	{ /* sentinel */ }
101};
102
103static 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}
130arch_initcall(starlink_cache_init);