1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2020, Sean Anderson <seanga2@gmail.com> 4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> 5 * 6 * U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT). 7 * The CLINT block holds memory-mapped control and status registers 8 * associated with software and timer interrupts. 9 */ 10 11#include <dm.h> 12#include <regmap.h> 13#include <syscon.h> 14#include <asm/global_data.h> 15#include <asm/io.h> 16#include <asm/smp.h> 17#include <asm/syscon.h> 18#include <linux/err.h> 19 20/* MSIP registers */ 21#define MSIP_REG(base, hart) ((ulong)(base) + (hart) * 4) 22 23DECLARE_GLOBAL_DATA_PTR; 24 25int riscv_init_ipi(void) 26{ 27 int ret; 28 struct udevice *dev; 29 30 ret = uclass_get_device_by_driver(UCLASS_TIMER, 31 DM_DRIVER_GET(riscv_aclint_timer), &dev); 32 if (ret) 33 return ret; 34 35 if (dev_get_driver_data(dev) != 0) 36 gd->arch.aclint = dev_read_addr_ptr(dev); 37 else 38 gd->arch.aclint = syscon_get_first_range(RISCV_SYSCON_ACLINT); 39 40 if (!gd->arch.aclint) 41 return -EINVAL; 42 43 return 0; 44} 45 46int riscv_send_ipi(int hart) 47{ 48 writel(1, (void __iomem *)MSIP_REG(gd->arch.aclint, hart)); 49 50 return 0; 51} 52 53int riscv_clear_ipi(int hart) 54{ 55 writel(0, (void __iomem *)MSIP_REG(gd->arch.aclint, hart)); 56 57 return 0; 58} 59 60int riscv_get_ipi(int hart, int *pending) 61{ 62 *pending = readl((void __iomem *)MSIP_REG(gd->arch.aclint, hart)); 63 64 return 0; 65} 66 67static const struct udevice_id riscv_aclint_swi_ids[] = { 68 { .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_ACLINT }, 69 { } 70}; 71 72U_BOOT_DRIVER(riscv_aclint_swi) = { 73 .name = "riscv_aclint_swi", 74 .id = UCLASS_SYSCON, 75 .of_match = riscv_aclint_swi_ids, 76 .flags = DM_FLAG_PRE_RELOC, 77}; 78