arch/intel64: add HPET timer support as oneshot timer

Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
p-szafonimateusz 2024-02-23 18:21:53 +01:00 committed by Xiang Xiao
parent 51d8bbfbd9
commit d4b17f963d
11 changed files with 1730 additions and 1 deletions

View File

@ -0,0 +1,96 @@
/****************************************************************************
* arch/x86_64/include/hpet.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_X86_64_INCLUDE_HPET_H
#define __ARCH_X86_64_INCLUDE_HPET_H
/****************************************************************************
* Included Files
****************************************************************************/
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Register definitions */
#define HPET_GCAPID_OFFSET (0x00)
#define HPET_GCONF_OFFSET (0x10)
#define HPET_GISR_OFFSET (0x20)
#define HPET_MCNTR_OFFSET (0xf0)
#define HPET_TCONF_OFFSET(n) (0x100 + (0x20 * (n)))
#define HPET_TCOMP_OFFSET(n) (0x108 + (0x20 * (n)))
#define HPET_TFSB_OFFSET(n) (0x110 + (0x20 * (n)))
/* General Capabilities and ID Register */
#define HPET_GCAPID_REVID_SHIFT (0ul) /* Bits 0-7: Revistion */
# define HPET_GCAPID_REVID_MASK (0xfful << HPET_GCAPID_REVID_SHIFT)
#define HPET_GCAPID_NUMTIM_SHIFT (8ul) /* Bits 8-12: Number of Timers */
#define HPET_GCAPID_NUMTIM_MASK (0x1ful << HPET_GCAPID_NUMTIM_SHIFT)
#define HPET_GCAPID_COUNTSIZE (1 << 13) /* Bit 13: Counter size, 0: 32 bit, 1: 64 bit */
/* Bit 14: Reserved */
#define HPET_GCAPID_LEGROUTE (1 << 15) /* Bit 15: LegacyReplacement Route Capable */
#define HPET_GCAPID_VENDORID_SHIFT (16ul) /* Bits 16-31: Vendor ID */
# define HPET_GCAPID_VENDORID_MASK (0x7ffful << HPET_GCAPID_VENDORID_SHIFT)
#define HPET_GCAPID_CLKPER_SHIFT (32ul) /* Bits 32-63: Main Counter Tick Period in ps */
# define HPET_GCAPID_CLKPER_MASK (0x7ffffffful << HPET_GCAPID_CLKPER_SHIFT)
/* General Configuration Register */
#define HPET_GCONF_LEGERT (1 << 0) /* Bit 0: LegacyReplacement Route */
#define HPET_GCONF_ENABLE (1 << 1) /* Bit 1: Overall Enable */
/* General Interrupt Status Register */
#define HPET_GISR_TINT(n) (1 << (n)) /* Timer n Interrupt Active */
/* Timer N Configuration and Capabilities Register */
/* Bit 0: Reserved */
#define HPET_TCONF_INTTYPE (1 << 1) /* Bit 1: Timer n Interrupt Type (0: edge, 1: level) */
#define HPET_TCONF_INTEN (1 << 2) /* Bit 2: Timer n Interrupt Enable */
#define HPET_TCONF_TYPE (1 << 3) /* Bit 3: Timer n Type (0: non-periodic, 1: periodic) */
#define HPET_TCONF_PERCAP (1 << 4) /* Bit 4: Timer n Periodic Interrupt Capable */
#define HPET_TCONF_SIZECAP (1 << 5) /* Bit 5: Timer n Size */
#define HPET_TCONF_VALSET (1 << 6) /* Bit 6: Timer n Value Set */
/* Bit 7: Reserved */
#define HPET_TCONF_32MODE (1 << 8) /* Bit 8: Timer n 32-bit mode */
#define HPET_TCONF_INTROUTE_SHIFT (9) /* Bits 9-13: Timer n Interrupt Route */
# define HPET_TCONF_INTROUTE_MASK (0x7f << HPET_TCONF_INTROUTE_SHIFT)
# define HPET_TCONF_INTROUTE(n) (((n) << HPET_TCONF_INTROUTE_SHIFT) & HPET_TCONF_INTROUTE_MASK)
#define HPET_TCONF_FSBEN (1 << 14) /* Bit 14: Timer n FSB Interrupt Enable */
#define HPET_TCONF_FSBCAP (1 << 15) /* Bit 15: Timer n FSB Interrupt Delivery */
/* Bits 16-31: Reserved */
#define HPET_TCONF_ROUTECAP_SHIFT (32) /* Bits 32-63: Timer n Interrupt Routing Capability */
# define HPET_TCONF_ROUTECAP_MASK (0x7ffffffful << HPET_TCONF_ROUTECAP_SHIFT)
/* Timer N FSB Interrupt Route Register */
#define HPET_TFSB_INT_VAL_SHIFT (0)
#define HPET_TFSB_INT_VAL_MASK (0x00000000ffffffff)
#define HPET_TFSB_INT_ADDR_SHIFT (31)
#define HPET_TFSB_INT_ADDR_MASK (0xffffffff00000000)
/* HPET register space */
#define HPET_REGION_SIZE (1024)
#endif /* __ARCH_X86_64_INCLUDE_HPET_H */

View File

