rockbox/firmware/target/mips/ingenic_x1000/system-target.h
Aidan MacDonald fceffb7d4a x1000: disable CPU idle stats by default
There's no point including this in normal builds: the stats are not
used for anything, they are not really of interest to anyone except
developers, and add a small overhead to the kernel tick.

Change-Id: I1b4f67cc62d11d634a8cec279dca513dd10eea96
2021-04-17 20:24:21 +00:00

168 lines
5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2021 Aidan MacDonald
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __SYSTEM_TARGET_H__
#define __SYSTEM_TARGET_H__
/* For the sake of system.h CACHEALIGN macros.
* We need this to align DMA buffers, etc.
*/
#define CACHEALIGN_BITS 5
#define CACHE_SIZE (16*1024)
#ifdef BOOTLOADER_SPL
/* This saves ~200 bytes in the SPL by allowing -ffunction-sections to split
* up the cache management functions, most of which aren't called by the SPL.
* If they are placed in .icode, then they all end up in one section and the
* linker can't discard the unused functions.
*/
# define MIPS_CACHEFUNC_ATTR
#endif
#ifdef DEBUG
/* Define this to get CPU idle stats, visible in the debug menu. */
# define X1000_CPUIDLE_STATS
#endif
#include "mmu-mips.h"
#include "mipsregs.h"
#include "mipsr2-endian.h"
#include <stdint.h>
/* Get physical address for DMA */
#define PHYSADDR(addr) (((unsigned long)(addr)) & 0x1fffffff)
#define HIGHEST_IRQ_LEVEL 0
/* Rockbox API */
#define enable_irq() set_c0_status(ST0_IE)
#define disable_irq() clear_c0_status(ST0_IE)
#define disable_irq_save() set_irq_level(0)
#define restore_irq(arg) write_c0_status(arg)
static inline int set_irq_level(int lev)
{
unsigned reg, oldreg;
reg = oldreg = read_c0_status();
if(lev)
reg |= ST0_IE;
else
reg &= ~ST0_IE;
write_c0_status(reg);
return oldreg;
}
#ifdef X1000_CPUIDLE_STATS
/* CPU idle stats, updated each kernel tick in kernel-x1000.c */
extern int __cpu_idle_avg;
extern int __cpu_idle_cur;
extern uint32_t __cpu_idle_ticks;
extern uint32_t __cpu_idle_reftick;
#endif
static inline uint32_t __ost_read32(void);
static inline void core_sleep(void)
{
#ifdef X1000_CPUIDLE_STATS
uint32_t t1 = __ost_read32();
#endif
__asm__ __volatile__(
".set push\n\t"
".set mips32r2\n\t"
"mfc0 $8, $12\n\t"
"move $9, $8\n\t"
"la $10, 0x8000000\n\t"
"or $8, $10\n\t"
"mtc0 $8, $12\n\t"
"wait\n\t"
"mtc0 $9, $12\n\t"
".set pop\n\t"
::: "t0", "t1", "t2");
#ifdef X1000_CPUIDLE_STATS
uint32_t t2 = __ost_read32();
__cpu_idle_ticks += t2 - t1;
#endif
enable_irq();
}
/* IRQ control */
extern void system_enable_irq(int irq);
extern void system_disable_irq(int irq);
/* Simple delay API */
#define OST_FREQUENCY (X1000_EXCLK_FREQ / 4)
#define OST_TICKS_PER_US (OST_FREQUENCY / 1000000)
#define MAX_OST_DELAY_ARG 0x7fffffff
#define MAX_UDELAY_ARG (MAX_OST_DELAY_ARG / OST_TICKS_PER_US)
#define MAX_MDELAY_ARG (MAX_UDELAY_ARG / 1000)
/* Macros adapted from include/linux/delay.h,
* Copyright (C) 1993 Linus Torvalds
*
* These optimize away all calculations to compile time for the common case
* of small constant arguments, reducing to a single __ost_delay() call.
*/
#define udelay(n) \
((__builtin_constant_p(n) && (n) <= MAX_UDELAY_ARG) ? \
__ost_delay((n) * OST_TICKS_PER_US) : __udelay((n)))
#define mdelay(n) \
((__builtin_constant_p(n) && (n) <= MAX_MDELAY_ARG) ? \
__ost_delay((n) * 1000 * OST_TICKS_PER_US) : __mdelay((n)))
/* Slow path implementations which handle their full argument range by
* looping and calling __ost_delay() repeatedly.
*/
extern void __udelay(uint32_t us);
extern void __mdelay(uint32_t ms);
/* Read full 64-bit OST counter value; this requires disabling IRQs
* to safely read the counter.
*/
extern uint64_t __ost_read64(void);
static inline uint32_t __ost_read32(void)
{
/* Read OST_2CNTL using raw address to avoid exposing internal headers.
* The 64-bit counter is read with IRQs disabled and since threads are
* not pre-emptive in Rockbox we won't trash anybody's 64-bit read by
* reading the low count without locking.
*/
return *(const volatile uint32_t*)0xb2000020;
}
/* NOTE: it is required that count < MAX_OST_DELAY_ARG, this is to provide
* some slack in the 32-bit counter so we can reliably detect the timeout.
*/
static inline void __ost_delay(uint32_t count)
{
/* Add one to ensure we delay for at least the time given */
count += 1;
uint32_t start = __ost_read32();
while(__ost_read32() - start < count);
}
#endif /* __SYSTEM_TARGET_H__ */