arch/intel64: add HPET timer support as oneshot timer
Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
parent
51d8bbfbd9
commit
d4b17f963d
96
arch/x86_64/include/hpet.h
Normal file
96
arch/x86_64/include/hpet.h
Normal 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 */
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
496
arch/x86_64/src/intel64/intel64_hpet.c
Normal file
496
arch/x86_64/src/intel64/intel64_hpet.c
Normal 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;
|
||||
}
|
118
arch/x86_64/src/intel64/intel64_hpet.h
Normal file
118
arch/x86_64/src/intel64/intel64_hpet.h
Normal 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 */
|
425
arch/x86_64/src/intel64/intel64_oneshot.c
Normal file
425
arch/x86_64/src/intel64/intel64_oneshot.c
Normal 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;
|
||||
}
|
177
arch/x86_64/src/intel64/intel64_oneshot.h
Normal file
177
arch/x86_64/src/intel64/intel64_oneshot.h
Normal 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 */
|
324
arch/x86_64/src/intel64/intel64_oneshot_lower.c
Normal file
324
arch/x86_64/src/intel64/intel64_oneshot_lower.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user