@ -97,6 +97,11 @@
#define IRQ_ERROR 51 /* APIC Error */
#define IRQ_SPURIOUS 0xff /* Spurious Interrupts */
/* Use legacy routing for HPET */
#define HPET0_IRQ IRQ2
#define HPET1_IRQ IRQ8
#define NR_IRQS 48
/* Common register save structure created by up_saveusercontext() and by

View File

@ -59,6 +59,14 @@ else()
list(APPEND SRCS intel64_timerisr.c)
endif()
if(CONFIG_INTEL64_HPET)
list(APPEND SRCS intel64_hpet.c)
endif()
if(CONFIG_INTEL64_ONESHOT)
list(APPEND SRCS intel64_oneshot.c intel64_oneshot_lower.c)
endif()
if(CONFIG_ARCH_FPU)
list(APPEND SRCS intel64_fpucmp.c)
endif()

View File

@ -46,6 +46,63 @@ config ARCH_INTEL64_APIC_FREQ_KHZ
endif
config INTEL64_HPET
bool "HPET timer support"
default n
---help---
Select to enable the HPET timer support
if INTEL64_HPET
config INTEL64_HPET_BASE
hex "HPET timer base address"
default 0xfed00000
---help---
Configure base address for HPET. In the future, we can get this address from
the ACPI table if ACPI support is enabled.
config INTEL64_HPET_CHANNELS
int "HPET timer supported channels"
default 2
range 1 3
---help---
Configure the number of supported HPET channles (called HPET timers
in HPET spec). We use HPET legacy replacement for interrupts which
means that Timer 0 and Timer 1 interrupts are hardcoded, but Timer 2
needs additional attention to configure interrupt routing.
Timer 2 will most likely not work with QEMU.
config INTEL64_HPET_MIN_DELAY
int "HPET minimum supported delay in micro-seconds"
default 1000
---help---
HPET use free runnin up-counter and a comparators which generate events
only on a equal event. This can results in event miss if we set too small
delay. In that case we must set a minimum value for delay that always work.
For the QEMU target this value should be as high as 1000, but for real
hardware it may go much lower (for i7-1255U CPU it works with values <10).
endif # INTEL64_HPET
config INTEL64_ONESHOT
bool "Oneshot timer support"
select INTEL64_HPET
default n
---help---
Select to enable the oneshot timer support
if INTEL64_ONESHOT
config INTEL64_ONESHOT_MAXTIMERS
int "Maximum number of oneshot timers"
default 1
range 1 3
---help---
Determines the maximum number of oneshot timers that can be
supported.
endif
config ARCH_INTEL64_HAVE_XSAVE
bool "XSAVE support"
default y

View File

@ -60,6 +60,14 @@ ifeq ($(CONFIG_SCHED_TICKLESS),y)
CHIP_CSRCS += intel64_tickless.c
endif
ifeq ($(CONFIG_INTEL64_HPET),y)
CHIP_CSRCS += intel64_hpet.c
endif
ifeq ($(CONFIG_INTEL64_ONESHOT),y)
CHIP_CSRCS += intel64_oneshot.c intel64_oneshot_lower.c
endif
ifeq ($(CONFIG_ARCH_FPU),y)
CHIP_CSRCS += intel64_fpucmp.c
endif

View File

@ -0,0 +1,496 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_hpet.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <arch/io.h>
#include <arch/hpet.h>
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <stdint.h>
#include "intel64_hpet.h"
/****************************************************************************
* Private Types
****************************************************************************/
/* HPET timer channel */
struct intel64_hpet_chan_s
{
uint8_t irq;
};
/* HPET timer driver */
struct intel64_hpet_s
{
struct intel64_tim_ops_s *ops;
uint64_t base;
uint32_t clk_per_fs;
uint8_t timers;
bool initialized;
struct intel64_hpet_chan_s chans[CONFIG_INTEL64_HPET_CHANNELS];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Helpers */
static void intel64_hpet_putreg(struct intel64_hpet_s *hpet, uint32_t offset,
uint64_t value);
static uint64_t intel64_hpet_getreg(struct intel64_hpet_s *hpet,
uint32_t offset);
/* Ops */
static void intel64_hpet_enable(struct intel64_tim_dev_s *dev, bool en);
static void intel64_hpet_cmpset(struct intel64_tim_dev_s *dev, uint8_t timer,
uint64_t cmp);
static uint64_t intel64_hpet_cmpget(struct intel64_tim_dev_s *dev,
uint8_t timer);
static uint64_t intel64_hpet_cntget(struct intel64_tim_dev_s *dev);
static uint64_t intel64_hpet_intget(struct intel64_tim_dev_s *dev,
uint8_t timer);
static void intel64_hpet_intack(struct intel64_tim_dev_s *dev,
uint8_t timer);
static void intel64_hpet_cntset(struct intel64_tim_dev_s *dev,
uint64_t cntr);
static uint32_t intel64_hpet_perget(struct intel64_tim_dev_s *dev);
static int intel64_hpet_setisr(struct intel64_tim_dev_s *dev, uint8_t timer,
xcpt_t handler, void *arg, bool periodic);
static void intel64_hpet_enint(struct intel64_tim_dev_s *dev, uint8_t tim);
static void intel64_hpet_disint(struct intel64_tim_dev_s *dev, uint8_t tim);
/****************************************************************************
* Private Data
****************************************************************************/
/* HPET ops */
static struct intel64_tim_ops_s g_intel64_hpet_ops =
{
.enable = intel64_hpet_enable,
.getperiod = intel64_hpet_perget,
.getcounter = intel64_hpet_cntget,
.setcounter = intel64_hpet_cntset,
.setcompare = intel64_hpet_cmpset,
.getcompare = intel64_hpet_cmpget,
.getint = intel64_hpet_intget,
.ackint = intel64_hpet_intack,
.setisr = intel64_hpet_setisr,
.enableint = intel64_hpet_enint,
.disableint = intel64_hpet_disint
};
/* HPET driver instance */
static struct intel64_hpet_s g_intel64_hpet =
{
.ops = &g_intel64_hpet_ops,
.initialized = false,
.chans =
{
/* Channel 0 (Timer 0) */
{
.irq = HPET0_IRQ,
},
#if CONFIG_INTEL64_HPET_CHANNELS > 1
/* Channel 1 (Timer 1) */
{
.irq = HPET1_IRQ,
},
#endif
#if CONFIG_INTEL64_HPET_CHANNELS > 2
/* Channel 2 (Timer 2) */
{
.irq = HPET2_IRQ
},
#endif
}
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: intel64_hpet_putreg
*
* Description:
* Put a 64-bit register value by offset
*
****************************************************************************/
static void intel64_hpet_putreg(struct intel64_hpet_s *hpet, uint32_t offset,
uint64_t value)
{
return mmio_write64((void *)(hpet->base + offset), value);
}
/****************************************************************************
* Name: intel64_hpet_getreg
*
* Description:
* Get a 64-bit register value by offset
*
****************************************************************************/
static uint64_t intel64_hpet_getreg(struct intel64_hpet_s *hpet,
uint32_t offset)
{
return mmio_read64((void *)(hpet->base + offset));
}
/****************************************************************************
* Name: intel64_hpet_enable
*
* Description:
* Allow main counter to run and allow timer interrupts
*
****************************************************************************/
static void intel64_hpet_enable(struct intel64_tim_dev_s *dev, bool en)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
uint64_t regval = 0;
regval = intel64_hpet_getreg(hpet, HPET_GCONF_OFFSET);
if (en)
{
regval |= HPET_GCONF_ENABLE;
}
else
{
regval &= ~HPET_GCONF_ENABLE;
}
intel64_hpet_putreg(hpet, HPET_GCONF_OFFSET, regval);
}
/****************************************************************************
* Name: intel64_hpet_cmpset
*
* Description:
* Set a compare register to a given value.
*
****************************************************************************/
static void intel64_hpet_cmpset(struct intel64_tim_dev_s *dev, uint8_t timer,
uint64_t cmp)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
DEBUGASSERT(timer < hpet->timers);
intel64_hpet_putreg(hpet, HPET_TCOMP_OFFSET(timer), cmp);
}
/****************************************************************************
* Name: intel64_hpet_cmpget
*
* Description:
* Get a compare register to a given value.
*
****************************************************************************/
static uint64_t intel64_hpet_cmpget(struct intel64_tim_dev_s *dev,
uint8_t timer)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
DEBUGASSERT(timer < hpet->timers);
return intel64_hpet_getreg(hpet, HPET_TCOMP_OFFSET(timer));
}
/****************************************************************************
* Name: intel64_hpet_intget
*
* Description:
* Get a interrupt status register.
*
****************************************************************************/
static uint64_t intel64_hpet_intget(struct intel64_tim_dev_s *dev,
uint8_t timer)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
return (intel64_hpet_getreg(hpet, HPET_GISR_OFFSET) &
HPET_GISR_TINT(timer));
}
/****************************************************************************
* Name: intel64_hpet_intack
*
* Description:
* ACK interrupt.
*
****************************************************************************/
static void intel64_hpet_intack(struct intel64_tim_dev_s *dev,
uint8_t timer)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
intel64_hpet_putreg(hpet, HPET_GISR_OFFSET, HPET_GISR_TINT(timer));
}
/****************************************************************************
* Name: intel64_hpet_cntget
*
* Description:
* Get the main counter.
*
****************************************************************************/
static uint64_t intel64_hpet_cntget(struct intel64_tim_dev_s *dev)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
return intel64_hpet_getreg(hpet, HPET_MCNTR_OFFSET);
}
/****************************************************************************
* Name: intel64_hpet_cntset
*
* Description:
* Set the main counter.
*
****************************************************************************/
static void intel64_hpet_cntset(struct intel64_tim_dev_s *dev,
uint64_t cntr)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
return intel64_hpet_putreg(hpet, HPET_MCNTR_OFFSET, cntr);
}
/****************************************************************************
* Name: intel64_hpet_perget
*
* Description:
* Get the main counter period in femtosecounds (1e-15 sec).
*
****************************************************************************/
static uint32_t intel64_hpet_perget(struct intel64_tim_dev_s *dev)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
return hpet->clk_per_fs;
}
/****************************************************************************
* Name: intel64_hpet_setisr
*
* Description:
* Configure interrupt handler for a given timer
*
****************************************************************************/
static int intel64_hpet_setisr(struct intel64_tim_dev_s *dev, uint8_t timer,
xcpt_t handler, void *arg, bool periodic)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
uint64_t regval = 0;
uint8_t irq = hpet->chans[timer].irq;
DEBUGASSERT(timer < hpet->timers);
regval = intel64_hpet_getreg(hpet, HPET_TCONF_OFFSET(timer));
if (periodic)
{
if ((regval & HPET_TCONF_PERCAP) == 0)
{
tmrerr("Periodic not supported");
return -EPERM;
}
regval |= HPET_TCONF_PERCAP;
}
else
{
regval &= ~HPET_TCONF_PERCAP;
}
/* Route interrupts */
regval |= HPET_TCONF_INTROUTE(irq - IRQ0);
/* Set level triggered mode.
*
* Edge triggered mode seems to work well on QEMU, but for real hardware,
* unwanted interrupt is generated when we enable timer interrupts.
*/
regval |= HPET_TCONF_INTTYPE;
/* Set 64-bit mode */
regval &= ~HPET_TCONF_32MODE;
/* Write Timer configuration */
intel64_hpet_putreg(hpet, HPET_TCONF_OFFSET(timer), regval);
if (handler == NULL)
{
/* Disable interrupt */
irq_attach(irq, handler, arg);
up_disable_irq(irq);
}
else
{
/* Set callback and enable interrupt */
irq_attach(irq, handler, arg);
up_enable_irq(irq);
}
return OK;
}
/****************************************************************************
* Name: intel64_hpet_enint
*
* Description:
* Enable interrupt
*
****************************************************************************/
static void intel64_hpet_enint(struct intel64_tim_dev_s *dev, uint8_t tim)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
uint64_t regval = 0;
DEBUGASSERT(tim < hpet->timers);
regval = intel64_hpet_getreg(hpet, HPET_TCONF_OFFSET(tim));
regval |= HPET_TCONF_INTEN;
intel64_hpet_putreg(hpet, HPET_TCONF_OFFSET(tim), regval);
}
/****************************************************************************
* Name: intel64_hpet_disint
*
* Description:
* Disable interrupt
*
****************************************************************************/
static void intel64_hpet_disint(struct intel64_tim_dev_s *dev, uint8_t tim)
{
struct intel64_hpet_s *hpet = (struct intel64_hpet_s *)dev;
uint64_t regval = 0;
DEBUGASSERT(tim < hpet->timers);
regval = intel64_hpet_getreg(hpet, HPET_TCONF_OFFSET(tim));
regval &= ~HPET_TCONF_INTEN;
intel64_hpet_putreg(hpet, HPET_TCONF_OFFSET(tim), regval);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: intel64_hpet_init
*
* Description:
* Initialize HPET timer with a given base address
*
****************************************************************************/
struct intel64_tim_dev_s *intel64_hpet_init(uint64_t base)
{
struct intel64_hpet_s *hpet = &g_intel64_hpet;
uint64_t regval = 0;
if (hpet->initialized == false)
{
/* Store HPET base */
hpet->base = base;
/* Map HPET region */
up_map_region((void *)hpet->base, HPET_REGION_SIZE,
(X86_PAGE_PRESENT | X86_PAGE_WR | X86_PAGE_NOCACHE));
/* Get capabilities */
regval = intel64_hpet_getreg(hpet, HPET_GCAPID_OFFSET);
hpet->clk_per_fs = ((regval & HPET_GCAPID_CLKPER_MASK) >>
HPET_GCAPID_CLKPER_SHIFT);
hpet->timers = ((regval & HPET_GCAPID_NUMTIM_MASK) >>
HPET_GCAPID_NUMTIM_SHIFT);
hpet->timers = (hpet->timers > CONFIG_INTEL64_HPET_CHANNELS ?
CONFIG_INTEL64_HPET_CHANNELS : hpet->timers);
/* Connect ops */
hpet->ops = &g_intel64_hpet_ops;
if (regval & HPET_GCAPID_LEGROUTE)
{
/* Configure legacy mode.
*
* There is no way to disable PIT interrupts (?) other than enable
* legacy mode for HPET. Otherwise unwanted PIT interupts will
* interfere with HPET interrupts, making them useless.
*/
intel64_hpet_putreg(hpet, HPET_GCONF_OFFSET, HPET_GCONF_LEGERT);
}
else
{
/* Not supported */
ASSERT(0);
}
/* Enable HPET */
intel64_hpet_enable((struct intel64_tim_dev_s *)hpet, true);
tmrinfo("clk_per_fs = %" PRId32 " timers = %d\n",
hpet->clk_per_fs, hpet->timers);
/* Initialization done */
hpet->initialized = true;
}
return (struct intel64_tim_dev_s *)hpet;
}

View File

@ -0,0 +1,118 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_hpet.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_X86_64_SRC_INTEL64_INTEL64_HPET_H
#define __ARCH_X86_64_SRC_INTEL64_INTEL64_HPET_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <nuttx/irq.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Helpers ******************************************************************/
#define INTEL64_TIM_ENABLE(d, e) ((d)->ops->enable(d, e))
#define INTEL64_TIM_GETPERIOD(d) ((d)->ops->getperiod(d))
#define INTEL64_TIM_GETCOUNTER(d) ((d)->ops->getcounter(d))
#define INTEL64_TIM_SETCOUNTER(d, c) ((d)->ops->setcounter(d, c))
#define INTEL64_TIM_SETCOMPARE(d, t, c) ((d)->ops->setcompare(d, t, c))
#define INTEL64_TIM_GETCOMPARE(d, t) ((d)->ops->getcompare(d, t))
#define INTEL64_TIM_GETINT(d, t) ((d)->ops->getint(d, t))
#define INTEL64_TIM_ACKINT(d, t) ((d)->ops->ackint(d, t))
#define INTEL64_TIM_SETISR(d, t, h, a, p) ((d)->ops->setisr(d, t, h, a, p))
#define INTEL64_TIM_ENABLEINT(d, t) ((d)->ops->enableint(d, t))
#define INTEL64_TIM_DISABLEINT(d, t) ((d)->ops->disableint(d, t))
/****************************************************************************
* Public Types
****************************************************************************/
/* TIM Device Structure */
struct intel64_tim_ops_s;
struct intel64_tim_dev_s
{
struct intel64_tim_ops_s *ops;
};
/* TIM Operations */
struct intel64_tim_ops_s
{
void (*enable)(struct intel64_tim_dev_s *dev, bool en);
uint32_t (*getperiod)(struct intel64_tim_dev_s *dev);
uint64_t (*getcounter)(struct intel64_tim_dev_s *dev);
void (*setcounter)(struct intel64_tim_dev_s *dev, uint64_t count);
void (*setcompare)(struct intel64_tim_dev_s *dev, uint8_t timer,
uint64_t compare);
uint64_t (*getcompare)(struct intel64_tim_dev_s *dev, uint8_t timer);
uint64_t (*getint)(struct intel64_tim_dev_s *dev, uint8_t timer);
void (*ackint)(struct intel64_tim_dev_s *dev, uint8_t timer);
int (*setisr)(struct intel64_tim_dev_s *dev, uint8_t timer,
xcpt_t handler, void * arg, bool periodic);
void (*enableint)(struct intel64_tim_dev_s *dev, uint8_t tim);
void (*disableint)(struct intel64_tim_dev_s *dev, uint8_t tim);
};
/****************************************************************************
* Inline Functions
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: intel64_hpet_init
*
* Description:
* Initialize HPET timer with a given base address
*
****************************************************************************/
struct intel64_tim_dev_s *intel64_hpet_init(uint64_t base);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_X86_64_SRC_INTEL64_INTEL64_HPET_H */

View File

@ -0,0 +1,425 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_oneshot.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/clock.h>
#include <nuttx/spinlock.h>
#include "intel64_hpet.h"
#include "intel64_oneshot.h"
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int intel64_oneshot_handler(int irg_num, void * context, void *arg);
static int intel64_allocate_handler(struct intel64_oneshot_s *oneshot);
/****************************************************************************
* Private Data
****************************************************************************/
static struct intel64_oneshot_s *g_oneshot[CONFIG_INTEL64_ONESHOT_MAXTIMERS];
static spinlock_t g_oneshot_spin;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: intel64_oneshot_handler
*
* Description:
* Common timer interrupt callback. When any oneshot timer interrupt
* expires, this function will be called. It will forward the call to
* the next level up.
*
* Input Parameters:
* oneshot - The state associated with the expired timer
*
* Returned Value:
* Always returns OK
*
****************************************************************************/
static int intel64_oneshot_handler(int irg_num, void * context, void *arg)
{
struct intel64_oneshot_s *oneshot = (struct intel64_oneshot_s *)arg;
void *oneshot_arg;
oneshot_handler_t oneshot_handler;
tmrinfo("Expired...\n");
DEBUGASSERT(oneshot != NULL && oneshot->handler);
if (INTEL64_TIM_GETINT(oneshot->tch, oneshot->chan))
{
/* Disable any further interrupts. */
INTEL64_TIM_DISABLEINT(oneshot->tch, oneshot->chan);
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, NULL, NULL, false);
INTEL64_TIM_ACKINT(oneshot->tch, oneshot->chan);
/* The timer is no longer running */
oneshot->running = false;
/* Forward the event, clearing out any vestiges */
oneshot_handler = (oneshot_handler_t)oneshot->handler;
oneshot->handler = NULL;
oneshot_arg = (void *)oneshot->arg;
oneshot->arg = NULL;
oneshot_handler(oneshot_arg);
}
return OK;
}
/****************************************************************************
* Name: intel64_allocate_handler
*
* Description:
* Allocate a timer callback handler for the oneshot instance.
*
* Input Parameters:
* oneshot - The state instance the new oneshot timer
*
* Returned Value:
* Returns zero (OK) on success. This can only fail if the number of
* timers exceeds CONFIG_INTEL64_ONESHOT_MAXTIMERS.
*
****************************************************************************/
static int intel64_allocate_handler(struct intel64_oneshot_s *oneshot)
{
int ret = -EBUSY;
int i;
/* Search for an unused handler */
for (i = 0; i < CONFIG_INTEL64_ONESHOT_MAXTIMERS; i++)
{
/* Is this handler available? */
if (g_oneshot[i] == NULL)
{
/* Yes... assign it to this oneshot */
g_oneshot[i] = oneshot;
oneshot->cbndx = i;
ret = OK;
break;
}
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: intel64_oneshot_initialize
*
* Description:
* Initialize the oneshot timer wrapper
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure
* chan Timer counter channel to be used.
* resolution The required resolution of the timer in units of
* microseconds. NOTE that the range is restricted to the
* range of uint16_t (excluding zero).
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
int intel64_oneshot_initialize(struct intel64_oneshot_s *oneshot, int chan,
uint16_t resolution)
{
/* HPET resolution can't be changed, but it is always in terms of ns */
UNUSED(resolution);
/* Get timer */
oneshot->tch = intel64_hpet_init(CONFIG_INTEL64_HPET_BASE);
if (oneshot->tch == NULL)
{
tmrerr("ERROR: Failed to allocate HPET timer %d\n", chan);
return -EBUSY;
}
/* Get the timer period */
oneshot->period = INTEL64_TIM_GETPERIOD(oneshot->tch);
oneshot->frequency = 1e15 / oneshot->period;
/* Initialize the remaining fields in the state structure. */
oneshot->chan = chan;
oneshot->running = false;
oneshot->handler = NULL;
oneshot->arg = NULL;
/* Assign a callback handler to the oneshot */
return intel64_allocate_handler(oneshot);
}
/****************************************************************************
* Name: intel64_oneshot_max_delay
*
* Description:
* Determine the maximum delay of the one-shot timer (in microseconds)
*
****************************************************************************/
int intel64_oneshot_max_delay(struct intel64_oneshot_s *oneshot,
uint64_t *usec)
{
DEBUGASSERT(oneshot != NULL && usec != NULL);
*usec = ((uint64_t)(UINT32_MAX / oneshot->frequency) *
(uint64_t)USEC_PER_SEC);
return OK;
}
/****************************************************************************
* Name: intel64_oneshot_start
*
* Description:
* Start the oneshot timer
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure. This
* structure must have been previously initialized via a call to
* intel64_oneshot_initialize();
* handler The function to call when when the oneshot timer expires.
* arg An opaque argument that will accompany the callback.
* ts Provides the duration of the one shot timer.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
int intel64_oneshot_start(struct intel64_oneshot_s *oneshot,
oneshot_handler_t handler, void *arg,
const struct timespec *ts)
{
uint64_t usec = 0;
uint64_t compare = 0;
irqstate_t flags;
tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
handler, arg, (unsigned long)ts->tv_sec,
(unsigned long)ts->tv_nsec);
DEBUGASSERT(oneshot && handler && ts);
DEBUGASSERT(oneshot->tch);
/* Was the oneshot already running? */
flags = spin_lock_irqsave(&g_oneshot_spin);
if (oneshot->running)
{
/* Yes.. then cancel it */
tmrinfo("Already running... cancelling\n");
intel64_oneshot_cancel(oneshot, NULL);
}
/* Save the new handler and its argument */
oneshot->handler = handler;
oneshot->arg = arg;
/* Express the delay in microseconds */
usec = (uint64_t)ts->tv_sec * USEC_PER_SEC +
(uint64_t)(ts->tv_nsec / NSEC_PER_USEC);
/* HPET use free runnin up-counter and a comparators which generate events
* only on a equal event. This can results in event miss if we set too
* small delay. In that case we just set a minimum value for delay that
* seem to work.
*/
if (usec < CONFIG_INTEL64_HPET_MIN_DELAY)
{
usec = CONFIG_INTEL64_HPET_MIN_DELAY;
}
/* Get the timer counter frequency and determine the number of counts need
* to achieve the requested delay.
*
* frequency = ticks / second
* ticks = seconds * frequency
* = (usecs * frequency) / USEC_PER_SEC;
*/
compare = (usec * (uint64_t)oneshot->frequency) / USEC_PER_SEC;
/* Set up to receive the callback when the interrupt occurs */
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, intel64_oneshot_handler,
oneshot, false);
/* Set comparator ahed of the current counter */
compare += INTEL64_TIM_GETCOUNTER(oneshot->tch);
INTEL64_TIM_SETCOMPARE(oneshot->tch, oneshot->chan, compare);
/* Enable interrupts. We should get the callback when the interrupt
* occurs.
*/
INTEL64_TIM_ENABLEINT(oneshot->tch, oneshot->chan);
oneshot->running = true;
spin_unlock_irqrestore(&g_oneshot_spin, flags);
return OK;
}
/****************************************************************************
* Name: intel64_oneshot_cancel
*
* Description:
* Cancel the oneshot timer and return the time remaining on the timer.
*
* NOTE: This function may execute at a high rate with no timer running (as
* when pre-emption is enabled and disabled).
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure. This
* structure must have been previously initialized via a call to
* intel64_oneshot_initialize();
* ts The location in which to return the time remaining on the
* oneshot timer. A time of zero is returned if the timer is
* not running.
*
* Returned Value:
* Zero (OK) is returned on success. A call to up_timer_cancel() when
* the timer is not active should also return success; a negated errno
* value is returned on any failure.
*
****************************************************************************/
int intel64_oneshot_cancel(struct intel64_oneshot_s *oneshot,
struct timespec *ts)
{
irqstate_t flags;
uint64_t usec;
uint64_t sec;
uint64_t nsec;
uint64_t counter;
uint64_t compare;
/* Was the timer running? */
flags = spin_lock_irqsave(&g_oneshot_spin);
if (!oneshot->running)
{
/* No.. Just return zero timer remaining and successful cancellation.
* This function may execute at a high rate with no timer running
* (as when pre-emption is enabled and disabled).
*/
ts->tv_sec = 0;
ts->tv_nsec = 0;
spin_unlock_irqrestore(&g_oneshot_spin, flags);
return OK;
}
/* Yes.. Get the timer counter and compare registers and stop the
* counter.
*/
tmrinfo("Cancelling...\n");
counter = INTEL64_TIM_GETCOUNTER(oneshot->tch);
compare = INTEL64_TIM_GETCOMPARE(oneshot->tch, oneshot->chan);
/* Now we can disable the interrupt and stop the timer. */
INTEL64_TIM_DISABLEINT(oneshot->tch, oneshot->chan);
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, NULL, NULL, false);
oneshot->running = false;
oneshot->handler = NULL;
oneshot->arg = NULL;
spin_unlock_irqrestore(&g_oneshot_spin, flags);
/* Did the caller provide us with a location to return the time
* remaining?
*/
if (ts)
{
/* Yes.. then calculate and return the time remaining on the
* oneshot timer.
*/
/* The total time remaining is the difference. Convert that
* to units of microseconds.
*
* frequency = ticks / second
* seconds = ticks * frequency
* usecs = (ticks * USEC_PER_SEC) / frequency;
*/
usec = ((compare - counter) * USEC_PER_SEC) /
oneshot->frequency;
/* Return the time remaining in the correct form */
sec = usec / USEC_PER_SEC;
nsec = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
ts->tv_sec = (time_t)sec;
ts->tv_nsec = (unsigned long)nsec;
tmrinfo("remaining (%lu, %lu)\n",
(unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
}
return OK;
}

View File

@ -0,0 +1,177 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_oneshot.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_X86_64_SRC_INTEL64_INTEL64_ONESHOT_H
#define __ARCH_X86_64_SRC_INTEL64_INTEL64_ONESHOT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <intel64_hpet.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/* This describes the callback function that will be invoked when the oneshot
* timer expires. The oneshot fires, the client will receive:
*
* arg - The opaque argument provided when the interrupt was registered
*/
typedef void (*oneshot_handler_t)(void *arg);
/* The oneshot client must allocate an instance of this structure and called
* intel64_oneshot_initialize() before using the oneshot facilities. The
* client should not access the contents of this structure directly since
* the contents are subject to change.
*/
struct intel64_oneshot_s
{
uint8_t chan;
uint8_t cbndx;
volatile bool running;
struct intel64_tim_dev_s *tch;
volatile oneshot_handler_t handler;
volatile void *arg;
uint32_t frequency;
uint32_t period;
};
/****************************************************************************
* Inline Functions
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: intel64_oneshot_initialize
*
* Description:
* Initialize the oneshot timer wrapper
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure
* chan Timer counter channel to be used.
* resolution The required resolution of the timer in units of
* microseconds. NOTE that the range is restricted to the
* range of uint16_t (excluding zero).
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
int intel64_oneshot_initialize(struct intel64_oneshot_s *oneshot, int chan,
uint16_t resolution);
/****************************************************************************
* Name: intel64_oneshot_max_delay
*
* Description:
* Determine the maximum delay of the one-shot timer (in microseconds)
*
****************************************************************************/
int intel64_oneshot_max_delay(struct intel64_oneshot_s *oneshot,
uint64_t *usec);
/****************************************************************************
* Name: intel64_oneshot_start
*
* Description:
* Start the oneshot timer
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure. This
* structure must have been previously initialized via a call to
* intel64_oneshot_initialize();
* handler The function to call when when the oneshot timer expires.
* arg An opaque argument that will accompany the callback.
* ts Provides the duration of the one shot timer.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
int intel64_oneshot_start(struct intel64_oneshot_s *oneshot,
oneshot_handler_t handler, void *arg,
const struct timespec *ts);
/****************************************************************************
* Name: intel64_oneshot_cancel
*
* Description:
* Cancel the oneshot timer and return the time remaining on the timer.
*
* NOTE: This function may execute at a high rate with no timer running (as
* when pre-emption is enabled and disabled).
*
* Input Parameters:
* oneshot Caller allocated instance of the oneshot state structure. This
* structure must have been previously initialized via a call to
* intel64_oneshot_initialize();
* ts The location in which to return the time remaining on the
* oneshot timer. A time of zero is returned if the timer is
* not running.
*
* Returned Value:
* Zero (OK) is returned on success. A call to up_timer_cancel() when
* the timer is not active should also return success; a negated errno
* value is returned on any failure.
*
****************************************************************************/
int intel64_oneshot_cancel(struct intel64_oneshot_s *oneshot,
struct timespec *ts);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_X86_64_SRC_INTEL64_INTEL64_ONESHOT_H */

View File

@ -0,0 +1,324 @@
/****************************************************************************
* arch/x86_64/src/intel64/intel64_oneshot_lower.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <time.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spinlock.h>
#include <nuttx/timers/oneshot.h>
#include "intel64_oneshot.h"
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes the state of the oneshot timer lower-half driver
*/
struct intel64_oneshot_lowerhalf_s
{
struct oneshot_lowerhalf_s lh;
struct intel64_oneshot_s oneshot;
oneshot_callback_t callback;
void *arg;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void intel64_oneshot_handler(void *arg);
static int intel64_max_delay(struct oneshot_lowerhalf_s *lower,
struct timespec *ts);
static int intel64_start(struct oneshot_lowerhalf_s *lower,
oneshot_callback_t callback, void *arg,
const struct timespec *ts);
static int intel64_cancel(struct oneshot_lowerhalf_s *lower,
struct timespec *ts);
/****************************************************************************
* Private Data
****************************************************************************/
/* Lower half operations */
static const struct oneshot_operations_s g_oneshot_ops =
{
.max_delay = intel64_max_delay,
.start = intel64_start,
.cancel = intel64_cancel,
};
static spinlock_t g_oneshotlow_spin;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: intel64_oneshot_handler
*
* Description:
* Timer expiration handler
*
* Input Parameters:
* arg - Should be the same argument provided when intel64_oneshot_start()
* was called.
*
* Returned Value:
* None
*
****************************************************************************/
static void intel64_oneshot_handler(void *arg)
{
struct intel64_oneshot_lowerhalf_s *priv = arg;
oneshot_callback_t callback;
void *cbarg;
DEBUGASSERT(priv != NULL);
/* Perhaps the callback was nullified in a race condition with
* intel64_cancel?
*/
if (priv->callback)
{
/* Sample and nullify BEFORE executing callback (in case the callback
* restarts the oneshot).
*/
callback = priv->callback;
cbarg = priv->arg;
priv->callback = NULL;
priv->arg = NULL;
/* Then perform the callback */
callback(&priv->lh, cbarg);
}
}
/****************************************************************************
* Name: intel64_max_delay
*
* Description:
* Determine the maximum delay of the one-shot timer (in microseconds)
*
* Input Parameters:
* lower An instance of the lower-half oneshot state structure. This
* structure must have been previously initialized via a call to
* oneshot_initialize();
* ts The location in which to return the maximum delay.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
static int intel64_max_delay(struct oneshot_lowerhalf_s *lower,
struct timespec *ts)
{
struct intel64_oneshot_lowerhalf_s *priv =
(struct intel64_oneshot_lowerhalf_s *)lower;
uint64_t usecs;
uint64_t sec;
int ret;
DEBUGASSERT(priv != NULL && ts != NULL);
ret = intel64_oneshot_max_delay(&priv->oneshot, &usecs);
if (ret >= 0)
{
sec = usecs / 1000000;
usecs -= 1000000 * sec;
ts->tv_sec = (time_t)sec;
ts->tv_nsec = (long)(usecs * 1000);
}
return ret;
}
/****************************************************************************
* Name: intel64_start
*
* Description:
* Start the oneshot timer
*
* Input Parameters:
* lower An instance of the lower-half oneshot state structure. This
* structure must have been previously initialized via a call to
* oneshot_initialize();
* handler The function to call when when the oneshot timer expires.
* arg An opaque argument that will accompany the callback.
* ts Provides the duration of the one shot timer.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on failure.
*
****************************************************************************/
static int intel64_start(struct oneshot_lowerhalf_s *lower,
oneshot_callback_t callback, void *arg,
const struct timespec *ts)
{
struct intel64_oneshot_lowerhalf_s *priv =
(struct intel64_oneshot_lowerhalf_s *)lower;
irqstate_t flags;
int ret;
DEBUGASSERT(priv != NULL && callback != NULL && ts != NULL);
/* Save the callback information and start the timer */
flags = spin_lock_irqsave(&g_oneshotlow_spin);
priv->callback = callback;
priv->arg = arg;
ret = intel64_oneshot_start(&priv->oneshot,
intel64_oneshot_handler,
priv, ts);
spin_unlock_irqrestore(&g_oneshotlow_spin, flags);
if (ret < 0)
{
tmrerr("ERROR: intel64_oneshot_start failed\n");
}
return ret;
}
/****************************************************************************
* Name: intel64_cancel
*
* Description:
* Cancel the oneshot timer and return the time remaining on the timer.
*
* NOTE: This function may execute at a high rate with no timer running (as
* when pre-emption is enabled and disabled).
*
* Input Parameters:
* lower Caller allocated instance of the oneshot state structure. This
* structure must have been previously initialized via a call to
* oneshot_initialize();
* ts The location in which to return the time remaining on the
* oneshot timer. A time of zero is returned if the timer is
* not running.
*
* Returned Value:
* Zero (OK) is returned on success. A call to up_timer_cancel() when
* the timer is not active should also return success; a negated errno
* value is returned on any failure.
*
****************************************************************************/
static int intel64_cancel(struct oneshot_lowerhalf_s *lower,
struct timespec *ts)
{
struct intel64_oneshot_lowerhalf_s *priv =
(struct intel64_oneshot_lowerhalf_s *)lower;
irqstate_t flags;
int ret;
DEBUGASSERT(priv != NULL);
/* Cancel the timer */
flags = spin_lock_irqsave(&g_oneshotlow_spin);
ret = intel64_oneshot_cancel(&priv->oneshot, ts);
priv->callback = NULL;
priv->arg = NULL;
spin_unlock_irqrestore(&g_oneshotlow_spin, flags);
if (ret < 0)
{
tmrerr("ERROR: intel64_oneshot_cancel failed\n");
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: oneshot_initialize
*
* Description:
* Initialize the oneshot timer and return a oneshot lower half driver
* instance.
*
* Input Parameters:
* chan Timer counter channel to be used.
* resolution The required resolution of the timer in units of
* microseconds. NOTE that the range is restricted to the
* range of uint16_t (excluding zero).
*
* Returned Value:
* On success, a non-NULL instance of the oneshot lower-half driver is
* returned. NULL is return on any failure.
*
****************************************************************************/
struct oneshot_lowerhalf_s *oneshot_initialize(int chan, uint16_t resolution)
{
struct intel64_oneshot_lowerhalf_s *priv;
int ret;
/* Allocate an instance of the lower half driver */
priv = (struct intel64_oneshot_lowerhalf_s *)
kmm_zalloc(sizeof(struct intel64_oneshot_lowerhalf_s));
if (priv == NULL)
{
tmrerr("ERROR: Failed to initialized state structure\n");
return NULL;
}
/* Initialize the lower-half driver structure */
priv->lh.ops = &g_oneshot_ops;
/* Initialize the contained INTEL64 oneshot timer */
ret = intel64_oneshot_initialize(&priv->oneshot, chan, resolution);
if (ret < 0)
{
tmrerr("ERROR: intel64_oneshot_initialize failed: %d\n", ret);
kmm_free(priv);
return NULL;
}
return &priv->lh;
}

View File

@ -31,7 +31,10 @@
#include <nuttx/board.h>
#include <nuttx/fs/fs.h>
#include <nuttx/input/buttons.h>
#ifdef CONFIG_ONESHOT
# include <nuttx/timers/oneshot.h>
#endif
#include "qemu_intel64.h"
@ -45,6 +48,10 @@
int qemu_bringup(void)
{
#ifdef CONFIG_ONESHOT
struct oneshot_lowerhalf_s *os = NULL;
#endif
int ret = OK;
#ifdef CONFIG_FS_PROCFS
@ -57,5 +64,13 @@ int qemu_bringup(void)
}
#endif
#ifdef CONFIG_ONESHOT
os = oneshot_initialize(0, 10);
if (os)
{
oneshot_register("/dev/oneshot", os);
}
#endif
return ret;
}