105 lines
2.7 KiB
C
105 lines
2.7 KiB
C
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
/* Port 80 Timer Interrupt for MEC1322 */
|
|
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "hooks.h"
|
|
#include "lpc.h"
|
|
#include "port80.h"
|
|
#include "registers.h"
|
|
#include "task.h"
|
|
|
|
/* Fire timer interrupt every 1000 usec to check for port80 data. */
|
|
#define POLL_PERIOD_USEC 1000
|
|
/* After 30 seconds of no port 80 data, disable the timer interrupt. */
|
|
#define INTERRUPT_DISABLE_TIMEOUT_SEC 30
|
|
#define INTERRUPT_DISABLE_IDLE_COUNT (INTERRUPT_DISABLE_TIMEOUT_SEC \
|
|
* 1000000 \
|
|
/ POLL_PERIOD_USEC)
|
|
|
|
/* Count the number of consecutive interrupts with no port 80 data. */
|
|
static int idle_count;
|
|
|
|
static void port_80_interrupt_enable(void)
|
|
{
|
|
idle_count = 0;
|
|
|
|
/* Enable the interrupt. */
|
|
task_enable_irq(MEC1322_IRQ_TIMER16_1);
|
|
/* Enable and start the timer. */
|
|
MEC1322_TMR16_CTL(1) |= 1 | BIT(5);
|
|
}
|
|
DECLARE_HOOK(HOOK_CHIPSET_RESUME, port_80_interrupt_enable, HOOK_PRIO_DEFAULT);
|
|
DECLARE_HOOK(HOOK_CHIPSET_RESET, port_80_interrupt_enable, HOOK_PRIO_DEFAULT);
|
|
|
|
static void port_80_interrupt_disable(void)
|
|
{
|
|
/* Disable the timer block. */
|
|
MEC1322_TMR16_CTL(1) &= ~1;
|
|
/* Disable the interrupt. */
|
|
task_disable_irq(MEC1322_IRQ_TIMER16_1);
|
|
}
|
|
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, port_80_interrupt_disable,
|
|
HOOK_PRIO_DEFAULT);
|
|
|
|
/*
|
|
* The port 80 interrupt will use TIMER16 instance 1 for a 1ms countdown
|
|
* timer. This timer is on GIRQ23, bit 1.
|
|
*/
|
|
static void port_80_interrupt_init(void)
|
|
{
|
|
uint32_t val = 0;
|
|
|
|
/*
|
|
* The timers are driven by a 48MHz oscillator. Prescale down to
|
|
* 1MHz. 48MHz/48 -> 1MHz
|
|
*/
|
|
val = MEC1322_TMR16_CTL(1);
|
|
val = (val & 0xFFFF) | (47 << 16);
|
|
/* Automatically restart the timer. */
|
|
val |= BIT(3);
|
|
/* The counter should decrement. */
|
|
val &= ~BIT(2);
|
|
MEC1322_TMR16_CTL(1) = val;
|
|
|
|
/* Set the reload value(us). */
|
|
MEC1322_TMR16_PRE(1) = POLL_PERIOD_USEC;
|
|
|
|
/* Clear the status if any. */
|
|
MEC1322_TMR16_STS(1) |= 1;
|
|
|
|
/* Clear any pending interrupt. */
|
|
MEC1322_INT_SOURCE(23) = BIT(1);
|
|
/* Enable IRQ vector 23. */
|
|
MEC1322_INT_BLK_EN |= BIT(23);
|
|
/* Enable the interrupt. */
|
|
MEC1322_TMR16_IEN(1) |= 1;
|
|
MEC1322_INT_ENABLE(23) = BIT(1);
|
|
|
|
port_80_interrupt_enable();
|
|
}
|
|
DECLARE_HOOK(HOOK_INIT, port_80_interrupt_init, HOOK_PRIO_DEFAULT);
|
|
|
|
void port_80_interrupt(void)
|
|
{
|
|
int data;
|
|
|
|
MEC1322_TMR16_STS(1) = 1; /* Ack the interrupt */
|
|
if (BIT(1) & MEC1322_INT_RESULT(23)) {
|
|
data = port_80_read();
|
|
|
|
if (data != PORT_80_IGNORE) {
|
|
idle_count = 0;
|
|
port_80_write(data);
|
|
}
|
|
}
|
|
|
|
if (++idle_count >= INTERRUPT_DISABLE_IDLE_COUNT)
|
|
port_80_interrupt_disable();
|
|
}
|
|
DECLARE_IRQ(MEC1322_IRQ_TIMER16_1, port_80_interrupt, 2);
|