1/** 2 * \file 3 * \brief Platform code for the Cortex-A9 MPCore. 4 */ 5 6/* 7 * Copyright (c) 2016 ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <maps/a9mpcore_map.h> 16#include <a9_scu.h> 17#include <a9_gt.h> 18#include <gic.h> 19#include <dev/cortex_a9_pit_dev.h> 20#include <assert.h> 21#include <cp15.h> 22#include <kernel.h> 23#include <init.h> 24#include <paging_kernel_arch.h> 25#include <arch/arm/platform.h> 26#include <systime.h> 27#include <arch/armv7/irq.h> 28 29#define MSG(format, ...) \ 30 printk( LOG_NOTE, "CortexA9 platform: "format, ## __VA_ARGS__ ) 31 32/* These are called from the A9/A15 common GIC (interrupt controller) code. */ 33 34lpaddr_t platform_gic_cpu_interface_base = A9MPCORE_GIC_CPU_OFFSET; 35lpaddr_t platform_gic_distributor_base = A9MPCORE_GIC_DIST_OFFSET; 36 37/* These are for A9-specific devices, so are only used here. */ 38 39static lpaddr_t 40platform_get_scu_address(void) { 41 assert(paging_mmu_enabled()); 42 return platform_get_private_region() + A9MPCORE_SCU_OFFSET; 43} 44 45static lpaddr_t 46platform_get_gt_address(void) { 47 assert(paging_mmu_enabled()); 48 return platform_get_private_region() + A9MPCORE_TIMER_GBL_OFFSET; 49} 50 51static lpaddr_t 52platform_get_lt_address(void) { 53 assert(paging_mmu_enabled()); 54 return platform_get_private_region() + A9MPCORE_TIMER_LCL_OFFSET; 55} 56 57/* On the A9, we need to initialise the snoop control unit. */ 58void 59platform_revision_init(void) { 60 assert(paging_mmu_enabled()); 61 a9_scu_init(platform_get_scu_address()); 62 platform_gic_cpu_interface_base += platform_get_private_region(); 63 platform_gic_distributor_base += platform_get_private_region(); 64 if(platform_get_core_count() > 1) a9_scu_enable(); 65} 66 67/* 68 * Return the core count from the interrupt controller 69 */ 70size_t 71platform_get_core_count(void) { 72 return gic_cpu_count(); 73} 74 75static cortex_a9_pit_t tsc; 76 77/* See TRM 4.3 */ 78#define GLOBAL_TIMER_IRQ 27 79 80void platform_timer_init(int timeslice) 81{ 82 errval_t err; 83 /* Time slice counter: use the Cortex-A9 Local Timer 84 (see Cortex-A9 MPCore TRM 4.1). */ 85 lvaddr_t lcl_base = 86 paging_map_device(platform_get_lt_address(), A9MPCORE_TIMER_LCL_SIZE); 87 cortex_a9_pit_initialize(&tsc, (mackerel_addr_t)lcl_base); 88 89 /* Global timer: use the Cortex-A9 Global Timer 90 (see Cortex-A9 MPCore TRM 4.3). */ 91 a9_gt_init(platform_get_gt_address()); 92 err = platform_enable_interrupt(GLOBAL_TIMER_IRQ, 0, 0, 0); 93 if(err_is_fail(err)){ 94 printk(LOG_ERR, 95 "Failed to enable timer interrupt. Will continue without..."); 96 } 97 /* Discover the clock rate. */ 98 a9_probe_tsc(); 99 assert(systime_frequency != 0); 100 101 MSG("System counter frequency is %lluHz.\n", systime_frequency); 102 /* Set kernel timeslice value, timeslice is in ms. */ 103 kernel_timeslice = ns_to_systime(timeslice * 1000000); 104 MSG("Timeslice interrupt every %llu system ticks (%dms).\n", kernel_timeslice, timeslice); 105 systime_set_timer(kernel_timeslice); 106} 107 108bool platform_is_timer_interrupt(uint32_t irq) 109{ 110 if (irq == GLOBAL_TIMER_IRQ) { 111 a9_gt_ack_irq(); 112 return 1; 113 } 114 115 return 0; 116} 117 118uint32_t platform_get_timer_interrupt(void){ 119 return GLOBAL_TIMER_IRQ; 120} 121 122systime_t systime_now(void) 123{ 124 return a9_gt_read(); 125} 126 127void systime_set_timeout(systime_t absolute_timeout) 128{ 129 a9_gt_set_comparator(absolute_timeout); 130} 131 132void systime_set_timer(systime_t relative_timeout) 133{ 134 systime_set_timeout(systime_now() + relative_timeout); 135} 136