1/* 2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8/* tell the kernel we have the set trigger feature */ 9#define HAVE_SET_TRIGGER 1 10 11 12#include <plat/machine/devices_gen.h> 13#include <arch/model/smp.h> 14 15/* The memory map is based on the PLIC section in 16 * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf 17 */ 18 19#define PLIC_PPTR_BASE PLIC_PPTR 20 21 22#define PLIC_HART_ID (CONFIG_FIRST_HART_ID) 23 24#define PLIC_PRIO 0x0 25#define PLIC_PRIO_PER_ID 0x4 26 27#define PLIC_PENDING 0x1000 28#define PLIC_EN 0x2000 29#define PLIC_EN_PER_HART 0x100 30#define PLIC_EN_PER_CONTEXT 0x80 31 32 33#define PLIC_THRES 0x200000 34#define PLIC_SVC_CONTEXT 1 35#define PLIC_THRES_PER_HART 0x2000 36#define PLIC_THRES_PER_CONTEXT 0x1000 37#define PLIC_THRES_CLAIM 0x4 38 39#define PLIC_NUM_INTERRUPTS PLIC_MAX_IRQ 40 41#if defined(CONFIG_PLAT_HIFIVE) || defined(CONFIG_PLAT_POLARFIRE) 42 43/* SiFive U54-MC has 5 cores, and the first core does not 44 * have supervisor mode. Therefore, we need to compensate 45 * for the addresses. 46 */ 47#define PLAT_PLIC_THRES_ADJUST(x) ((x) - PLIC_THRES_PER_CONTEXT) 48#define PLAT_PLIC_EN_ADJUST(x) ((x) - PLIC_EN_PER_CONTEXT) 49 50#else 51 52#define PLAT_PLIC_THRES_ADJUST(x) (x) 53#define PLAT_PLIC_EN_ADJUST(x) (x) 54 55#endif 56 57static inline void write_sie(word_t value) 58{ 59 asm volatile("csrw sie, %0" :: "r"(value)); 60} 61 62static inline word_t read_sie(void) 63{ 64 word_t temp; 65 asm volatile("csrr %0, sie" : "=r"(temp)); 66 return temp; 67} 68 69static inline uint32_t readl(uint64_t addr) 70{ 71 return *((volatile uint32_t *)(addr)); 72} 73 74static inline void writel(uint32_t val, uint64_t addr) 75{ 76 *((volatile uint32_t *)(addr)) = val; 77} 78 79static inline word_t plic_enable_offset(word_t hart_id, word_t context_id) 80{ 81 word_t addr = PLAT_PLIC_EN_ADJUST(PLIC_EN + hart_id * PLIC_EN_PER_HART + context_id * PLIC_EN_PER_CONTEXT); 82 return addr; 83} 84 85 86static inline word_t plic_thres_offset(word_t hart_id, word_t context_id) 87{ 88 word_t addr = PLAT_PLIC_THRES_ADJUST(PLIC_THRES + hart_id * PLIC_THRES_PER_HART + context_id * PLIC_THRES_PER_CONTEXT); 89 return addr; 90} 91 92static inline word_t plic_claim_offset(word_t hart_id, word_t context_id) 93{ 94 word_t addr = plic_thres_offset(hart_id, context_id) + PLIC_THRES_CLAIM; 95 return addr; 96} 97 98static inline bool_t plic_pending_interrupt(word_t interrupt) 99{ 100 word_t addr = PLIC_PPTR_BASE + PLIC_PENDING + (interrupt / 32) * 4; 101 word_t bit = interrupt % 32; 102 if (readl(addr) & BIT(bit)) { 103 return true; 104 } else { 105 return false; 106 } 107} 108 109static inline word_t get_hart_id(void) 110{ 111#ifdef ENABLE_SMP_SUPPORT 112 return cpuIndexToID(getCurrentCPUIndex()); 113#else 114 return CONFIG_FIRST_HART_ID; 115#endif 116} 117 118static inline irq_t plic_get_claim(void) 119{ 120 /* Read the claim register for our HART interrupt context */ 121 word_t hart_id = get_hart_id(); 122 return readl(PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT)); 123} 124 125static inline void plic_complete_claim(irq_t irq) 126{ 127 /* Complete the IRQ claim by writing back to the claim register. */ 128 word_t hart_id = get_hart_id(); 129 writel(irq, PLIC_PPTR_BASE + plic_claim_offset(hart_id, PLIC_SVC_CONTEXT)); 130} 131 132static inline void plic_mask_irq(bool_t disable, irq_t irq) 133{ 134 uint64_t addr = 0; 135 uint32_t val = 0; 136 uint32_t bit = 0; 137 138 word_t hart_id = get_hart_id(); 139 addr = PLIC_PPTR_BASE + plic_enable_offset(hart_id, PLIC_SVC_CONTEXT) + (irq / 32) * 4; 140 bit = irq % 32; 141 142 val = readl(addr); 143 if (disable) { 144 val &= ~BIT(bit); 145 } else { 146 val |= BIT(bit); 147 } 148 writel(val, addr); 149} 150 151static inline void plic_init_hart(void) 152{ 153 154 word_t hart_id = get_hart_id(); 155 156 for (int i = 1; i <= PLIC_NUM_INTERRUPTS; i++) { 157 /* Disable interrupts */ 158 plic_mask_irq(true, i); 159 } 160 161 /* Set threshold to zero */ 162 writel(0, (PLIC_PPTR_BASE + plic_thres_offset(hart_id, PLIC_SVC_CONTEXT))); 163} 164 165static inline void plic_init_controller(void) 166{ 167 168 for (int i = 1; i <= PLIC_NUM_INTERRUPTS; i++) { 169 /* Clear all pending bits */ 170 if (plic_pending_interrupt(i)) { 171 readl(PLIC_PPTR_BASE + plic_claim_offset(PLIC_HART_ID, PLIC_SVC_CONTEXT)); 172 writel(i, PLIC_PPTR_BASE + plic_claim_offset(PLIC_HART_ID, PLIC_SVC_CONTEXT)); 173 } 174 } 175 176 /* Set the priorities of all interrupts to 1 */ 177 for (int i = 1; i <= PLIC_MAX_IRQ + 1; i++) { 178 writel(2, PLIC_PPTR_BASE + PLIC_PRIO + PLIC_PRIO_PER_ID * i); 179 } 180 181} 182 183 184/* 185 * Provide a dummy definition of set trigger as the Hifive platform currently 186 * has all global interrupt positive-level triggered. 187 */ 188static inline void plic_irq_set_trigger(irq_t irq, bool_t edge_triggered) 189{ 190} 191