initial FW setup for Raven validation
This commit is contained in:
		
							
								
								
									
										252
									
								
								raven/bsp/drivers/fe300prci/fe300prci_driver.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								raven/bsp/drivers/fe300prci/fe300prci_driver.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,252 @@
 | 
			
		||||
// See LICENSE file for license details
 | 
			
		||||
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
 | 
			
		||||
#ifdef PRCI_BASE_ADDR
 | 
			
		||||
#include "fe300prci/fe300prci_driver.h"
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#define rdmcycle(x)  {				       \
 | 
			
		||||
    uint32_t lo, hi, hi2;			       \
 | 
			
		||||
    __asm__ __volatile__ ("1:\n\t"		       \
 | 
			
		||||
			  "csrr %0, mcycleh\n\t"       \
 | 
			
		||||
			  "csrr %1, mcycle\n\t"	       \
 | 
			
		||||
			  "csrr %2, mcycleh\n\t"		\
 | 
			
		||||
			  "bne  %0, %2, 1b\n\t"			\
 | 
			
		||||
			  : "=r" (hi), "=r" (lo), "=r" (hi2)) ;	\
 | 
			
		||||
    *(x) = lo | ((uint64_t) hi << 32); 				\
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  uint32_t start_mtime = CLINT_REG(CLINT_MTIME);
 | 
			
		||||
  uint32_t end_mtime = start_mtime + mtime_ticks + 1;
 | 
			
		||||
 | 
			
		||||
  // Make sure we won't get rollover.
 | 
			
		||||
  while (end_mtime < start_mtime){
 | 
			
		||||
    start_mtime = CLINT_REG(CLINT_MTIME);
 | 
			
		||||
    end_mtime = start_mtime + mtime_ticks + 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Don't start measuring until mtime edge.
 | 
			
		||||
  uint32_t tmp = start_mtime;
 | 
			
		||||
  do {
 | 
			
		||||
    start_mtime = CLINT_REG(CLINT_MTIME);
 | 
			
		||||
  } while (start_mtime == tmp);
 | 
			
		||||
  
 | 
			
		||||
  uint64_t start_mcycle;
 | 
			
		||||
  rdmcycle(&start_mcycle);
 | 
			
		||||
  
 | 
			
		||||
  while (CLINT_REG(CLINT_MTIME) < end_mtime) ;
 | 
			
		||||
  
 | 
			
		||||
  uint64_t end_mcycle;
 | 
			
		||||
  rdmcycle(&end_mcycle);
 | 
			
		||||
  uint32_t difference = (uint32_t) (end_mcycle - start_mcycle);
 | 
			
		||||
 | 
			
		||||
  uint64_t freq = ((uint64_t) difference * mtime_freq) / mtime_ticks;
 | 
			
		||||
  return (uint32_t) freq & 0xFFFFFFFF;
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
void PRCI_use_hfrosc(int div, int trim)
 | 
			
		||||
{
 | 
			
		||||
  // Make sure the HFROSC is running at its default setting
 | 
			
		||||
  // It is OK to change this even if we are running off of it.
 | 
			
		||||
  
 | 
			
		||||
  PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
 | 
			
		||||
 | 
			
		||||
  while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0);
 | 
			
		||||
  
 | 
			
		||||
  PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PRCI_use_pll(int refsel, int bypass,
 | 
			
		||||
			 int r, int f, int q, int finaldiv,
 | 
			
		||||
			 int hfroscdiv, int hfrosctrim)
 | 
			
		||||
{
 | 
			
		||||
  // Ensure that we aren't running off the PLL before we mess with it.
 | 
			
		||||
  if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
 | 
			
		||||
    // Make sure the HFROSC is running at its default setting
 | 
			
		||||
    PRCI_use_hfrosc(4, 16);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Set PLL Source to be HFXOSC if desired.
 | 
			
		||||
  uint32_t config_value = 0;
 | 
			
		||||
 | 
			
		||||
  config_value |= PLL_REFSEL(refsel);
 | 
			
		||||
  
 | 
			
		||||
  if (bypass) {
 | 
			
		||||
    // Bypass
 | 
			
		||||
    config_value |= PLL_BYPASS(1);
 | 
			
		||||
 | 
			
		||||
    PRCI_REG(PRCI_PLLCFG) = config_value;
 | 
			
		||||
 | 
			
		||||
    // If we don't have an HFXTAL, this doesn't really matter.
 | 
			
		||||
    // Set our Final output divide to divide-by-1:
 | 
			
		||||
    PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
 | 
			
		||||
  } else {
 | 
			
		||||
  
 | 
			
		||||
    // To overclock, use the hfrosc
 | 
			
		||||
    if (hfrosctrim >= 0 && hfroscdiv >= 0) {
 | 
			
		||||
      PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Set DIV Settings for PLL
 | 
			
		||||
    
 | 
			
		||||
    // (Legal values of f_REF are 6-48MHz)
 | 
			
		||||
 | 
			
		||||
    // Set DIVR to divide-by-2 to get 8MHz frequency
 | 
			
		||||
    // (legal values of f_R are 6-12 MHz)
 | 
			
		||||
 | 
			
		||||
    config_value |= PLL_BYPASS(1);
 | 
			
		||||
    config_value |= PLL_R(r);
 | 
			
		||||
 | 
			
		||||
    // Set DIVF to get 512Mhz frequncy
 | 
			
		||||
    // There is an implied multiply-by-2, 16Mhz.
 | 
			
		||||
    // So need to write 32-1
 | 
			
		||||
    // (legal values of f_F are 384-768 MHz)
 | 
			
		||||
    config_value |= PLL_F(f);
 | 
			
		||||
 | 
			
		||||
    // Set DIVQ to divide-by-2 to get 256 MHz frequency
 | 
			
		||||
    // (legal values of f_Q are 50-400Mhz)
 | 
			
		||||
    config_value |= PLL_Q(q);
 | 
			
		||||
 | 
			
		||||
    // Set our Final output divide to divide-by-1:
 | 
			
		||||
    if (finaldiv == 1){
 | 
			
		||||
      PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
 | 
			
		||||
    } else {
 | 
			
		||||
      PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV(finaldiv-1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PRCI_REG(PRCI_PLLCFG) = config_value;
 | 
			
		||||
 | 
			
		||||
    // Un-Bypass the PLL.
 | 
			
		||||
    PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
 | 
			
		||||
 | 
			
		||||
    // Wait for PLL Lock
 | 
			
		||||
    // Note that the Lock signal can be glitchy.
 | 
			
		||||
    // Need to wait 100 us
 | 
			
		||||
    // RTC is running at 32kHz.
 | 
			
		||||
    // So wait 4 ticks of RTC.
 | 
			
		||||
    uint32_t now = CLINT_REG(CLINT_MTIME);
 | 
			
		||||
    while (CLINT_REG(CLINT_MTIME) - now < 4) ;
 | 
			
		||||
    
 | 
			
		||||
    // Now it is safe to check for PLL Lock
 | 
			
		||||
    while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0);
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Switch over to PLL Clock source
 | 
			
		||||
  PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
 | 
			
		||||
 | 
			
		||||
  // If we're running off HFXOSC, turn off the HFROSC to
 | 
			
		||||
  // save power.
 | 
			
		||||
  if (refsel) {
 | 
			
		||||
    PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PRCI_use_default_clocks()
 | 
			
		||||
{
 | 
			
		||||
  // Turn off the LFROSC
 | 
			
		||||
  AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
 | 
			
		||||
 | 
			
		||||
  // Use HFROSC
 | 
			
		||||
  PRCI_use_hfrosc(4, 16);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PRCI_use_hfxosc(uint32_t finaldiv)
 | 
			
		||||
{
 | 
			
		||||
  
 | 
			
		||||
  PRCI_use_pll(1, // Use HFXTAL
 | 
			
		||||
	       1, // Bypass = 1
 | 
			
		||||
	       0, // PLL settings don't matter
 | 
			
		||||
	       0, // PLL settings don't matter
 | 
			
		||||
	       0, // PLL settings don't matter
 | 
			
		||||
	       finaldiv,
 | 
			
		||||
	       -1,
 | 
			
		||||
	       -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is a generic function, which
 | 
			
		||||
// doesn't span the entire range of HFROSC settings.
 | 
			
		||||
// It only adjusts the trim, which can span a hundred MHz or so.
 | 
			
		||||
// This function does not check the legality of the PLL settings
 | 
			
		||||
// at all, and it is quite possible to configure invalid PLL settings
 | 
			
		||||
// this way.
 | 
			
		||||
// It returns the actual measured CPU frequency.
 | 
			
		||||
 | 
			
		||||
uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target )
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  uint32_t hfrosctrim = 0;
 | 
			
		||||
  uint32_t hfroscdiv = 4;
 | 
			
		||||
  uint32_t prev_trim = 0;
 | 
			
		||||
 | 
			
		||||
  // In this function we use PLL settings which
 | 
			
		||||
  // will give us a 32x multiplier from the output
 | 
			
		||||
  // of the HFROSC source to the output of the
 | 
			
		||||
  // PLL. We first measure our HFROSC to get the
 | 
			
		||||
  // right trim, then finally use it as the PLL source.
 | 
			
		||||
  // We should really check here that the f_cpu
 | 
			
		||||
  // requested is something in the limit of the PLL. For
 | 
			
		||||
  // now that is up to the user.
 | 
			
		||||
 | 
			
		||||
  // This will undershoot for frequencies not divisible by 16.
 | 
			
		||||
  uint32_t desired_hfrosc_freq = (f_cpu/ 16);
 | 
			
		||||
 | 
			
		||||
  PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
 | 
			
		||||
  
 | 
			
		||||
  // Ignore the first run (for icache reasons)
 | 
			
		||||
  uint32_t cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
 | 
			
		||||
 | 
			
		||||
  cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
 | 
			
		||||
  uint32_t prev_freq = cpu_freq;
 | 
			
		||||
  
 | 
			
		||||
  while ((cpu_freq < desired_hfrosc_freq) && (hfrosctrim < 0x1F)){
 | 
			
		||||
    prev_trim = hfrosctrim;
 | 
			
		||||
    prev_freq = cpu_freq;
 | 
			
		||||
    hfrosctrim ++;
 | 
			
		||||
    PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
 | 
			
		||||
    cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
 | 
			
		||||
  } 
 | 
			
		||||
 | 
			
		||||
  // We couldn't go low enough
 | 
			
		||||
  if (prev_freq > desired_hfrosc_freq){
 | 
			
		||||
    PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
 | 
			
		||||
    cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ);
 | 
			
		||||
    return cpu_freq;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // We couldn't go high enough
 | 
			
		||||
  if (cpu_freq < desired_hfrosc_freq){
 | 
			
		||||
    PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
 | 
			
		||||
    cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ);
 | 
			
		||||
    return cpu_freq;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Check for over/undershoot
 | 
			
		||||
  switch(target) {
 | 
			
		||||
  case(PRCI_FREQ_CLOSEST):
 | 
			
		||||
    if ((desired_hfrosc_freq - prev_freq) < (cpu_freq - desired_hfrosc_freq)) {
 | 
			
		||||
      PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
 | 
			
		||||
    } else {
 | 
			
		||||
      PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, hfrosctrim);
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  case(PRCI_FREQ_UNDERSHOOT):
 | 
			
		||||
    PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, hfrosctrim);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cpu_freq =  PRCI_measure_mcycle_freq(1000, RTC_FREQ);
 | 
			
		||||
  return cpu_freq;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										79
									
								
								raven/bsp/drivers/fe300prci/fe300prci_driver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								raven/bsp/drivers/fe300prci/fe300prci_driver.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
// See LICENSE file for license details
 | 
			
		||||
 | 
			
		||||
#ifndef _FE300PRCI_DRIVER_H_
 | 
			
		||||
#define _FE300PRCI_DRIVER_H_
 | 
			
		||||
 | 
			
		||||
__BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
typedef enum prci_freq_target {
 | 
			
		||||
  
 | 
			
		||||
  PRCI_FREQ_OVERSHOOT,
 | 
			
		||||
  PRCI_FREQ_CLOSEST,
 | 
			
		||||
  PRCI_FREQ_UNDERSHOOT
 | 
			
		||||
 | 
			
		||||
} PRCI_freq_target;
 | 
			
		||||
 | 
			
		||||
/* Measure and return the approximate frequency of the 
 | 
			
		||||
 * CPU, as given by measuring the mcycle counter against 
 | 
			
		||||
 * the mtime ticks.
 | 
			
		||||
 */
 | 
			
		||||
uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq);
 | 
			
		||||
 | 
			
		||||
/* Safely switch over to the HFROSC using the given div
 | 
			
		||||
 * and trim settings.
 | 
			
		||||
 */
 | 
			
		||||
void PRCI_use_hfrosc(int div, int trim);
 | 
			
		||||
 | 
			
		||||
/* Safely switch over to the 16MHz HFXOSC,
 | 
			
		||||
 * applying the finaldiv clock divider (1 is the lowest
 | 
			
		||||
 * legal value).
 | 
			
		||||
 */
 | 
			
		||||
void PRCI_use_hfxosc(uint32_t finaldiv);
 | 
			
		||||
 | 
			
		||||
/* Safely switch over to the PLL using the given
 | 
			
		||||
 * settings.
 | 
			
		||||
 * 
 | 
			
		||||
 * Note that not all combinations of the inputs are actually
 | 
			
		||||
 * legal, and this function does not check for their
 | 
			
		||||
 * legality ("safely" means that this function won't turn off
 | 
			
		||||
 * or glitch the clock the CPU is actually running off, but
 | 
			
		||||
 * doesn't protect against you making it too fast or slow.)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void PRCI_use_pll(int refsel, int bypass,
 | 
			
		||||
			 int r, int f, int q, int finaldiv,
 | 
			
		||||
			 int hfroscdiv, int hfrosctrim);
 | 
			
		||||
 | 
			
		||||
/* Use the default clocks configured at reset.
 | 
			
		||||
 * This is ~16Mhz HFROSC and turns off the LFROSC
 | 
			
		||||
 * (on the current FE310 Dev Platforms, an external LFROSC is 
 | 
			
		||||
 * used as it is more power efficient).
 | 
			
		||||
 */
 | 
			
		||||
void PRCI_use_default_clocks();
 | 
			
		||||
 | 
			
		||||
/* This routine will adjust the HFROSC trim
 | 
			
		||||
 * while using HFROSC as the clock source, 
 | 
			
		||||
 * measure the resulting frequency, then
 | 
			
		||||
 * use it as the PLL clock source, 
 | 
			
		||||
 * in an attempt to get over, under, or close to the 
 | 
			
		||||
 * requested frequency. It returns the actual measured 
 | 
			
		||||
 * frequency. 
 | 
			
		||||
 *
 | 
			
		||||
 * Note that the requested frequency must be within the 
 | 
			
		||||
 * range supported by the PLL so not all values are 
 | 
			
		||||
 * achievable with this function, and not all 
 | 
			
		||||
 * are guaranteed to actually work. The PLL
 | 
			
		||||
 * is rated higher than the hardware.
 | 
			
		||||
 * 
 | 
			
		||||
 * There is no check on the desired f_cpu frequency, it
 | 
			
		||||
 * is up to the user to specify something reasonable.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target);
 | 
			
		||||
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
  
 | 
			
		||||
							
								
								
									
										127
									
								
								raven/bsp/drivers/plic/plic_driver.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								raven/bsp/drivers/plic/plic_driver.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
// See LICENSE for license details.
 | 
			
		||||
 | 
			
		||||
#include "sifive/devices/plic.h"
 | 
			
		||||
#include "plic/plic_driver.h"
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
#include "encoding.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Note that there are no assertions or bounds checking on these
 | 
			
		||||
// parameter values.
 | 
			
		||||
 | 
			
		||||
void volatile_memzero(uint8_t * base, unsigned int size)
 | 
			
		||||
{
 | 
			
		||||
  volatile uint8_t * ptr;
 | 
			
		||||
  for (ptr = base; ptr < (base + size); ptr++){
 | 
			
		||||
    *ptr = 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PLIC_init (
 | 
			
		||||
                plic_instance_t * this_plic,
 | 
			
		||||
                uintptr_t         base_addr,
 | 
			
		||||
                uint32_t num_sources,
 | 
			
		||||
                uint32_t num_priorities
 | 
			
		||||
                )
 | 
			
		||||
{
 | 
			
		||||
  
 | 
			
		||||
  this_plic->base_addr = base_addr;
 | 
			
		||||
  this_plic->num_sources = num_sources;
 | 
			
		||||
  this_plic->num_priorities = num_priorities;
 | 
			
		||||
  
 | 
			
		||||
  // Disable all interrupts (don't assume that these registers are reset).
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);
 | 
			
		||||
  volatile_memzero((uint8_t*) (this_plic->base_addr +
 | 
			
		||||
                               PLIC_ENABLE_OFFSET +
 | 
			
		||||
                               (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)),
 | 
			
		||||
                   (num_sources + 8) / 8);
 | 
			
		||||
  
 | 
			
		||||
  // Set all priorities to 0 (equal priority -- don't assume that these are reset).
 | 
			
		||||
  volatile_memzero ((uint8_t *)(this_plic->base_addr +
 | 
			
		||||
                                PLIC_PRIORITY_OFFSET),
 | 
			
		||||
                    (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE);
 | 
			
		||||
 | 
			
		||||
  // Set the threshold to 0.
 | 
			
		||||
  volatile plic_threshold* threshold = (plic_threshold*)
 | 
			
		||||
    (this_plic->base_addr +
 | 
			
		||||
     PLIC_THRESHOLD_OFFSET +
 | 
			
		||||
     (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
 | 
			
		||||
 | 
			
		||||
  *threshold = 0;
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PLIC_set_threshold (plic_instance_t * this_plic,
 | 
			
		||||
			 plic_threshold threshold){
 | 
			
		||||
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);  
 | 
			
		||||
  volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr +
 | 
			
		||||
                                                              PLIC_THRESHOLD_OFFSET +
 | 
			
		||||
                                                              (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
 | 
			
		||||
 | 
			
		||||
  *threshold_ptr = threshold;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){
 | 
			
		||||
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);
 | 
			
		||||
  volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr +
 | 
			
		||||
                                                        PLIC_ENABLE_OFFSET +
 | 
			
		||||
                                                        (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
 | 
			
		||||
                                                        (source >> 3));
 | 
			
		||||
  uint8_t current = *current_ptr;
 | 
			
		||||
  current = current | ( 1 << (source & 0x7));
 | 
			
		||||
  *current_ptr = current;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){
 | 
			
		||||
  
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);
 | 
			
		||||
  volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr +
 | 
			
		||||
                                                         PLIC_ENABLE_OFFSET +
 | 
			
		||||
                                                         (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
 | 
			
		||||
                                                         (source >> 3));
 | 
			
		||||
  uint8_t current = *current_ptr;
 | 
			
		||||
  current = current & ~(( 1 << (source & 0x7)));
 | 
			
		||||
  *current_ptr = current;
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){
 | 
			
		||||
 | 
			
		||||
  if (this_plic->num_priorities > 0) {
 | 
			
		||||
    volatile plic_priority * priority_ptr = (volatile plic_priority *)
 | 
			
		||||
      (this_plic->base_addr +
 | 
			
		||||
       PLIC_PRIORITY_OFFSET +
 | 
			
		||||
       (source << PLIC_PRIORITY_SHIFT_PER_SOURCE));
 | 
			
		||||
    *priority_ptr = priority;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){
 | 
			
		||||
  
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);
 | 
			
		||||
 | 
			
		||||
  volatile plic_source * claim_addr = (volatile plic_source * )
 | 
			
		||||
    (this_plic->base_addr +
 | 
			
		||||
     PLIC_CLAIM_OFFSET +
 | 
			
		||||
     (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
 | 
			
		||||
 | 
			
		||||
  return  *claim_addr;
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){
 | 
			
		||||
  
 | 
			
		||||
  unsigned long hart_id = read_csr(mhartid);
 | 
			
		||||
  volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr +
 | 
			
		||||
                                                                PLIC_CLAIM_OFFSET +
 | 
			
		||||
                                                                (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
 | 
			
		||||
  *claim_addr = source;
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								raven/bsp/drivers/plic/plic_driver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								raven/bsp/drivers/plic/plic_driver.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
// See LICENSE file for licence details
 | 
			
		||||
 | 
			
		||||
#ifndef PLIC_DRIVER_H
 | 
			
		||||
#define PLIC_DRIVER_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#include "platform.h"
 | 
			
		||||
 | 
			
		||||
typedef struct __plic_instance_t
 | 
			
		||||
{
 | 
			
		||||
  uintptr_t base_addr;
 | 
			
		||||
 | 
			
		||||
  uint32_t num_sources;
 | 
			
		||||
  uint32_t num_priorities;
 | 
			
		||||
  
 | 
			
		||||
} plic_instance_t;
 | 
			
		||||
 | 
			
		||||
typedef uint32_t plic_source;
 | 
			
		||||
typedef uint32_t plic_priority;
 | 
			
		||||
typedef uint32_t plic_threshold;
 | 
			
		||||
 | 
			
		||||
void PLIC_init (
 | 
			
		||||
                plic_instance_t * this_plic,
 | 
			
		||||
                uintptr_t         base_addr,
 | 
			
		||||
                uint32_t num_sources,
 | 
			
		||||
                uint32_t num_priorities
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
void PLIC_set_threshold (plic_instance_t * this_plic,
 | 
			
		||||
			 plic_threshold threshold);
 | 
			
		||||
  
 | 
			
		||||
void PLIC_enable_interrupt (plic_instance_t * this_plic,
 | 
			
		||||
			    plic_source source);
 | 
			
		||||
 | 
			
		||||
void PLIC_disable_interrupt (plic_instance_t * this_plic,
 | 
			
		||||
			     plic_source source);
 | 
			
		||||
  
 | 
			
		||||
void PLIC_set_priority (plic_instance_t * this_plic,
 | 
			
		||||
			plic_source source,
 | 
			
		||||
			plic_priority priority);
 | 
			
		||||
 | 
			
		||||
plic_source PLIC_claim_interrupt(plic_instance_t * this_plic);
 | 
			
		||||
 | 
			
		||||
void PLIC_complete_interrupt(plic_instance_t * this_plic,
 | 
			
		||||
			     plic_source source);
 | 
			
		||||
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user