iBoot/drivers/apple/audio/audio.c

232 lines
4.6 KiB
C

/*
* Copyright (C) 2009-2013 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <platform.h>
#include <platform/int.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <platform/soc/pmgr.h>
#include <platform/timer.h>
#include <arch/arm/arm.h>
#include <drivers/audio/audio.h>
/*
* AE2 Decrementer
*
* Note that for absolute time, we rely on externally defined timer_get_ticks and
* it is assumed that the tick rate matches our decrementer's.
*/
static void timer_deadline(void *arg);
static void (* timer_deadline_func)(void);
#define DECR_MAX_COUNT (0x7fffffffULL)
static uint32_t timer_count = 0;
static uint32_t timer_late_count = 0;
int timer_init(u_int32_t timer)
{
if (timer) return -1;
/* Disable timer */
rAE2_ADECSR = 0;
/* Install handler but mask for now */
install_int_handler(AE2_INT_DEC, (int_handler)timer_deadline, NULL);
set_int_type(AE2_INT_DEC, INT_TYPE_IRQ | INT_TYPE_LEVEL);
mask_int(AE2_INT_DEC);
return 0;
}
void timer_deadline_enter(u_int64_t deadline, void (* func)(void))
{
uint64_t ticks;
uint32_t decr;
timer_deadline_func = func;
if (func) {
/* convert absolute deadline to relative time */
ticks = timer_get_ticks();
timer_count++;
if (deadline < ticks) {
timer_late_count++;
deadline = 0;
} else {
deadline -= ticks;
}
/* clamp the deadline to our maximum, which is about 89 seconds */
decr = (deadline > DECR_MAX_COUNT) ? DECR_MAX_COUNT : deadline;
/*
* Stop the decrementer and clear the value to ensure
* no pending interrupts. Load the value and go.
*/
rAE2_ADECSR = 0;
rAE2_ADECTR = 0;
unmask_int(AE2_INT_DEC);
rAE2_ADECTR = decr;
rAE2_ADECSR = 1;
} else {
/* no deadline, disable the decrementer and its interrupt */
dprintf(DEBUG_INFO, "timer off\n");
mask_int(AE2_INT_DEC);
rAE2_ADECSR = 0;
}
}
static void
timer_deadline(void *arg)
{
/* acknowledge the interrupt and disable the decrementer */
mask_int(AE2_INT_DEC);
/* if we have a callback, invoke it now */
if (timer_deadline_func)
timer_deadline_func();
}
#if OSC_FREQ == 24000000
utime_t timer_ticks_to_usecs(uint64_t ticks)
{
return ticks / 24;
}
uint64_t timer_usecs_to_ticks(utime_t usecs)
{
return usecs * 24;
}
#endif
uint32_t timer_get_tick_rate(void)
{
return OSC_FREQ;
}
uint64_t timer_get_ticks(void)
{
extern uint64_t aic_get_ticks();
return aic_get_ticks();
}
/*
* AE2 interrupts
*/
static struct interrupt_entry handlers[AE2_MAX_INTS];
#if SUPPORT_SLEEP
struct ae2_int_state {
u_int32_t irqs;
u_int32_t fiqs;
} ae2_saved_state;
#endif
int interrupt_init(void)
{
rAE2_AIRQCR = 0xffffffff;
rAE2_AFIQCR = 0xffffffff;
#if SUPPORT_SLEEP
rAE2_AIRQSR = ae2_saved_state.irqs;
rAE2_AFIQSR = ae2_saved_state.fiqs;
#endif
/* also enable it */
exit_critical_section();
return 0;
}
void unmask_int(uint32_t vector)
{
if (handlers[vector].edge)
rAE2_AFIQSR = 1 << vector;
else
rAE2_AIRQSR = 1 << vector;
#if SUPPORT_SLEEP
ae2_saved_state.irqs = rAE2_AIRQER;
ae2_saved_state.fiqs = rAE2_AFIQER;
#endif
}
void mask_int(uint32_t vector)
{
if (handlers[vector].edge)
rAE2_AFIQCR = 1 << vector;
else
rAE2_AIRQCR = 1 << vector;
#if SUPPORT_SLEEP
ae2_saved_state.irqs = rAE2_AIRQER;
ae2_saved_state.fiqs = rAE2_AFIQER;
#endif
}
void set_int_type(uint32_t vector, int type)
{
/* Overload the "edge" member to indicate FIQ */
handlers[vector].edge = (type & INT_TYPE_FIQ) != 0;
if (type & INT_TYPE_FIQ)
arm_enable_fiqs();
}
int install_int_handler(uint32_t vector, int_handler handler, void *arg)
{
ASSERT(vector < AE2_MAX_INTS);
enter_critical_section();
handlers[vector].handler = handler;
handlers[vector].arg = arg;
exit_critical_section();
return 0;
}
void platform_irq(void)
{
u_int32_t pending, vector;
if (0 == (pending = (rAE2_AIRQRR & rAE2_AIRQER))) {
return;
}
vector = __builtin_ctz(pending);
if (handlers[vector].handler)
handlers[vector].handler(handlers[vector].arg);
}
void platform_fiq(void)
{
u_int32_t pending, vector;
if (0 == (pending = (rAE2_AFIQRR & rAE2_AFIQER))) {
return;
}
vector = __builtin_ctz(pending);
if (handlers[vector].handler)
handlers[vector].handler(handlers[vector].arg);
}
void interrupt_generate_ipc(u_int32_t vector)
{
rAE2_ASFISR = 1 << vector;
}
void interrupt_clear_ipc(u_int32_t vector)
{
rAE2_ASFICR = 1 << vector;
}